Compare commits
367 commits
v1,0
...
v6.6-order
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c3f0119ae9 | ||
![]() |
c693d203d9 | ||
![]() |
005fc23648 | ||
![]() |
58082f3fe8 | ||
![]() |
cc37c8fb52 | ||
![]() |
c3a2d96ba2 | ||
![]() |
7aef82f3be | ||
![]() |
4ab8158c18 | ||
![]() |
8f377d1eaa | ||
![]() |
aaa2090dbf | ||
![]() |
f25e76508f | ||
![]() |
a46c3f6324 | ||
![]() |
2a40c7dbff | ||
![]() |
f69370b841 | ||
![]() |
a03624a0ce | ||
![]() |
0bb3ca6c98 | ||
![]() |
18e297d2d8 | ||
![]() |
280bb390a2 | ||
![]() |
19ca5aeb50 | ||
![]() |
ebd1fa605c | ||
![]() |
a57389693c | ||
![]() |
977a7ff321 | ||
![]() |
4d0e36d426 | ||
![]() |
99bbf880e9 | ||
![]() |
8dbe3726b7 | ||
![]() |
e452172d8c | ||
![]() |
a8ee041f21 | ||
![]() |
6bf1dbd04e | ||
![]() |
b093f59250 | ||
![]() |
8fa56e18bb | ||
![]() |
dd9391fb78 | ||
![]() |
d840f77541 | ||
![]() |
bd7623e9fb | ||
![]() |
17e2875d4d | ||
![]() |
b595b95b21 | ||
![]() |
48dbb3f815 | ||
![]() |
41a09a3b67 | ||
![]() |
81e0f0879d | ||
![]() |
d841b2a0fb | ||
![]() |
f9427ea449 | ||
![]() |
efa999f0f3 | ||
![]() |
d688a02f14 | ||
![]() |
a1a51f8aab | ||
![]() |
31d750c981 | ||
![]() |
c8d97904ce | ||
![]() |
c5f3836dd8 | ||
![]() |
19067f3333 | ||
![]() |
5793cf6bf0 | ||
![]() |
ffcdafb798 | ||
![]() |
e553d4f851 | ||
![]() |
de70691526 | ||
![]() |
1774a54301 | ||
![]() |
af484de3af | ||
![]() |
9796ad49ff | ||
![]() |
43b6034266 | ||
![]() |
eab694c170 | ||
![]() |
fdd67ea2c4 | ||
![]() |
f8d47b5c64 | ||
![]() |
47d09dba0e | ||
![]() |
d692927067 | ||
![]() |
14317817f8 | ||
![]() |
3ba6aec5bb | ||
![]() |
8b2094fc23 | ||
![]() |
c84b644247 | ||
![]() |
8e1c59be7e | ||
![]() |
f289f5586e | ||
![]() |
3ad10c131c | ||
![]() |
cbb5e082f2 | ||
![]() |
43532cfada | ||
![]() |
eea6066d70 | ||
![]() |
44d47226dc | ||
![]() |
50dbe24b78 | ||
![]() |
ebcf755c1a | ||
![]() |
484c03d4c8 | ||
![]() |
a79b7d94a5 | ||
![]() |
87f42ed64d | ||
![]() |
379f791b3c | ||
![]() |
8cce4e8ffa | ||
![]() |
ac2bf5f638 | ||
![]() |
4b7559b320 | ||
![]() |
526d0ddef9 | ||
![]() |
6fb0c63581 | ||
![]() |
06e054aa06 | ||
![]() |
1a7fbee50e | ||
![]() |
7e635f5d57 | ||
![]() |
7461921407 | ||
![]() |
794d7a3527 | ||
![]() |
c206a43374 | ||
![]() |
e0f9a554fc | ||
![]() |
e85006b775 | ||
![]() |
921ac8fba5 | ||
![]() |
30ceb546fa | ||
![]() |
e1110617b2 | ||
![]() |
a891e0260e | ||
![]() |
c1c2e5ca56 | ||
![]() |
f1a46d63cc | ||
![]() |
2e8586d547 | ||
![]() |
ac1dddeaed | ||
![]() |
6a30a3efc6 | ||
![]() |
84247b0037 | ||
![]() |
9bb3afb358 | ||
![]() |
2baddde5ba | ||
![]() |
b5def1af8e | ||
![]() |
0abc6ed072 | ||
![]() |
30216a9c7c | ||
![]() |
6af23967a5 | ||
![]() |
74620fbdbf | ||
![]() |
4cec9e73df | ||
![]() |
957b1298d5 | ||
![]() |
901b451bd5 | ||
![]() |
b83519eb82 | ||
![]() |
1372794704 | ||
![]() |
19cfed5bd7 | ||
![]() |
6875869cb2 | ||
![]() |
9285159a7d | ||
![]() |
90144a2f2e | ||
![]() |
cbd6da78fc | ||
![]() |
cf98b67079 | ||
![]() |
c4c112dcaf | ||
![]() |
9722cb01e4 | ||
![]() |
f4f303f9bd | ||
![]() |
de23c61210 | ||
![]() |
cca7bbfe2a | ||
![]() |
5ca9ab45df | ||
![]() |
8c25d81890 | ||
![]() |
f47375e54d | ||
![]() |
1f7323417b | ||
![]() |
e82e6fde67 | ||
![]() |
cd899a83d5 | ||
![]() |
e750de0ecc | ||
![]() |
efaa210d79 | ||
![]() |
e6e5240922 | ||
![]() |
8ea751c4e9 | ||
![]() |
e2529f9eee | ||
![]() |
6aff6e0b33 | ||
![]() |
bb09e9d24b | ||
![]() |
edddb2fbe4 | ||
![]() |
655d7fe57b | ||
![]() |
d64e994982 | ||
![]() |
673305fc4e | ||
![]() |
47d97e7bd5 | ||
![]() |
955707d944 | ||
![]() |
cf2a5fe807 | ||
![]() |
471f88b337 | ||
![]() |
d5b71a009d | ||
![]() |
bccf557d62 | ||
![]() |
a5095cd7b2 | ||
![]() |
bcdc10e193 | ||
![]() |
ebb9a9d82a | ||
![]() |
783eff8779 | ||
![]() |
ec5fc9d9b8 | ||
![]() |
bb1422182b | ||
![]() |
f2b2516426 | ||
![]() |
e26006d40c | ||
![]() |
138d22226e | ||
![]() |
a24da444df | ||
![]() |
c3adcde556 | ||
![]() |
1452d85e0f | ||
![]() |
329c8090ea | ||
![]() |
53c0db449b | ||
![]() |
89f8a76646 | ||
![]() |
39c134f430 | ||
![]() |
17944791bb | ||
![]() |
df68ab22d6 | ||
![]() |
88aae48c41 | ||
![]() |
6bcd4cad2f | ||
![]() |
7f88e11fd0 | ||
![]() |
60e90d6fae | ||
![]() |
5cefec4cca | ||
![]() |
1f9c1464ab | ||
![]() |
71f01070d8 | ||
![]() |
19d1e6eb88 | ||
![]() |
07dc49259a | ||
![]() |
d8775ccb93 | ||
![]() |
c3ddbb521d | ||
![]() |
1456785779 | ||
![]() |
02eccbcd55 | ||
![]() |
131ee8187d | ||
![]() |
ed615d2318 | ||
![]() |
2cc009619e | ||
![]() |
aaf0cc2c61 | ||
![]() |
a6db04e724 | ||
![]() |
0be1de9750 | ||
![]() |
fcbc3b6d6b | ||
![]() |
c2b419c286 | ||
![]() |
ed094dece5 | ||
![]() |
51966603da | ||
![]() |
6afe18224a | ||
![]() |
953fa50f4f | ||
![]() |
4396e4f834 | ||
![]() |
26754b0821 | ||
![]() |
af8668ff97 | ||
![]() |
2d08bb0b35 | ||
![]() |
c2f81c1f23 | ||
![]() |
63fa92db39 | ||
![]() |
d2c0f1b5c9 | ||
![]() |
775005d865 | ||
![]() |
8c80018c3e | ||
![]() |
076d12f7fb | ||
![]() |
c0f1dfa8bb | ||
![]() |
67f7942cfd | ||
![]() |
86c198d7dc | ||
![]() |
1d4abfa41d | ||
![]() |
f52ed1b363 | ||
![]() |
97146337cb | ||
![]() |
1046e30108 | ||
![]() |
97fd3f2eab | ||
![]() |
60d2a5129d | ||
![]() |
6b4133b5f0 | ||
![]() |
0ed11aa9a4 | ||
![]() |
2e1940bb0f | ||
![]() |
6c6dfaa7d3 | ||
![]() |
468b40eee5 | ||
![]() |
07a6c4659e | ||
![]() |
ad4d66d3f7 | ||
![]() |
add12477e9 | ||
![]() |
74d65bfcbd | ||
![]() |
deed034f31 | ||
![]() |
2563020e29 | ||
![]() |
30276c80bc | ||
![]() |
82c8d1024a | ||
![]() |
476378c156 | ||
![]() |
4c15036368 | ||
![]() |
cb9bf1c913 | ||
![]() |
37a37a6d16 | ||
![]() |
de22f92298 | ||
![]() |
72d3c9e2f6 | ||
![]() |
b9272dcee8 | ||
![]() |
61022875b3 | ||
![]() |
41c71f1b45 | ||
![]() |
8c5ffaeed3 | ||
![]() |
920ef83b63 | ||
![]() |
48463b9a50 | ||
![]() |
2da704e872 | ||
![]() |
d6f808b278 | ||
![]() |
873580cfd5 | ||
![]() |
ae32476755 | ||
![]() |
277aeacb81 | ||
![]() |
08f0d96d68 | ||
![]() |
da5f90473b | ||
![]() |
0ea5d2bd98 | ||
![]() |
c7026a4048 | ||
![]() |
11e9db79b5 | ||
![]() |
90d2673610 | ||
![]() |
09728d1c82 | ||
![]() |
b98fce84e0 | ||
![]() |
6c6b9ab7de | ||
![]() |
27b6cdf252 | ||
![]() |
f5b82b6b7d | ||
![]() |
5744fd1bbb | ||
![]() |
95f4fe0688 | ||
![]() |
3392bf394b | ||
![]() |
0965139ead | ||
![]() |
be0812c70b | ||
![]() |
dfc7b404a5 | ||
![]() |
deeddaabb4 | ||
![]() |
bfe6978ef4 | ||
![]() |
67b4504964 | ||
![]() |
bca16c68c4 | ||
![]() |
ab0b28d08f | ||
![]() |
a73335b8d0 | ||
![]() |
58c6233325 | ||
![]() |
f85c98c4e0 | ||
![]() |
7009515ec9 | ||
![]() |
8c499c2268 | ||
![]() |
9a9f4368b4 | ||
![]() |
3d56af9d3c | ||
![]() |
3074de1f86 | ||
![]() |
33ddbd39d3 | ||
![]() |
983d4834bb | ||
![]() |
a8d0a23583 | ||
![]() |
ccac09b842 | ||
![]() |
0548a6d0a3 | ||
![]() |
d0d9107c91 | ||
![]() |
d660a92d73 | ||
![]() |
8211f4c000 | ||
![]() |
86329f0719 | ||
![]() |
031bbb3a1a | ||
![]() |
80e0478c91 | ||
![]() |
860d38fc47 | ||
![]() |
1901914b56 | ||
![]() |
7e1f29af35 | ||
![]() |
d3d95d0296 | ||
![]() |
22f495491a | ||
![]() |
235485652b | ||
![]() |
9dce807fb7 | ||
![]() |
d6744a76d2 | ||
![]() |
829ae64abe | ||
![]() |
a98c728f33 | ||
![]() |
6b6552bf9c | ||
![]() |
cff392127f | ||
![]() |
0d30a1599d | ||
![]() |
0f5ff56d1e | ||
![]() |
b8f9bb38fd | ||
![]() |
2f31ac4ea4 | ||
![]() |
00d123836f | ||
![]() |
d225c664d7 | ||
![]() |
b462e8a724 | ||
![]() |
e2266a2791 | ||
![]() |
12d155f6ea | ||
![]() |
1c1643003f | ||
![]() |
18eec1abfa | ||
![]() |
fa4b566d9a | ||
![]() |
560008e8fd | ||
![]() |
cf52966d00 | ||
![]() |
edb5a1da65 | ||
![]() |
3fdc0c4345 | ||
![]() |
3a0a0e8b57 | ||
![]() |
f49d896613 | ||
![]() |
73ff8fe114 | ||
![]() |
8b84b891cd | ||
![]() |
7170b7fcb2 | ||
![]() |
add8afa699 | ||
![]() |
995c17c160 | ||
![]() |
10e0f12b16 | ||
![]() |
d8b60f1116 | ||
![]() |
780db6f6ab | ||
![]() |
b032c0664d | ||
![]() |
56da9a526c | ||
![]() |
c3367740d5 | ||
![]() |
156697545a | ||
![]() |
aec1941ae1 | ||
![]() |
7aae0e3353 | ||
![]() |
188be2636f | ||
![]() |
a62c615114 | ||
![]() |
0cb24e58d2 | ||
![]() |
07b67878dc | ||
![]() |
5607fed986 | ||
![]() |
878027066d | ||
![]() |
5028a91201 | ||
![]() |
7f4b5849a7 | ||
![]() |
3fd4021f45 | ||
![]() |
b9d9cde471 | ||
![]() |
8094f7c3ab | ||
![]() |
3fed3fdc8a | ||
![]() |
9e6b2472e3 | ||
![]() |
76a0140513 | ||
![]() |
12bac6756a | ||
![]() |
b28887adab | ||
![]() |
125e5188e5 | ||
![]() |
3c4fc91f89 | ||
![]() |
932d2ab1c5 | ||
![]() |
f362cdd383 | ||
![]() |
6a0b216dbf | ||
![]() |
b142dc56fc | ||
![]() |
cde3b55c1f | ||
![]() |
9884e01dfd | ||
![]() |
5863e7d3ac | ||
![]() |
0aae7a6ea6 | ||
![]() |
51fbe557f3 | ||
![]() |
41fbb892b9 | ||
![]() |
7fdad37206 | ||
![]() |
5baa9289cf | ||
![]() |
45932231a7 | ||
![]() |
cc6185e587 | ||
![]() |
d454f0df21 | ||
![]() |
af15d8c5a0 | ||
![]() |
eee3db3733 | ||
![]() |
baaecb8b7d | ||
![]() |
9a97f5033f | ||
![]() |
b4c2dba036 | ||
![]() |
1d7ef19938 | ||
![]() |
32d80ed5a4 | ||
![]() |
448f135c53 | ||
![]() |
c6d4885aeb | ||
![]() |
d764c26a2d | ||
![]() |
5b49bfb4ec |
53 changed files with 10101 additions and 136 deletions
674
LICENSE
Normal file
674
LICENSE
Normal file
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
49
Makefile
49
Makefile
|
@ -1,11 +1,52 @@
|
|||
obj-m := wm8960.o
|
||||
#
|
||||
# Peter Yang <turmary@126.com>
|
||||
# Copyright (c) 2019 Seeed Studio
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
|
||||
uname_r=$(shell uname -r)
|
||||
|
||||
# If KERNELRELEASE is defined, we've been invoked from the
|
||||
# kernel build system and can use its language
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
# $(warning KERNELVERSION=$(KERNELVERSION))
|
||||
|
||||
snd-soc-wm8960-objs := wm8960.o
|
||||
snd-soc-ac108-objs := ac108.o ac101.o
|
||||
snd-soc-seeed-voicecard-objs := seeed-voicecard.o
|
||||
|
||||
|
||||
obj-m += snd-soc-wm8960.o
|
||||
obj-m += snd-soc-ac108.o
|
||||
obj-m += snd-soc-seeed-voicecard.o
|
||||
|
||||
ifdef DEBUG
|
||||
ifneq ($(DEBUG),0)
|
||||
ccflags-y += -DDEBUG -DAC101_DEBG
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
|
||||
else
|
||||
|
||||
DEST := /lib/modules/$(uname_r)/kernel
|
||||
|
||||
all:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
|
||||
make -C /lib/modules/$(uname_r)/build M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
|
||||
make -C /lib/modules/$(uname_r)/build M=$(PWD) clean
|
||||
|
||||
install:
|
||||
sudo cp wm8960.ko /lib/modules/$(shell uname -r)
|
||||
sudo cp snd-soc-ac108.ko ${DEST}/sound/soc/codecs/
|
||||
sudo cp snd-soc-wm8960.ko ${DEST}/sound/soc/codecs/
|
||||
sudo cp snd-soc-seeed-voicecard.ko ${DEST}/sound/soc/bcm/
|
||||
sudo depmod -a
|
||||
|
||||
|
||||
.PHONY: all clean install
|
||||
|
||||
endif
|
||||
|
||||
|
|
99
README.md
99
README.md
|
@ -1,59 +1,64 @@
|
|||
# seeed-voicecard
|
||||
|
||||
[](https://gitter.im/seeed-voicecard/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
The drivers for [ReSpeaker Mic Hat](https://www.seeedstudio.com/ReSpeaker-2-Mics-Pi-HAT-p-2874.html), [ReSpeaker 4 Mic Array](https://www.seeedstudio.com/ReSpeaker-4-Mic-Array-for-Raspberry-Pi-p-2941.html), [6-Mics Circular Array Kit](), and [4-Mics Linear Array Kit]() for Raspberry Pi.
|
||||
|
||||
While the upstream wm8960 codec is not currently supported by current Pi kernel builds, upstream wm8960 has some bugs, we had fixed it. we must it build manually.
|
||||
|
||||
Get the seeed voice card source code.
|
||||
```
|
||||
git clone https://github.com/respeaker/seeed-voicecard
|
||||
### Install seeed-voicecard
|
||||
Get the seeed voice card source code and install all linux kernel drivers
|
||||
```bash
|
||||
git clone https://github.com/HinTak/seeed-voicecard
|
||||
cd seeed-voicecard
|
||||
sudo ./install.sh
|
||||
reboot
|
||||
sudo reboot
|
||||
```
|
||||
## ReSpeaker Documentation
|
||||
|
||||
Up to date documentation for reSpeaker products can be found in [Seeed Studio Wiki](https://wiki.seeedstudio.com/ReSpeaker/)!
|
||||

|
||||
|
||||
|
||||
### Coherence
|
||||
|
||||
Estimate the magnitude squared coherence using Welch’s method.
|
||||

|
||||
Note: 'CO 1-2' means the coherence between channel 1 and channel 2.
|
||||
|
||||
```bash
|
||||
# How to get the coherence of the captured audio(a.wav for example).
|
||||
sudo apt install python-numpy python-scipy python-matplotlib
|
||||
python tools/coherence.py a.wav
|
||||
|
||||
# Requirement of the input audio file:
|
||||
- format: WAV(Microsoft) signed 16-bit PCM
|
||||
- channels: >=2
|
||||
```
|
||||
|
||||
Check that the sound card name matches the source code seeed-voicecard.
|
||||
### uninstall seeed-voicecard
|
||||
If you want to upgrade the driver , you need uninstall the driver first.
|
||||
|
||||
```
|
||||
pi@raspberrypi:~/seeed-voicecard$ aplay -l
|
||||
**** List of PLAYBACK Hardware Devices ****
|
||||
card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
|
||||
Subdevices: 8/8
|
||||
Subdevice #0: subdevice #0
|
||||
Subdevice #1: subdevice #1
|
||||
Subdevice #2: subdevice #2
|
||||
Subdevice #3: subdevice #3
|
||||
Subdevice #4: subdevice #4
|
||||
Subdevice #5: subdevice #5
|
||||
Subdevice #6: subdevice #6
|
||||
Subdevice #7: subdevice #7
|
||||
card 0: ALSA [bcm2835 ALSA], device 1: bcm2835 ALSA [bcm2835 IEC958/HDMI]
|
||||
Subdevices: 1/1
|
||||
Subdevice #0: subdevice #0
|
||||
card 1: seeedvoicecard [seeed-voicecard], device 0: bcm2835-i2s-wm8960-hifi wm8960-hifi-0 []
|
||||
Subdevices: 1/1
|
||||
Subdevice #0: subdevice #0
|
||||
pi@raspberrypi:~/seeed-voicecard$
|
||||
pi@raspberrypi:~/seeed-voicecard $ sudo ./uninstall.sh
|
||||
...
|
||||
------------------------------------------------------
|
||||
Please reboot your raspberry pi to apply all settings
|
||||
Thank you!
|
||||
------------------------------------------------------
|
||||
```
|
||||
Next apply the alsa controls setting
|
||||
```
|
||||
sudo alsactl --file=asound.state restore
|
||||
```
|
||||
If you want to change the alsa settings, You can use `sudo alsactl --file=asound.state store` to save it.
|
||||
|
||||
Test:
|
||||
```
|
||||
arecord -f cd -Dhw:1 | aplay -Dhw:1
|
||||
```
|
||||
|
||||
### with Google Assistant
|
||||
if you run the assistant but the playback is speed up considerably, try to configure alsa:
|
||||
|
||||
```
|
||||
sudo cp asound.conf /etc/asound.conf
|
||||
```
|
||||
|
||||
If the alsa configuration doesn't solve the issue, try to use pulseaudio. See [#4](https://github.com/respeaker/seeed-voicecard/issues/4)
|
||||
|
||||
|
||||
Enjoy !
|
||||
|
||||
### Technical support
|
||||
|
||||
For hardware testing purposes we made a Rasperry Pi OS 5.10.17-v7l+ 32-bit image with reSpeaker drivers pre-installed, which you can download by clicking on [this link](https://files.seeedstudio.com/linux/Raspberry%20Pi%204%20reSpeaker/2021-05-07-raspios-buster-armhf-lite-respeaker.img.xz).
|
||||
|
||||
We provide official support for using reSpeaker with the following OS:
|
||||
- 32-bit Raspberry Pi OS
|
||||
- 64-bit Raspberry Pi OS
|
||||
|
||||
And following hardware platforms:
|
||||
- Raspberry Pi 3 (all models), Raspberry Pi 4 (all models)
|
||||
|
||||
Anything beyond the scope of official support is considered to be community supported. Support for other OS/hardware platforms can be added, provided MOQ requirements can be met.
|
||||
|
||||
If you have a technical problem when using reSpeaker with one of the officially supported platforms/OS, feel free to create an issue on Github. For general questions or suggestions, please use [Seeed forum](https://forum.seeedstudio.com/c/products/respeaker/15).
|
||||
|
||||
|
||||
|
|
432
ac101_regs.h
Normal file
432
ac101_regs.h
Normal file
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
* ac101_regs.h
|
||||
*
|
||||
* (C) Copyright 2017-2018
|
||||
* Seeed Technology Co., Ltd. <www.seeedstudio.com>
|
||||
*
|
||||
* PeterYang <linsheng.yang@seeed.cc>
|
||||
*
|
||||
* (C) Copyright 2010-2017
|
||||
* Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
|
||||
* huangxin <huangxin@reuuimllatech.com>
|
||||
*
|
||||
* some simple description for this code
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
#ifndef __AC101_REGS_H__
|
||||
#define __AC101_REGS_H__
|
||||
|
||||
/*pll source*/
|
||||
#define AC101_MCLK1 1
|
||||
#define AC101_MCLK2 2
|
||||
#define AC101_BCLK1 3
|
||||
#define AC101_BCLK2 4
|
||||
|
||||
#define AIF1_CLK 1
|
||||
#define AIF2_CLK 2
|
||||
|
||||
#define CHIP_AUDIO_RST 0x0
|
||||
#define PLL_CTRL1 0x1
|
||||
#define PLL_CTRL2 0x2
|
||||
#define SYSCLK_CTRL 0x3
|
||||
#define MOD_CLK_ENA 0x4
|
||||
#define MOD_RST_CTRL 0x5
|
||||
#define AIF_SR_CTRL 0x6
|
||||
|
||||
#define AIF1_CLK_CTRL 0x10
|
||||
#define AIF1_ADCDAT_CTRL 0x11
|
||||
#define AIF1_DACDAT_CTRL 0x12
|
||||
#define AIF1_MXR_SRC 0x13
|
||||
#define AIF1_VOL_CTRL1 0x14
|
||||
#define AIF1_VOL_CTRL2 0x15
|
||||
#define AIF1_VOL_CTRL3 0x16
|
||||
#define AIF1_VOL_CTRL4 0x17
|
||||
#define AIF1_MXR_GAIN 0x18
|
||||
#define AIF1_RXD_CTRL 0x19
|
||||
#define ADC_DIG_CTRL 0x40
|
||||
#define ADC_VOL_CTRL 0x41
|
||||
#define ADC_DBG_CTRL 0x42
|
||||
|
||||
#define HMIC_CTRL1 0x44
|
||||
#define HMIC_CTRL2 0x45
|
||||
#define HMIC_STS 0x46
|
||||
|
||||
#define DAC_DIG_CTRL 0x48
|
||||
#define DAC_VOL_CTRL 0x49
|
||||
#define DAC_DBG_CTRL 0x4a
|
||||
#define DAC_MXR_SRC 0x4c
|
||||
#define DAC_MXR_GAIN 0x4d
|
||||
|
||||
#define ADC_APC_CTRL 0x50
|
||||
#define ADC_SRC 0x51
|
||||
#define ADC_SRCBST_CTRL 0x52
|
||||
#define OMIXER_DACA_CTRL 0x53
|
||||
#define OMIXER_SR 0x54
|
||||
#define OMIXER_BST1_CTRL 0x55
|
||||
#define HPOUT_CTRL 0x56
|
||||
#define ESPKOUT_CTRL 0x57
|
||||
#define SPKOUT_CTRL 0x58
|
||||
#define LOUT_CTRL 0x59
|
||||
#define ADDA_TUNE1 0x5a
|
||||
#define ADDA_TUNE2 0x5b
|
||||
#define ADDA_TUNE3 0x5c
|
||||
#define HPOUT_STR 0x5d
|
||||
|
||||
/*CHIP_AUDIO_RST*/
|
||||
#define AC101_CHIP_ID 0x0101
|
||||
|
||||
/*PLL_CTRL1*/
|
||||
#define DPLL_DAC_BIAS 14
|
||||
#define PLL_POSTDIV_M 8
|
||||
#define CLOSE_LOOP 6
|
||||
#define INT 0
|
||||
|
||||
/*PLL_CTRL2*/
|
||||
#define PLL_EN 15
|
||||
#define PLL_LOCK_STATUS 14
|
||||
#define PLL_PREDIV_NI 4
|
||||
#define PLL_POSTDIV_NF 0
|
||||
|
||||
/*SYSCLK_CTRL*/
|
||||
#define PLLCLK_ENA 15
|
||||
#define PLLCLK_SRC 12
|
||||
#define AIF1CLK_ENA 11
|
||||
#define AIF1CLK_SRC 8
|
||||
#define AIF2CLK_ENA 7
|
||||
#define AIF2CLK_SRC 4
|
||||
#define SYSCLK_ENA 3
|
||||
#define SYSCLK_SRC 0
|
||||
|
||||
/*MOD_CLK_ENA*/
|
||||
#define MOD_CLK_AIF1 15
|
||||
#define MOD_CLK_AIF2 14
|
||||
#define MOD_CLK_AIF3 13
|
||||
#define MOD_CLK_SRC1 11
|
||||
#define MOD_CLK_SRC2 10
|
||||
#define MOD_CLK_HPF_AGC 7
|
||||
#define MOD_CLK_HPF_DRC 6
|
||||
#define MOD_CLK_ADC_DIG 3
|
||||
#define MOD_CLK_DAC_DIG 2
|
||||
|
||||
/*MOD_RST_CTRL*/
|
||||
#define MOD_RESET_CTL 0
|
||||
#define MOD_RESET_AIF1 15
|
||||
#define MOD_RESET_AIF2 14
|
||||
#define MOD_RESET_AIF3 13
|
||||
#define MOD_RESET_SRC1 11
|
||||
#define MOD_RESET_SRC2 10
|
||||
#define MOD_RESET_HPF_AGC 7
|
||||
#define MOD_RESET_HPF_DRC 6
|
||||
#define MOD_RESET_ADC_DIG 3
|
||||
#define MOD_RESET_DAC_DIG 2
|
||||
|
||||
/*AIF_SR_CTRL*/
|
||||
#define AIF1_FS 12 //AIF1 Sample Rate
|
||||
#define AIF2_FS 8 //AIF2 Sample Rate
|
||||
#define SRC1_ENA 3
|
||||
#define SRC1_SRC 2
|
||||
#define SRC2_ENA 1
|
||||
#define SRC2_SRC 0
|
||||
|
||||
/*AIF1LCK_CTRL*/
|
||||
#define AIF1_MSTR_MOD 15
|
||||
#define AIF1_BCLK_INV 14
|
||||
#define AIF1_LRCK_INV 13
|
||||
#define AIF1_BCLK_DIV 9
|
||||
#define AIF1_LRCK_DIV 6
|
||||
#define AIF1_WORK_SIZ 4
|
||||
#define AIF1_DATA_FMT 2
|
||||
#define DSP_MONO_PCM 1
|
||||
#define AIF1_TDMM_ENA 0
|
||||
|
||||
/*AIF1_ADCDAT_CTRL*/
|
||||
#define AIF1_AD0L_ENA 15
|
||||
#define AIF1_AD0R_ENA 14
|
||||
#define AIF1_AD1L_ENA 13
|
||||
#define AIF1_AD1R_ENA 12
|
||||
#define AIF1_AD0L_SRC 10
|
||||
#define AIF1_AD0R_SRC 8
|
||||
#define AIF1_AD1L_SRC 6
|
||||
#define AIF1_AD1R_SRC 4
|
||||
#define AIF1_ADCP_ENA 3
|
||||
#define AIF1_ADUL_ENA 2
|
||||
#define AIF1_SLOT_SIZ 0
|
||||
|
||||
/*AIF1_DACDAT_CTRL*/
|
||||
#define AIF1_DA0L_ENA 15
|
||||
#define AIF1_DA0R_ENA 14
|
||||
#define AIF1_DA1L_ENA 13
|
||||
#define AIF1_DA1R_ENA 12
|
||||
#define AIF1_DA0L_SRC 10
|
||||
#define AIF1_DA0R_SRC 8
|
||||
#define AIF1_DA1L_SRC 6
|
||||
#define AIF1_DA1R_SRC 4
|
||||
#define AIF1_DACP_ENA 3
|
||||
#define AIF1_DAUL_ENA 2
|
||||
#define AIF1_SLOT_SIZ 0
|
||||
|
||||
/*AIF1_MXR_SRC*/
|
||||
#define AIF1_AD0L_AIF1_DA0L_MXR 15
|
||||
#define AIF1_AD0L_AIF2_DACL_MXR 14
|
||||
#define AIF1_AD0L_ADCL_MXR 13
|
||||
#define AIF1_AD0L_AIF2_DACR_MXR 12
|
||||
#define AIF1_AD0R_AIF1_DA0R_MXR 11
|
||||
#define AIF1_AD0R_AIF2_DACR_MXR 10
|
||||
#define AIF1_AD0R_ADCR_MXR 9
|
||||
#define AIF1_AD0R_AIF2_DACL_MXR 8
|
||||
#define AIF1_AD1L_AIF2_DACL_MXR 7
|
||||
#define AIF1_AD1L_ADCL_MXR 6
|
||||
#define AIF1_AD1L_MXR_SRC 6
|
||||
#define AIF1_AD1R_AIF2_DACR_MXR 3
|
||||
#define AIF1_AD1R_ADCR_MXR 2
|
||||
#define AIF1_AD1R_MXR_SRC 2
|
||||
|
||||
/*AIF1_VOL_CTRL1*/
|
||||
#define AIF1_AD0L_VOL 8
|
||||
#define AIF1_AD0R_VOL 0
|
||||
|
||||
/*AIF1_VOL_CTRL2*/
|
||||
#define AIF1_AD1L_VOL 8
|
||||
#define AIF1_AD1R_VOL 0
|
||||
|
||||
/*AIF1_VOL_CTRL3*/
|
||||
#define AIF1_DA0L_VOL 8
|
||||
#define AIF1_DA0R_VOL 0
|
||||
|
||||
/*AIF1_VOL_CTRL4*/
|
||||
#define AIF1_DA1L_VOL 8
|
||||
#define AIF1_DA1R_VOL 0
|
||||
|
||||
/*AIF1_MXR_GAIN*/
|
||||
#define AIF1_AD0L_MXR_GAIN 12
|
||||
#define AIF1_AD0R_MXR_GAIN 8
|
||||
#define AIF1_AD1L_MXR_GAIN 6
|
||||
#define AIF1_AD1R_MXR_GAIN 2
|
||||
|
||||
/*AIF1_RXD_CTRL*/
|
||||
#define AIF1_N_DATA_DISCARD 8
|
||||
|
||||
/*ADC_DIG_CTRL*/
|
||||
#define ENAD 15
|
||||
#define ENDM 14
|
||||
#define ADFIR32 13
|
||||
#define ADOUT_DTS 2
|
||||
#define ADOUT_DLY 1
|
||||
|
||||
/*ADC_VOL_CTRL*/
|
||||
#define ADC_VOL_L 8
|
||||
#define ADC_VOL_R 0
|
||||
|
||||
/*ADC_DBG_CTRL*/
|
||||
#define ADSW 15
|
||||
#define DMIC_CLK_PIN_CTRL 12
|
||||
|
||||
/*HMIC_CTRL1*/
|
||||
#define HMIC_M 12
|
||||
#define HMIC_N 8
|
||||
#define HMIC_DATA_IRQ_MODE 7
|
||||
#define HMIC_TH1_HYSTERESIS 5
|
||||
#define HMIC_PULLOUT_IRQ 4
|
||||
#define HMIC_PLUGIN_IRQ 3
|
||||
#define HMIC_KEYUP_IRQ 2
|
||||
#define HMIC_KEYDOWN_IRQ 1
|
||||
#define HMIC_DATA_IRQ_EN 0
|
||||
|
||||
/*HMIC_CTRL2*/
|
||||
#define HMIC_SAMPLE_SELECT 14
|
||||
#define HMIC_TH2_HYSTERESIS 13
|
||||
#define HMIC_TH2 8
|
||||
#define HMIC_SF 6
|
||||
#define KEYUP_CLEAR 5
|
||||
#define HMIC_TH1 0
|
||||
|
||||
/*HMIC_STS*/
|
||||
#define HMIC_DATA 8
|
||||
#define GET_HMIC_DATA(r) (((r) >> HMIC_DATA) & 0x1F)
|
||||
#define HMIC_PULLOUT_PEND 4
|
||||
#define HMIC_PLUGIN_PEND 3
|
||||
#define HMIC_KEYUP_PEND 2
|
||||
#define HMKC_KEYDOWN_PEND 1
|
||||
#define HMIC_DATA_PEND 0
|
||||
#define HMIC_PEND_ALL (0x1F)
|
||||
|
||||
/*DAC_DIG_CTRL*/
|
||||
#define ENDA 15
|
||||
#define ENHPF 14
|
||||
#define DAFIR32 13
|
||||
#define MODQU 8
|
||||
|
||||
/*DAC_VOL_CTRL*/
|
||||
#define DAC_VOL_L 8
|
||||
#define DAC_VOL_R 0
|
||||
|
||||
/*DAC_DBG_CTRL*/
|
||||
#define DASW 15
|
||||
#define ENDWA_N 14
|
||||
#define DAC_MOD_DBG 13
|
||||
#define DAC_PTN_SEL 6
|
||||
#define DVC 0
|
||||
|
||||
/*DAC_MXR_SRC*/
|
||||
#define DACL_MXR_AIF1_DA0L 15
|
||||
#define DACL_MXR_AIF1_DA1L 14
|
||||
#define DACL_MXR_AIF2_DACL 13
|
||||
#define DACL_MXR_ADCL 12
|
||||
#define DACL_MXR_SRC 12
|
||||
#define DACR_MXR_AIF1_DA0R 11
|
||||
#define DACR_MXR_AIF1_DA1R 10
|
||||
#define DACR_MXR_AIF2_DACR 9
|
||||
#define DACR_MXR_ADCR 8
|
||||
#define DACR_MXR_SRC 8
|
||||
|
||||
/*DAC_MXR_GAIN*/
|
||||
#define DACL_MXR_GAIN 12
|
||||
#define DACR_MXR_GAIN 8
|
||||
|
||||
/*ADC_APC_CTRL*/
|
||||
#define ADCREN 15
|
||||
#define ADCRG 12
|
||||
#define ADCLEN 11
|
||||
#define ADCLG 8
|
||||
#define MBIASEN 7
|
||||
#define MMIC_BIAS_CHOP_EN 6
|
||||
#define MMIC_BIAS_CHOP_CKS 4
|
||||
#define HBIASMOD 2
|
||||
#define HBIASEN 1
|
||||
#define HBIASADCEN 0
|
||||
|
||||
/*ADC_SRC*/
|
||||
#define RADCMIXMUTEMIC1BOOST (13)
|
||||
#define RADCMIXMUTEMIC2BOOST (12)
|
||||
#define RADCMIXMUTELINEINLR (11)
|
||||
#define RADCMIXMUTELINEINR (10)
|
||||
#define RADCMIXMUTEAUXINR (9)
|
||||
#define RADCMIXMUTEROUTPUT (8)
|
||||
#define RADCMIXMUTELOUTPUT (7)
|
||||
#define LADCMIXMUTEMIC1BOOST (6)
|
||||
#define LADCMIXMUTEMIC2BOOST (5)
|
||||
#define LADCMIXMUTELINEINLR (4)
|
||||
#define LADCMIXMUTELINEINL (3)
|
||||
#define LADCMIXMUTEAUXINL (2)
|
||||
#define LADCMIXMUTELOUTPUT (1)
|
||||
#define LADCMIXMUTEROUTPUT (0)
|
||||
|
||||
|
||||
/*ADC_SRCBST_CTRL*/
|
||||
#define MIC1AMPEN 15
|
||||
#define ADC_MIC1G 12
|
||||
#define MIC2AMPEN 11
|
||||
#define ADC_MIC2G 8
|
||||
#define MIC2SLT 7
|
||||
#define LINEIN_PREG 4
|
||||
#define AUXI_PREG 0
|
||||
|
||||
/*OMIXER_DACA_CTRL*/
|
||||
#define DACAREN 15
|
||||
#define DACALEN 14
|
||||
#define RMIXEN 13
|
||||
#define LMIXEN 12
|
||||
#define HPOUTPUTENABLE 8
|
||||
|
||||
/*OMIXER_SR*/
|
||||
#define RMIXMUTEMIC1BOOST (13)
|
||||
#define RMIXMUTEMIC2BOOST (12)
|
||||
#define RMIXMUTELINEINLR (11)
|
||||
#define RMIXMUTELINEINR (10)
|
||||
#define RMIXMUTEAUXINR (9)
|
||||
#define RMIXMUTEDACR (8)
|
||||
#define RMIXMUTEDACL (7)
|
||||
#define LMIXMUTEMIC1BOOST (6)
|
||||
#define LMIXMUTEMIC2BOOST (5)
|
||||
#define LMIXMUTELINEINLR (4)
|
||||
#define LMIXMUTELINEINL (3)
|
||||
#define LMIXMUTEAUXINL (2)
|
||||
#define LMIXMUTEDACL (1)
|
||||
#define LMIXMUTEDACR (0)
|
||||
|
||||
/*OMIXER_BST1_CTRL*/
|
||||
#define BIASVOLTAGE 12
|
||||
#define AXG 9
|
||||
#define OMIXER_MIC1G 6
|
||||
#define OMIXER_MIC2G 3
|
||||
#define LINEING 0
|
||||
|
||||
/*HPOUT_CTRL*/
|
||||
#define RHPS 15
|
||||
#define LHPS 14
|
||||
#define RHPPA_MUTE 13
|
||||
#define LHPPA_MUTE 12
|
||||
#define HPPA_EN 11
|
||||
#define HP_VOL 4
|
||||
#define HPPA_DEL 2
|
||||
#define HPPA_IS 0
|
||||
|
||||
/*ESPKOUT_CTRL*/
|
||||
#define EAR_RAMP_TIME 11
|
||||
#define ESPA_OUT_CURRENT 9
|
||||
#define ESPSR 7
|
||||
#define ESPPA_MUTE 6
|
||||
#define ESPPA_EN 5
|
||||
#define ESP_VOL 0
|
||||
|
||||
/*SPKOUT_CTRL*/
|
||||
#define HPCALICKS 13
|
||||
#define RSPKS 12
|
||||
#define RSPKINVEN 11
|
||||
#define RSPK_EN 9
|
||||
#define LSPKS 8
|
||||
#define LSPKINVEN 7
|
||||
#define LSPK_EN 5
|
||||
#define SPK_VOL 0
|
||||
|
||||
/*LOUT_CTRL*/
|
||||
#define LINEOUTG 5
|
||||
#define LINEOUTEN 4
|
||||
#define LINEOUTS0 3
|
||||
#define LINEOUTS1 2
|
||||
#define LINEOUTS2 1
|
||||
#define LINEOUTS3 0
|
||||
|
||||
/*ADDA_TUNE1*/
|
||||
#define CURRENT_TEST_SELECT 14
|
||||
#define BIHE_CTRL 12
|
||||
#define DITHER 11
|
||||
#define DITHER_CLK 9
|
||||
#define ZERO_CROSSOVER_EN 8
|
||||
#define ZERO_CROSSOVER_TIME 7
|
||||
#define EAR_SPEED_SELECT 6
|
||||
#define REF_CHOPPEN_CKS 4
|
||||
#define OPMIC_BIAS_CUR 0
|
||||
|
||||
/*ADDA_TUNE2*/
|
||||
#define OPDAC_BIAS_CUR 14
|
||||
#define OPDRV_BIAS_CUR 12
|
||||
#define OPMIX_BIAS_CUR 10
|
||||
#define OPEAR_BIAS_CUR 8
|
||||
#define OPVR_BIAS_CUR 6
|
||||
#define OPAAF_BIAS_CUR 4
|
||||
#define OPADC1_BIAS_CUR 2
|
||||
#define OPADC2_BIAS_CUR 0
|
||||
|
||||
/*ADDA_TUNE3*/
|
||||
#define LDOEN 15
|
||||
#define LDO_SEL 12
|
||||
#define BIASCALIVERIFY 11
|
||||
#define BIASMODE 10
|
||||
#define BIASCALIDATA 9
|
||||
#define OSCS 1
|
||||
#define OSCEN 0
|
||||
|
||||
/*HPOUT_STR*/
|
||||
#define HPVL_SOFT_MOD 14
|
||||
#define HPVL_STEP_CTRL 8
|
||||
#define DACA_CHND_ENA 7
|
||||
#define HPPA_MXRD_ENA 6
|
||||
#define HPVL_CTRL_OUT 0
|
||||
|
||||
#endif//__AC101_REGS_H__
|
774
ac108.h
Executable file
774
ac108.h
Executable file
|
@ -0,0 +1,774 @@
|
|||
/*
|
||||
* ac108.h -- ac108 ALSA Soc Audio driver
|
||||
*
|
||||
* Author: panjunwen
|
||||
*
|
||||
* 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 _AC108_H
|
||||
#define _AC108_H
|
||||
|
||||
|
||||
/*** AC108 Codec Register Define***/
|
||||
|
||||
//Chip Reset
|
||||
#define CHIP_RST 0x00
|
||||
#define CHIP_RST_VAL 0x12
|
||||
|
||||
//Power Control
|
||||
#define PWR_CTRL1 0x01
|
||||
#define PWR_CTRL2 0x02
|
||||
#define PWR_CTRL3 0x03
|
||||
#define PWR_CTRL4 0x04
|
||||
#define PWR_CTRL5 0x05
|
||||
#define PWR_CTRL6 0x06
|
||||
#define PWR_CTRL7 0x07
|
||||
#define PWR_CTRL8 0x08
|
||||
#define PWR_CTRL9 0x09
|
||||
|
||||
//PLL Configure Control
|
||||
#define PLL_CTRL1 0x10
|
||||
#define PLL_CTRL2 0x11
|
||||
#define PLL_CTRL3 0x12
|
||||
#define PLL_CTRL4 0x13
|
||||
#define PLL_CTRL5 0x14
|
||||
#define PLL_CTRL6 0x16
|
||||
#define PLL_CTRL7 0x17
|
||||
#define PLL_LOCK_CTRL 0x18
|
||||
|
||||
//System Clock Control
|
||||
#define SYSCLK_CTRL 0x20
|
||||
#define MOD_CLK_EN 0x21
|
||||
#define MOD_RST_CTRL 0x22
|
||||
#define DSM_CLK_CTRL 0x25
|
||||
|
||||
//I2S Common Control
|
||||
#define I2S_CTRL 0x30
|
||||
#define I2S_BCLK_CTRL 0x31
|
||||
#define I2S_LRCK_CTRL1 0x32
|
||||
#define I2S_LRCK_CTRL2 0x33
|
||||
#define I2S_FMT_CTRL1 0x34
|
||||
#define I2S_FMT_CTRL2 0x35
|
||||
#define I2S_FMT_CTRL3 0x36
|
||||
|
||||
//I2S TX1 Control
|
||||
#define I2S_TX1_CTRL1 0x38
|
||||
#define I2S_TX1_CTRL2 0x39
|
||||
#define I2S_TX1_CTRL3 0x3A
|
||||
#define I2S_TX1_CHMP_CTRL1 0x3C
|
||||
#define I2S_TX1_CHMP_CTRL2 0x3D
|
||||
#define I2S_TX1_CHMP_CTRL3 0x3E
|
||||
#define I2S_TX1_CHMP_CTRL4 0x3F
|
||||
|
||||
//I2S TX2 Control
|
||||
#define I2S_TX2_CTRL1 0x40
|
||||
#define I2S_TX2_CTRL2 0x41
|
||||
#define I2S_TX2_CTRL3 0x42
|
||||
#define I2S_TX2_CHMP_CTRL1 0x44
|
||||
#define I2S_TX2_CHMP_CTRL2 0x45
|
||||
#define I2S_TX2_CHMP_CTRL3 0x46
|
||||
#define I2S_TX2_CHMP_CTRL4 0x47
|
||||
|
||||
//I2S RX1 Control
|
||||
#define I2S_RX1_CTRL1 0x50
|
||||
#define I2S_RX1_CHMP_CTRL1 0x54
|
||||
#define I2S_RX1_CHMP_CTRL2 0x55
|
||||
#define I2S_RX1_CHMP_CTRL3 0x56
|
||||
#define I2S_RX1_CHMP_CTRL4 0x57
|
||||
|
||||
//I2S Loopback Debug
|
||||
#define I2S_LPB_DEBUG 0x58
|
||||
|
||||
//ADC Common Control
|
||||
#define ADC_SPRC 0x60
|
||||
#define ADC_DIG_EN 0x61
|
||||
#define DMIC_EN 0x62
|
||||
#define ADC_DSR 0x63
|
||||
#define ADC_FIR 0x64
|
||||
#define ADC_DDT_CTRL 0x65
|
||||
|
||||
//HPF Control
|
||||
#define HPF_EN 0x66
|
||||
#define HPF_COEF_REGH1 0x67
|
||||
#define HPF_COEF_REGH2 0x68
|
||||
#define HPF_COEF_REGL1 0x69
|
||||
#define HPF_COEF_REGL2 0x6A
|
||||
#define HPF_GAIN_REGH1 0x6B
|
||||
#define HPF_GAIN_REGH2 0x6C
|
||||
#define HPF_GAIN_REGL1 0x6D
|
||||
#define HPF_GAIN_REGL2 0x6E
|
||||
|
||||
//ADC Digital Channel Volume Control
|
||||
#define ADC1_DVOL_CTRL 0x70
|
||||
#define ADC2_DVOL_CTRL 0x71
|
||||
#define ADC3_DVOL_CTRL 0x72
|
||||
#define ADC4_DVOL_CTRL 0x73
|
||||
|
||||
//ADC Digital Mixer Source and Gain Control
|
||||
#define ADC1_DMIX_SRC 0x76
|
||||
#define ADC2_DMIX_SRC 0x77
|
||||
#define ADC3_DMIX_SRC 0x78
|
||||
#define ADC4_DMIX_SRC 0x79
|
||||
|
||||
//ADC Digital Debug Control
|
||||
#define ADC_DIG_DEBUG 0x7F
|
||||
|
||||
//I2S Pad Drive Control
|
||||
#define I2S_DAT_PADDRV_CTRL 0x80
|
||||
#define I2S_CLK_PADDRV_CTRL 0x81
|
||||
|
||||
//Analog PGA Control
|
||||
#define ANA_PGA1_CTRL 0x90
|
||||
#define ANA_PGA2_CTRL 0x91
|
||||
#define ANA_PGA3_CTRL 0x92
|
||||
#define ANA_PGA4_CTRL 0x93
|
||||
|
||||
//MIC Offset Control
|
||||
#define MIC_OFFSET_CTRL1 0x96
|
||||
#define MIC_OFFSET_CTRL2 0x97
|
||||
#define MIC1_OFFSET_STATU1 0x98
|
||||
#define MIC1_OFFSET_STATU2 0x99
|
||||
#define MIC2_OFFSET_STATU1 0x9A
|
||||
#define MIC2_OFFSET_STATU2 0x9B
|
||||
#define MIC3_OFFSET_STATU1 0x9C
|
||||
#define MIC3_OFFSET_STATU2 0x9D
|
||||
#define MIC4_OFFSET_STATU1 0x9E
|
||||
#define MIC4_OFFSET_STATU2 0x9F
|
||||
|
||||
//ADC1 Analog Control
|
||||
#define ANA_ADC1_CTRL1 0xA0
|
||||
#define ANA_ADC1_CTRL2 0xA1
|
||||
#define ANA_ADC1_CTRL3 0xA2
|
||||
#define ANA_ADC1_CTRL4 0xA3
|
||||
#define ANA_ADC1_CTRL5 0xA4
|
||||
#define ANA_ADC1_CTRL6 0xA5
|
||||
#define ANA_ADC1_CTRL7 0xA6
|
||||
|
||||
//ADC2 Analog Control
|
||||
#define ANA_ADC2_CTRL1 0xA7
|
||||
#define ANA_ADC2_CTRL2 0xA8
|
||||
#define ANA_ADC2_CTRL3 0xA9
|
||||
#define ANA_ADC2_CTRL4 0xAA
|
||||
#define ANA_ADC2_CTRL5 0xAB
|
||||
#define ANA_ADC2_CTRL6 0xAC
|
||||
#define ANA_ADC2_CTRL7 0xAD
|
||||
|
||||
//ADC3 Analog Control
|
||||
#define ANA_ADC3_CTRL1 0xAE
|
||||
#define ANA_ADC3_CTRL2 0xAF
|
||||
#define ANA_ADC3_CTRL3 0xB0
|
||||
#define ANA_ADC3_CTRL4 0xB1
|
||||
#define ANA_ADC3_CTRL5 0xB2
|
||||
#define ANA_ADC3_CTRL6 0xB3
|
||||
#define ANA_ADC3_CTRL7 0xB4
|
||||
|
||||
//ADC4 Analog Control
|
||||
#define ANA_ADC4_CTRL1 0xB5
|
||||
#define ANA_ADC4_CTRL2 0xB6
|
||||
#define ANA_ADC4_CTRL3 0xB7
|
||||
#define ANA_ADC4_CTRL4 0xB8
|
||||
#define ANA_ADC4_CTRL5 0xB9
|
||||
#define ANA_ADC4_CTRL6 0xBA
|
||||
#define ANA_ADC4_CTRL7 0xBB
|
||||
|
||||
//GPIO Configure
|
||||
#define GPIO_CFG1 0xC0
|
||||
#define GPIO_CFG2 0xC1
|
||||
#define GPIO_DAT 0xC2
|
||||
#define GPIO_DRV 0xC3
|
||||
#define GPIO_PULL 0xC4
|
||||
#define GPIO_INT_CFG 0xC5
|
||||
#define GPIO_INT_EN 0xC6
|
||||
#define GPIO_INT_STATUS 0xC7
|
||||
|
||||
//Misc
|
||||
#define BGTC_DAT 0xD1
|
||||
#define BGVC_DAT 0xD2
|
||||
#define PRNG_CLK_CTRL 0xDF
|
||||
|
||||
|
||||
|
||||
/*** AC108 Codec Register Bit Define***/
|
||||
|
||||
/*PWR_CTRL1*/
|
||||
#define CP12_CTRL 4
|
||||
#define CP12_SENSE_SELECT 3
|
||||
|
||||
/*PWR_CTRL2*/
|
||||
#define CP12_SENSE_FILT 6
|
||||
#define CP12_COMP_FF_EN 3
|
||||
#define CP12_FORCE_ENABLE 2
|
||||
#define CP12_FORCE_RSTB 1
|
||||
|
||||
/*PWR_CTRL3*/
|
||||
#define LDO33DIG_CTRL 0
|
||||
|
||||
/*PWR_CTRL6*/
|
||||
#define LDO33ANA_2XHDRM 2
|
||||
#define LDO33ANA_ENABLE 0
|
||||
|
||||
/*PWR_CTRL7*/
|
||||
#define VREF_SEL 3
|
||||
#define VREF_FASTSTART_ENABLE 1
|
||||
#define VREF_ENABLE 0
|
||||
|
||||
/*PWR_CTRL9*/
|
||||
#define VREFP_FASTSTART_ENABLE 7
|
||||
#define VREFP_RESCTRL 5
|
||||
#define VREFP_LPMODE 4
|
||||
#define IGEN_TRIM 1
|
||||
#define VREFP_ENABLE 0
|
||||
|
||||
|
||||
/*PLL_CTRL1*/
|
||||
#define PLL_IBIAS 4
|
||||
#define PLL_NDET 3
|
||||
#define PLL_LOCKED_STATUS 2
|
||||
#define PLL_COM_EN 1
|
||||
#define PLL_EN 0
|
||||
|
||||
/*PLL_CTRL2*/
|
||||
#define PLL_PREDIV2 5
|
||||
#define PLL_PREDIV1 0
|
||||
|
||||
/*PLL_CTRL3*/
|
||||
#define PLL_LOOPDIV_MSB 0
|
||||
|
||||
/*PLL_CTRL4*/
|
||||
#define PLL_LOOPDIV_LSB 0
|
||||
|
||||
/*PLL_CTRL5*/
|
||||
#define PLL_POSTDIV2 5
|
||||
#define PLL_POSTDIV1 0
|
||||
|
||||
/*PLL_CTRL6*/
|
||||
#define PLL_LDO 6
|
||||
#define PLL_CP 0
|
||||
|
||||
/*PLL_CTRL7*/
|
||||
#define PLL_CAP 6
|
||||
#define PLL_RES 4
|
||||
#define PLL_TEST_EN 0
|
||||
|
||||
/*PLL_LOCK_CTRL*/
|
||||
#define LOCK_LEVEL1 2
|
||||
#define LOCK_LEVEL2 1
|
||||
#define PLL_LOCK_EN 0
|
||||
|
||||
|
||||
/*SYSCLK_CTRL*/
|
||||
#define PLLCLK_EN 7
|
||||
#define PLLCLK_SRC 4
|
||||
#define SYSCLK_SRC 3
|
||||
#define SYSCLK_EN 0
|
||||
|
||||
/*MOD_CLK_EN & MOD_RST_CTRL*/
|
||||
#define I2S 7
|
||||
#define ADC_DIGITAL 4
|
||||
#define MIC_OFFSET_CALIBRATION 1
|
||||
#define ADC_ANALOG 0
|
||||
|
||||
/*DSM_CLK_CTRL*/
|
||||
#define MIC_OFFSET_DIV 4
|
||||
#define DSM_CLK_SEL 0
|
||||
|
||||
|
||||
/*I2S_CTRL*/
|
||||
#define BCLK_IOEN 7
|
||||
#define LRCK_IOEN 6
|
||||
#define SDO2_EN 5
|
||||
#define SDO1_EN 4
|
||||
#define TXEN 2
|
||||
#define RXEN 1
|
||||
#define GEN 0
|
||||
|
||||
/*I2S_BCLK_CTRL*/
|
||||
#define EDGE_TRANSFER 5
|
||||
#define BCLK_POLARITY 4
|
||||
#define BCLKDIV 0
|
||||
|
||||
/*I2S_LRCK_CTRL1*/
|
||||
#define LRCK_POLARITY 4
|
||||
#define LRCK_PERIODH 0
|
||||
|
||||
/*I2S_LRCK_CTRL2*/
|
||||
#define LRCK_PERIODL 0
|
||||
|
||||
/*I2S_FMT_CTRL1*/
|
||||
#define ENCD_SEL 6
|
||||
#define MODE_SEL 4
|
||||
#define TX2_OFFSET 3
|
||||
#define TX1_OFFSET 2
|
||||
#define TX_SLOT_HIZ 1
|
||||
#define TX_STATE 0
|
||||
|
||||
/*I2S_FMT_CTRL2*/
|
||||
#define SLOT_WIDTH_SEL 4
|
||||
#define SAMPLE_RESOLUTION 0
|
||||
|
||||
/*I2S_FMT_CTRL3*/
|
||||
#define TX_MLS 7
|
||||
#define SEXT 5
|
||||
#define OUT2_MUTE 4
|
||||
#define OUT1_MUTE 3
|
||||
#define LRCK_WIDTH 2
|
||||
#define TX_PDM 0
|
||||
|
||||
|
||||
/*I2S_TX1_CTRL1*/
|
||||
#define TX1_CHSEL 0
|
||||
|
||||
/*I2S_TX1_CTRL2*/
|
||||
#define TX1_CH8_EN 7
|
||||
#define TX1_CH7_EN 6
|
||||
#define TX1_CH6_EN 5
|
||||
#define TX1_CH5_EN 4
|
||||
#define TX1_CH4_EN 3
|
||||
#define TX1_CH3_EN 2
|
||||
#define TX1_CH2_EN 1
|
||||
#define TX1_CH1_EN 0
|
||||
|
||||
/*I2S_TX1_CTRL3*/
|
||||
#define TX1_CH16_EN 7
|
||||
#define TX1_CH15_EN 6
|
||||
#define TX1_CH14_EN 5
|
||||
#define TX1_CH13_EN 4
|
||||
#define TX1_CH12_EN 3
|
||||
#define TX1_CH11_EN 2
|
||||
#define TX1_CH10_EN 1
|
||||
#define TX1_CH9_EN 0
|
||||
|
||||
/*I2S_TX1_CHMP_CTRL1*/
|
||||
#define TX1_CH4_MAP 6
|
||||
#define TX1_CH3_MAP 4
|
||||
#define TX1_CH2_MAP 2
|
||||
#define TX1_CH1_MAP 0
|
||||
|
||||
/*I2S_TX1_CHMP_CTRL2*/
|
||||
#define TX1_CH8_MAP 6
|
||||
#define TX1_CH7_MAP 4
|
||||
#define TX1_CH6_MAP 2
|
||||
#define TX1_CH5_MAP 0
|
||||
|
||||
/*I2S_TX1_CHMP_CTRL3*/
|
||||
#define TX1_CH12_MAP 6
|
||||
#define TX1_CH11_MAP 4
|
||||
#define TX1_CH10_MAP 2
|
||||
#define TX1_CH9_MAP 0
|
||||
|
||||
/*I2S_TX1_CHMP_CTRL4*/
|
||||
#define TX1_CH16_MAP 6
|
||||
#define TX1_CH15_MAP 4
|
||||
#define TX1_CH14_MAP 2
|
||||
#define TX1_CH13_MAP 0
|
||||
|
||||
|
||||
/*I2S_TX2_CTRL1*/
|
||||
#define TX2_CHSEL 0
|
||||
|
||||
/*I2S_TX2_CHMP_CTRL1*/
|
||||
#define TX2_CH4_MAP 6
|
||||
#define TX2_CH3_MAP 4
|
||||
#define TX2_CH2_MAP 2
|
||||
#define TX2_CH1_MAP 0
|
||||
|
||||
/*I2S_TX2_CHMP_CTRL2*/
|
||||
#define TX2_CH8_MAP 6
|
||||
#define TX2_CH7_MAP 4
|
||||
#define TX2_CH6_MAP 2
|
||||
#define TX2_CH5_MAP 0
|
||||
|
||||
/*I2S_TX2_CHMP_CTRL3*/
|
||||
#define TX2_CH12_MAP 6
|
||||
#define TX2_CH11_MAP 4
|
||||
#define TX2_CH10_MAP 2
|
||||
#define TX2_CH9_MAP 0
|
||||
|
||||
/*I2S_TX2_CHMP_CTRL4*/
|
||||
#define TX2_CH16_MAP 6
|
||||
#define TX2_CH15_MAP 4
|
||||
#define TX2_CH14_MAP 2
|
||||
#define TX2_CH13_MAP 0
|
||||
|
||||
|
||||
/*I2S_RX1_CTRL1*/
|
||||
#define RX1_CHSEL 0
|
||||
|
||||
/*I2S_RX1_CHMP_CTRL1*/
|
||||
#define RX1_CH4_MAP 6
|
||||
#define RX1_CH3_MAP 4
|
||||
#define RX1_CH2_MAP 2
|
||||
#define RX1_CH1_MAP 0
|
||||
|
||||
/*I2S_RX1_CHMP_CTRL2*/
|
||||
#define RX1_CH8_MAP 6
|
||||
#define RX1_CH7_MAP 4
|
||||
#define RX1_CH6_MAP 2
|
||||
#define RX1_CH5_MAP 0
|
||||
|
||||
/*I2S_RX1_CHMP_CTRL3*/
|
||||
#define RX1_CH12_MAP 6
|
||||
#define RX1_CH11_MAP 4
|
||||
#define RX1_CH10_MAP 2
|
||||
#define RX1_CH9_MAP 0
|
||||
|
||||
/*I2S_RX1_CHMP_CTRL4*/
|
||||
#define RX1_CH16_MAP 6
|
||||
#define RX1_CH15_MAP 4
|
||||
#define RX1_CH14_MAP 2
|
||||
#define RX1_CH13_MAP 0
|
||||
|
||||
|
||||
/*I2S_LPB_DEBUG*/
|
||||
#define I2S_LPB_DEBUG_EN 0
|
||||
|
||||
|
||||
/*ADC_SPRC*/
|
||||
#define ADC_FS_I2S1 0
|
||||
|
||||
/*ADC_DIG_EN*/
|
||||
#define DG_EN 4
|
||||
#define ENAD4 3
|
||||
#define ENAD3 2
|
||||
#define ENAD2 1
|
||||
#define ENAD1 0
|
||||
|
||||
/*DMIC_EN*/
|
||||
#define DMIC2_EN 1
|
||||
#define DMIC1_EN 0
|
||||
|
||||
/*ADC_DSR*/
|
||||
#define DIG_ADC4_SRS 6
|
||||
#define DIG_ADC3_SRS 4
|
||||
#define DIG_ADC2_SRS 2
|
||||
#define DIG_ADC1_SRS 0
|
||||
|
||||
/*ADC_DDT_CTRL*/
|
||||
#define ADOUT_DLY_EN 2
|
||||
#define ADOUT_DTS 0
|
||||
|
||||
|
||||
/*HPF_EN*/
|
||||
#define DIG_ADC4_HPF_EN 3
|
||||
#define DIG_ADC3_HPF_EN 2
|
||||
#define DIG_ADC2_HPF_EN 1
|
||||
#define DIG_ADC1_HPF_EN 0
|
||||
|
||||
|
||||
/*ADC1_DMIX_SRC*/
|
||||
#define ADC1_ADC4_DMXL_GC 7
|
||||
#define ADC1_ADC3_DMXL_GC 6
|
||||
#define ADC1_ADC2_DMXL_GC 5
|
||||
#define ADC1_ADC1_DMXL_GC 4
|
||||
#define ADC1_ADC4_DMXL_SRC 3
|
||||
#define ADC1_ADC3_DMXL_SRC 2
|
||||
#define ADC1_ADC2_DMXL_SRC 1
|
||||
#define ADC1_ADC1_DMXL_SRC 0
|
||||
|
||||
/*ADC2_DMIX_SRC*/
|
||||
#define ADC2_ADC4_DMXL_GC 7
|
||||
#define ADC2_ADC3_DMXL_GC 6
|
||||
#define ADC2_ADC2_DMXL_GC 5
|
||||
#define ADC2_ADC1_DMXL_GC 4
|
||||
#define ADC2_ADC4_DMXL_SRC 3
|
||||
#define ADC2_ADC3_DMXL_SRC 2
|
||||
#define ADC2_ADC2_DMXL_SRC 1
|
||||
#define ADC2_ADC1_DMXL_SRC 0
|
||||
|
||||
/*ADC3_DMIX_SRC*/
|
||||
#define ADC3_ADC4_DMXL_GC 7
|
||||
#define ADC3_ADC3_DMXL_GC 6
|
||||
#define ADC3_ADC2_DMXL_GC 5
|
||||
#define ADC3_ADC1_DMXL_GC 4
|
||||
#define ADC3_ADC4_DMXL_SRC 3
|
||||
#define ADC3_ADC3_DMXL_SRC 2
|
||||
#define ADC3_ADC2_DMXL_SRC 1
|
||||
#define ADC3_ADC1_DMXL_SRC 0
|
||||
|
||||
/*ADC4_DMIX_SRC*/
|
||||
#define ADC4_ADC4_DMXL_GC 7
|
||||
#define ADC4_ADC3_DMXL_GC 6
|
||||
#define ADC4_ADC2_DMXL_GC 5
|
||||
#define ADC4_ADC1_DMXL_GC 4
|
||||
#define ADC4_ADC4_DMXL_SRC 3
|
||||
#define ADC4_ADC3_DMXL_SRC 2
|
||||
#define ADC4_ADC2_DMXL_SRC 1
|
||||
#define ADC4_ADC1_DMXL_SRC 0
|
||||
|
||||
|
||||
/*ADC_DIG_DEBUG*/
|
||||
#define ADC_PTN_SEL 0
|
||||
|
||||
|
||||
/*I2S_DAT_PADDRV_CTRL*/
|
||||
#define TX2_DAT_DRV 4
|
||||
#define TX1_DAT_DRV 0
|
||||
|
||||
/*I2S_CLK_PADDRV_CTRL*/
|
||||
#define LRCK_DRV 4
|
||||
#define BCLK_DRV 0
|
||||
|
||||
|
||||
/*ANA_PGA1_CTRL*/
|
||||
#define ADC1_ANALOG_PGA 1
|
||||
#define ADC1_ANALOG_PGA_STEP 0
|
||||
|
||||
/*ANA_PGA2_CTRL*/
|
||||
#define ADC2_ANALOG_PGA 1
|
||||
#define ADC2_ANALOG_PGA_STEP 0
|
||||
|
||||
/*ANA_PGA3_CTRL*/
|
||||
#define ADC3_ANALOG_PGA 1
|
||||
#define ADC3_ANALOG_PGA_STEP 0
|
||||
|
||||
/*ANA_PGA4_CTRL*/
|
||||
#define ADC4_ANALOG_PGA 1
|
||||
#define ADC4_ANALOG_PGA_STEP 0
|
||||
|
||||
|
||||
/*MIC_OFFSET_CTRL1*/
|
||||
#define MIC_OFFSET_CAL_EN4 3
|
||||
#define MIC_OFFSET_CAL_EN3 2
|
||||
#define MIC_OFFSET_CAL_EN2 1
|
||||
#define MIC_OFFSET_CAL_EN1 0
|
||||
|
||||
/*MIC_OFFSET_CTRL2*/
|
||||
#define MIC_OFFSET_CAL_GAIN 3
|
||||
#define MIC_OFFSET_CAL_CHANNEL 1
|
||||
#define MIC_OFFSET_CAL_EN_ONCE 0
|
||||
|
||||
/*MIC1_OFFSET_STATU1*/
|
||||
#define MIC1_OFFSET_CAL_DONE 7
|
||||
#define MIC1_OFFSET_CAL_RUN_STA 6
|
||||
#define MIC1_OFFSET_MSB 0
|
||||
|
||||
/*MIC1_OFFSET_STATU2*/
|
||||
#define MIC1_OFFSET_LSB 0
|
||||
|
||||
/*MIC2_OFFSET_STATU1*/
|
||||
#define MIC2_OFFSET_CAL_DONE 7
|
||||
#define MIC2_OFFSET_CAL_RUN_STA 6
|
||||
#define MIC2_OFFSET_MSB 0
|
||||
|
||||
/*MIC2_OFFSET_STATU2*/
|
||||
#define MIC2_OFFSET_LSB 0
|
||||
|
||||
/*MIC3_OFFSET_STATU1*/
|
||||
#define MIC3_OFFSET_CAL_DONE 7
|
||||
#define MIC3_OFFSET_CAL_RUN_STA 6
|
||||
#define MIC3_OFFSET_MSB 0
|
||||
|
||||
/*MIC3_OFFSET_STATU2*/
|
||||
#define MIC3_OFFSET_LSB 0
|
||||
|
||||
/*MIC4_OFFSET_STATU1*/
|
||||
#define MIC4_OFFSET_CAL_DONE 7
|
||||
#define MIC4_OFFSET_CAL_RUN_STA 6
|
||||
#define MIC4_OFFSET_MSB 0
|
||||
|
||||
/*MIC4_OFFSET_STATU2*/
|
||||
#define MIC4_OFFSET_LSB 0
|
||||
|
||||
|
||||
/*ANA_ADC1_CTRL1*/
|
||||
#define ADC1_PGA_BYPASS 7
|
||||
#define ADC1_PGA_BYP_RCM 6
|
||||
#define ADC1_PGA_CTRL_RCM 4
|
||||
#define ADC1_PGA_MUTE 3
|
||||
#define ADC1_DSM_ENABLE 2
|
||||
#define ADC1_PGA_ENABLE 1
|
||||
#define ADC1_MICBIAS_EN 0
|
||||
|
||||
/*ANA_ADC1_CTRL3*/
|
||||
#define ADC1_ANA_CAL_EN 5
|
||||
#define ADC1_SEL_OUT_EDGE 3
|
||||
#define ADC1_DSM_DISABLE 2
|
||||
#define ADC1_VREFP_DISABLE 1
|
||||
#define ADC1_AAF_DISABLE 0
|
||||
|
||||
/*ANA_ADC1_CTRL6*/
|
||||
#define PGA_CTRL_TC 6
|
||||
#define PGA_CTRL_RC 4
|
||||
#define PGA_CTRL_I_LIN 2
|
||||
#define PGA_CTRL_I_IN 0
|
||||
|
||||
/*ANA_ADC1_CTRL7*/
|
||||
#define PGA_CTRL_HI_Z 7
|
||||
#define PGA_CTRL_SHORT_RF 6
|
||||
#define PGA_CTRL_VCM_VG 4
|
||||
#define PGA_CTRL_VCM_IN 0
|
||||
|
||||
|
||||
/*ANA_ADC2_CTRL1*/
|
||||
#define ADC2_PGA_BYPASS 7
|
||||
#define ADC2_PGA_BYP_RCM 6
|
||||
#define ADC2_PGA_CTRL_RCM 4
|
||||
#define ADC2_PGA_MUTE 3
|
||||
#define ADC2_DSM_ENABLE 2
|
||||
#define ADC2_PGA_ENABLE 1
|
||||
#define ADC2_MICBIAS_EN 0
|
||||
|
||||
/*ANA_ADC2_CTRL3*/
|
||||
#define ADC2_ANA_CAL_EN 5
|
||||
#define ADC2_SEL_OUT_EDGE 3
|
||||
#define ADC2_DSM_DISABLE 2
|
||||
#define ADC2_VREFP_DISABLE 1
|
||||
#define ADC2_AAF_DISABLE 0
|
||||
|
||||
/*ANA_ADC2_CTRL6*/
|
||||
#define PGA_CTRL_IBOOST 7
|
||||
#define PGA_CTRL_IQCTRL 6
|
||||
#define PGA_CTRL_OABIAS 4
|
||||
#define PGA_CTRL_CMLP_DIS 3
|
||||
#define PGA_CTRL_PDB_RIN 2
|
||||
#define PGA_CTRL_PEAKDET 0
|
||||
|
||||
/*ANA_ADC2_CTRL7*/
|
||||
#define AAF_LPMODE_EN 7
|
||||
#define AAF_STG2_IB_SEL 4
|
||||
#define AAFDSM_IB_DIV2 3
|
||||
#define AAF_STG1_IB_SEL 0
|
||||
|
||||
|
||||
/*ANA_ADC3_CTRL1*/
|
||||
#define ADC3_PGA_BYPASS 7
|
||||
#define ADC3_PGA_BYP_RCM 6
|
||||
#define ADC3_PGA_CTRL_RCM 4
|
||||
#define ADC3_PGA_MUTE 3
|
||||
#define ADC3_DSM_ENABLE 2
|
||||
#define ADC3_PGA_ENABLE 1
|
||||
#define ADC3_MICBIAS_EN 0
|
||||
|
||||
/*ANA_ADC3_CTRL3*/
|
||||
#define ADC3_ANA_CAL_EN 5
|
||||
#define ADC3_INVERT_CLK 4
|
||||
#define ADC3_SEL_OUT_EDGE 3
|
||||
#define ADC3_DSM_DISABLE 2
|
||||
#define ADC3_VREFP_DISABLE 1
|
||||
#define ADC3_AAF_DISABLE 0
|
||||
|
||||
/*ANA_ADC3_CTRL7*/
|
||||
#define DSM_COMP_IB_SEL 6
|
||||
#define DSM_OTA_CTRL 4
|
||||
#define DSM_LPMODE 3
|
||||
#define DSM_OTA_IB_SEL 0
|
||||
|
||||
|
||||
/*ANA_ADC4_CTRL1*/
|
||||
#define ADC4_PGA_BYPASS 7
|
||||
#define ADC4_PGA_BYP_RCM 6
|
||||
#define ADC4_PGA_CTRL_RCM 4
|
||||
#define ADC4_PGA_MUTE 3
|
||||
#define ADC4_DSM_ENABLE 2
|
||||
#define ADC4_PGA_ENABLE 1
|
||||
#define ADC4_MICBIAS_EN 0
|
||||
|
||||
/*ANA_ADC4_CTRL3*/
|
||||
#define ADC4_ANA_CAL_EN 5
|
||||
#define ADC4_SEL_OUT_EDGE 3
|
||||
#define ADC4_DSM_DISABLE 2
|
||||
#define ADC4_VREFP_DISABLE 1
|
||||
#define ADC4_AAF_DISABLE 0
|
||||
|
||||
/*ANA_ADC4_CTRL6*/
|
||||
#define DSM_DEMOFF 5
|
||||
#define DSM_EN_DITHER 4
|
||||
#define DSM_VREFP_LPMODE 2
|
||||
#define DSM_VREFP_OUTCTRL 0
|
||||
|
||||
/*ANA_ADC4_CTRL7*/
|
||||
#define CK8M_EN 5
|
||||
#define OSC_EN 4
|
||||
#define ADC4_CLK_GATING 3
|
||||
#define ADC3_CLK_GATING 2
|
||||
#define ADC2_CLK_GATING 1
|
||||
#define ADC1_CLK_GATING 0
|
||||
|
||||
|
||||
/*GPIO_CFG1*/
|
||||
#define GPIO2_SELECT 4
|
||||
#define GPIO1_SELECT 0
|
||||
|
||||
/*GPIO_CFG2*/
|
||||
#define GPIO4_SELECT 4
|
||||
#define GPIO3_SELECT 0
|
||||
|
||||
/*GPIO_DAT*///order???
|
||||
#define GPIO4_DAT 3
|
||||
#define GPIO3_DAT 2
|
||||
#define GPIO2_DAT 1
|
||||
#define GPIO1_DAT 0
|
||||
|
||||
/*GPIO_DRV*/
|
||||
#define GPIO4_DRV 6
|
||||
#define GPIO3_DRV 4
|
||||
#define GPIO2_DRV 2
|
||||
#define GPIO1_DRV 0
|
||||
|
||||
/*GPIO_PULL*/
|
||||
#define GPIO4_PULL 6
|
||||
#define GPIO3_PULL 4
|
||||
#define GPIO2_PULL 2
|
||||
#define GPIO1_PULL 0
|
||||
|
||||
/*GPIO_INT_CFG*/
|
||||
#define GPIO4_EINT_CFG 6
|
||||
#define GPIO3_EINT_CFG 4
|
||||
#define GPIO2_EINT_CFG 2
|
||||
#define GPIO1_EINT_CFG 0
|
||||
|
||||
/*GPIO_INT_EN*///order???
|
||||
#define GPIO4_EINT_EN 3
|
||||
#define GPIO3_EINT_EN 2
|
||||
#define GPIO2_EINT_EN 1
|
||||
#define GPIO1_EINT_EN 0
|
||||
|
||||
/*GPIO_INT_STATUS*///order???
|
||||
#define GPIO4_EINT_STA 3
|
||||
#define GPIO3_EINT_STA 2
|
||||
#define GPIO2_EINT_STA 1
|
||||
#define GPIO1_EINT_STA 0
|
||||
|
||||
|
||||
/*PRNG_CLK_CTRL*/
|
||||
#define PRNG_CLK_EN 1
|
||||
#define PRNG_CLK_POS 0
|
||||
|
||||
|
||||
|
||||
/*** Some Config Value ***/
|
||||
|
||||
//[SYSCLK_CTRL]: PLLCLK_SRC
|
||||
#define PLLCLK_SRC_MCLK 0
|
||||
#define PLLCLK_SRC_BCLK 1
|
||||
#define PLLCLK_SRC_GPIO2 2
|
||||
#define PLLCLK_SRC_GPIO3 3
|
||||
|
||||
//[SYSCLK_CTRL]: SYSCLK_SRC
|
||||
#define SYSCLK_SRC_MCLK 0
|
||||
#define SYSCLK_SRC_PLL 1
|
||||
|
||||
//I2S BCLK POLARITY Control
|
||||
#define BCLK_NORMAL_DRIVE_N_SAMPLE_P 0
|
||||
#define BCLK_INVERT_DRIVE_P_SAMPLE_N 1
|
||||
|
||||
//I2S LRCK POLARITY Control
|
||||
#define LRCK_LEFT_LOW_RIGHT_HIGH 0
|
||||
#define LRCK_LEFT_HIGH_RIGHT_LOW 1
|
||||
|
||||
//I2S Format Selection
|
||||
#define PCM_FORMAT 0
|
||||
#define LEFT_JUSTIFIED_FORMAT 1
|
||||
#define RIGHT_JUSTIFIED_FORMAT 2
|
||||
|
||||
|
||||
//I2S data protocol types
|
||||
|
||||
#define IS_ENCODING_MODE 0
|
||||
|
||||
#endif
|
||||
|
367
ac108_6mic.state
Normal file
367
ac108_6mic.state
Normal file
|
@ -0,0 +1,367 @@
|
|||
state.ALSA {
|
||||
control.1 {
|
||||
iface MIXER
|
||||
name 'PCM Playback Volume'
|
||||
value 400
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '-10239 - 400'
|
||||
dbmin -9999999
|
||||
dbmax 400
|
||||
dbvalue.0 400
|
||||
}
|
||||
}
|
||||
control.2 {
|
||||
iface MIXER
|
||||
name 'PCM Playback Switch'
|
||||
value true
|
||||
comment {
|
||||
access 'read write'
|
||||
type BOOLEAN
|
||||
count 1
|
||||
}
|
||||
}
|
||||
control.3 {
|
||||
iface MIXER
|
||||
name 'PCM Playback Route'
|
||||
value 1
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 2'
|
||||
}
|
||||
}
|
||||
control.4 {
|
||||
iface PCM
|
||||
name 'IEC958 Playback Default'
|
||||
value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
comment {
|
||||
access 'read write'
|
||||
type IEC958
|
||||
count 1
|
||||
}
|
||||
}
|
||||
control.5 {
|
||||
iface PCM
|
||||
name 'IEC958 Playback Con Mask'
|
||||
value '0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
comment {
|
||||
access read
|
||||
type IEC958
|
||||
count 1
|
||||
}
|
||||
}
|
||||
control.6 {
|
||||
iface PCM
|
||||
name 'IEC958 Playback PCM Stream'
|
||||
value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
comment {
|
||||
access 'read write inactive'
|
||||
type IEC958
|
||||
count 1
|
||||
}
|
||||
}
|
||||
}
|
||||
state.seeed8micvoicec {
|
||||
control.1 {
|
||||
iface MIXER
|
||||
name 'CH1 digital volume'
|
||||
value 208
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 3675
|
||||
}
|
||||
}
|
||||
control.2 {
|
||||
iface MIXER
|
||||
name 'CH2 digital volume'
|
||||
value 208
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 3675
|
||||
}
|
||||
}
|
||||
control.3 {
|
||||
iface MIXER
|
||||
name 'CH3 digital volume'
|
||||
value 208
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 3675
|
||||
}
|
||||
}
|
||||
control.4 {
|
||||
iface MIXER
|
||||
name 'CH4 digital volume'
|
||||
value 208
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 3675
|
||||
}
|
||||
}
|
||||
control.5 {
|
||||
iface MIXER
|
||||
name 'ADC1 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
control.6 {
|
||||
iface MIXER
|
||||
name 'ADC2 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
control.7 {
|
||||
iface MIXER
|
||||
name 'ADC3 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
control.8 {
|
||||
iface MIXER
|
||||
name 'ADC4 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
control.9 {
|
||||
iface MIXER
|
||||
name 'CH5 digital volume'
|
||||
value 208
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 3675
|
||||
}
|
||||
}
|
||||
control.10 {
|
||||
iface MIXER
|
||||
name 'CH6 digital volume'
|
||||
value 208
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 3675
|
||||
}
|
||||
}
|
||||
control.11 {
|
||||
iface MIXER
|
||||
name 'CH7 digital volume'
|
||||
value 198
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 2925
|
||||
}
|
||||
}
|
||||
control.12 {
|
||||
iface MIXER
|
||||
name 'CH8 digital volume'
|
||||
value 198
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 2925
|
||||
}
|
||||
}
|
||||
control.13 {
|
||||
iface MIXER
|
||||
name 'ADC5 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
control.14 {
|
||||
iface MIXER
|
||||
name 'ADC6 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
control.15 {
|
||||
iface MIXER
|
||||
name 'ADC7 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
control.16 {
|
||||
iface MIXER
|
||||
name 'ADC8 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
control.17 {
|
||||
iface MIXER
|
||||
name 'DAC volume'
|
||||
value.0 0
|
||||
value.1 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 2
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 -11925
|
||||
dbvalue.1 -11925
|
||||
}
|
||||
}
|
||||
control.18 {
|
||||
iface MIXER
|
||||
name 'DAC mixer gain'
|
||||
value.0 0
|
||||
value.1 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 2
|
||||
range '0 - 15'
|
||||
dbmin -600
|
||||
dbmax 8400
|
||||
dbvalue.0 -600
|
||||
dbvalue.1 -600
|
||||
}
|
||||
}
|
||||
control.19 {
|
||||
iface MIXER
|
||||
name 'digital volume'
|
||||
value 51
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 63'
|
||||
dbmin -7308
|
||||
dbmax 0
|
||||
dbvalue.0 -1392
|
||||
}
|
||||
}
|
||||
control.20 {
|
||||
iface MIXER
|
||||
name 'Speaker Playback Volume'
|
||||
value 25
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin -4800
|
||||
dbmax -150
|
||||
dbvalue.0 -1050
|
||||
}
|
||||
}
|
||||
control.21 {
|
||||
iface MIXER
|
||||
name 'Headphone Playback Volume'
|
||||
value 52
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 63'
|
||||
dbmin -6300
|
||||
dbmax 0
|
||||
dbvalue.0 -1100
|
||||
}
|
||||
}
|
||||
}
|
181
ac108_asound.state
Normal file
181
ac108_asound.state
Normal file
|
@ -0,0 +1,181 @@
|
|||
state.ALSA {
|
||||
control.1 {
|
||||
iface MIXER
|
||||
name 'PCM Playback Volume'
|
||||
value 400
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '-10239 - 400'
|
||||
dbmin -9999999
|
||||
dbmax 400
|
||||
dbvalue.0 400
|
||||
}
|
||||
}
|
||||
control.2 {
|
||||
iface MIXER
|
||||
name 'PCM Playback Switch'
|
||||
value true
|
||||
comment {
|
||||
access 'read write'
|
||||
type BOOLEAN
|
||||
count 1
|
||||
}
|
||||
}
|
||||
control.3 {
|
||||
iface MIXER
|
||||
name 'PCM Playback Route'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 2'
|
||||
}
|
||||
}
|
||||
control.4 {
|
||||
iface PCM
|
||||
name 'IEC958 Playback Default'
|
||||
value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
comment {
|
||||
access 'read write'
|
||||
type IEC958
|
||||
count 1
|
||||
}
|
||||
}
|
||||
control.5 {
|
||||
iface PCM
|
||||
name 'IEC958 Playback Con Mask'
|
||||
value '0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
comment {
|
||||
access read
|
||||
type IEC958
|
||||
count 1
|
||||
}
|
||||
}
|
||||
control.6 {
|
||||
iface PCM
|
||||
name 'IEC958 Playback PCM Stream'
|
||||
value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
comment {
|
||||
access 'read write inactive'
|
||||
type IEC958
|
||||
count 1
|
||||
}
|
||||
}
|
||||
}
|
||||
state.seeed4micvoicec {
|
||||
control.1 {
|
||||
iface MIXER
|
||||
name 'CH1 digital volume'
|
||||
value 222
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 4725
|
||||
}
|
||||
}
|
||||
control.2 {
|
||||
iface MIXER
|
||||
name 'CH2 digital volume'
|
||||
value 222
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 4725
|
||||
}
|
||||
}
|
||||
control.3 {
|
||||
iface MIXER
|
||||
name 'CH3 digital volume'
|
||||
value 222
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 4725
|
||||
}
|
||||
}
|
||||
control.4 {
|
||||
iface MIXER
|
||||
name 'CH4 digital volume'
|
||||
value 222
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 255'
|
||||
dbmin -11925
|
||||
dbmax 7200
|
||||
dbvalue.0 4725
|
||||
}
|
||||
}
|
||||
control.5 {
|
||||
iface MIXER
|
||||
name 'ADC1 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
control.6 {
|
||||
iface MIXER
|
||||
name 'ADC2 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
control.7 {
|
||||
iface MIXER
|
||||
name 'ADC3 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
control.8 {
|
||||
iface MIXER
|
||||
name 'ADC4 PGA gain'
|
||||
value 0
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
count 1
|
||||
range '0 - 31'
|
||||
dbmin 0
|
||||
dbmax 3100
|
||||
dbvalue.0 0
|
||||
}
|
||||
}
|
||||
}
|
58
ac108_plugin/Makefile
Normal file
58
ac108_plugin/Makefile
Normal file
|
@ -0,0 +1,58 @@
|
|||
|
||||
# Quiet (set to @ for a quite compile)
|
||||
Q ?= @
|
||||
#Q ?=
|
||||
|
||||
# Build Tools
|
||||
CC := gcc
|
||||
CFLAGS += -I. -Wall -funroll-loops -ffast-math -fPIC -DPIC -O0 -g
|
||||
LD := gcc
|
||||
LDFLAGS += -Wall -shared -lasound
|
||||
|
||||
SND_PCM_OBJECTS = pcm_ac108.o ac108_help.o
|
||||
SND_PCM_LIBS =
|
||||
SND_PCM_BIN = libasound_module_pcm_ac108.so
|
||||
|
||||
#SND_CTL_OBJECTS = ctl_ac108.o ladspa_utils.o
|
||||
#SND_CTL_LIBS =
|
||||
#SND_CTL_BIN = libasound_module_ctl_ac108.so
|
||||
|
||||
MULTIARCH:=$(shell gcc --print-multiarch)
|
||||
LIBDIR = lib/$(MULTIARCH)
|
||||
|
||||
.PHONY: all clean dep load_default
|
||||
|
||||
all: Makefile $(SND_PCM_BIN) $(SND_CTL_BIN)
|
||||
|
||||
dep:
|
||||
@echo DEP $@
|
||||
$(Q)for i in *.c; do $(CC) -MM $(CFLAGS) "$${i}" ; done > makefile.dep
|
||||
|
||||
-include makefile.dep
|
||||
|
||||
$(SND_PCM_BIN): $(SND_PCM_OBJECTS)
|
||||
@echo LD $@
|
||||
$(Q)$(LD) $(LDFLAGS) $(SND_PCM_LIBS) $(SND_PCM_OBJECTS) -o $(SND_PCM_BIN)
|
||||
|
||||
#$(SND_CTL_BIN): $(SND_CTL_OBJECTS)
|
||||
# @echo LD $@
|
||||
# $(Q)$(LD) $(LDFLAGS) $(SND_CTL_LIBS) $(SND_CTL_OBJECTS) -o $(SND_CTL_BIN)
|
||||
|
||||
%.o: %.c
|
||||
@echo GCC $<
|
||||
$(Q)$(CC) -c $(CFLAGS) $(CPPFLAGS) $<
|
||||
|
||||
clean:
|
||||
@echo Cleaning...
|
||||
$(Q)rm -vf *.o *.so
|
||||
|
||||
install: all
|
||||
@echo Installing...
|
||||
$(Q)mkdir -p ${DESTDIR}/usr/$(LIBDIR)/alsa-lib/
|
||||
$(Q)install -m 644 $(SND_PCM_BIN) ${DESTDIR}/usr/$(LIBDIR)/alsa-lib/
|
||||
#$(Q)install -m 644 $(SND_CTL_BIN) ${DESTDIR}/usr/$(LIBDIR)/alsa-lib/
|
||||
|
||||
uninstall:
|
||||
@echo Un-installing...
|
||||
$(Q)rm ${DESTDIR}/usr/lib/alsa-lib/$(SND_PCM_BIN)
|
||||
#$(Q)rm ${DESTDIR}/usr/lib/alsa-lib/$(SND_CTL_BIN)
|
5
ac108_plugin/README.md
Normal file
5
ac108_plugin/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
#seeed-4mic-voicecard alsa plugin
|
||||
```
|
||||
sudo apt install libasound2-dev
|
||||
make && sudo make install
|
||||
```
|
77
ac108_plugin/ac108_help.c
Normal file
77
ac108_plugin/ac108_help.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "ac108_help.h"
|
||||
|
||||
void generate_sine(const snd_pcm_channel_area_t *areas,
|
||||
snd_pcm_uframes_t offset,
|
||||
int count, double *_phase)
|
||||
{
|
||||
snd_pcm_format_t format = SND_PCM_FORMAT_S32; /* sample format */
|
||||
unsigned int rate = 16000; /* stream rate */
|
||||
unsigned int channels = 4; /* count of channels */
|
||||
unsigned int buffer_time = 500000; /* ring buffer length in us */
|
||||
unsigned int period_time = 100000; /* period time in us */
|
||||
double freq = 160; /* sinusoidal wave frequency in Hz */
|
||||
int verbose = 0; /* verbose flag */
|
||||
int resample = 1; /* enable alsa-lib resampling */
|
||||
int period_event = 0; /* produce poll event after each period */
|
||||
|
||||
static double max_phase = 2. * M_PI;
|
||||
double phase = *_phase;
|
||||
double step = max_phase*freq/(double)rate;
|
||||
unsigned char *samples[channels];
|
||||
int steps[channels];
|
||||
unsigned int chn;
|
||||
int format_bits = snd_pcm_format_width(format);
|
||||
unsigned int maxval = (1 << (format_bits - 1)) - 1;
|
||||
int bps = format_bits / 8; /* bytes per sample */
|
||||
int phys_bps = snd_pcm_format_physical_width(format) / 8;
|
||||
int big_endian = snd_pcm_format_big_endian(format) == 1;
|
||||
int to_unsigned = snd_pcm_format_unsigned(format) == 1;
|
||||
int is_float = (format == SND_PCM_FORMAT_FLOAT_LE ||
|
||||
format == SND_PCM_FORMAT_FLOAT_BE);
|
||||
|
||||
/* verify and prepare the contents of areas */
|
||||
for (chn = 0; chn < channels; chn++) {
|
||||
if ((areas[chn].first % 8) != 0) {
|
||||
printf("areas[%i].first == %i, aborting...\n", chn, areas[chn].first);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
|
||||
if ((areas[chn].step % 16) != 0) {
|
||||
printf("areas[%i].step == %i, aborting...\n", chn, areas[chn].step);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
steps[chn] = areas[chn].step / 8;
|
||||
samples[chn] += offset * steps[chn];
|
||||
}
|
||||
/* fill the channel areas */
|
||||
while (count-- > 0) {
|
||||
union {
|
||||
float f;
|
||||
int i;
|
||||
} fval;
|
||||
int res, i;
|
||||
if (is_float) {
|
||||
fval.f = sin(phase);
|
||||
res = fval.i;
|
||||
} else
|
||||
res = sin(phase) * maxval;
|
||||
if (to_unsigned)
|
||||
res ^= 1U << (format_bits - 1);
|
||||
for (chn = 0; chn < channels; chn++) {
|
||||
/* Generate data in native endian format */
|
||||
if (big_endian) {
|
||||
for (i = 0; i < bps; i++)
|
||||
*(samples[chn] + phys_bps - 1 - i) = (res >> i * 8) & 0xff;
|
||||
} else {
|
||||
for (i = 0; i < bps; i++)
|
||||
*(samples[chn] + i) = (res >> i * 8) & 0xff;
|
||||
}
|
||||
samples[chn] += steps[chn];
|
||||
}
|
||||
phase += step;
|
||||
if (phase >= max_phase)
|
||||
phase -= max_phase;
|
||||
}
|
||||
*_phase = phase;
|
||||
}
|
||||
|
11
ac108_plugin/ac108_help.h
Normal file
11
ac108_plugin/ac108_help.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <alsa/pcm_external.h>
|
||||
#include <alsa/pcm_plugin.h>
|
||||
#include <math.h>
|
||||
|
||||
void generate_sine(const snd_pcm_channel_area_t *areas,
|
||||
snd_pcm_uframes_t offset,
|
||||
int count, double *_phase);
|
BIN
ac108_plugin/libasound_module_pcm_ac108.so
Executable file
BIN
ac108_plugin/libasound_module_pcm_ac108.so
Executable file
Binary file not shown.
536
ac108_plugin/pcm_ac108.c
Normal file
536
ac108_plugin/pcm_ac108.c
Normal file
|
@ -0,0 +1,536 @@
|
|||
//https://github.com/HazouPH/android_device_motorola_smi-plus/blob/48029b4afc307c73181b108a5b0155b9f20856ca/smi-modules/alsa-lib_module_voice/pcm_voice.c
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <alsa/pcm_external.h>
|
||||
#include <alsa/pcm_plugin.h>
|
||||
#include "ac108_help.h"
|
||||
#include <math.h>
|
||||
|
||||
#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0]))
|
||||
#define AC108_FRAME_SIZE 40960
|
||||
struct ac108_t {
|
||||
snd_pcm_ioplug_t io;
|
||||
snd_pcm_t *pcm;
|
||||
snd_pcm_hw_params_t *hw_params;
|
||||
unsigned int last_size;
|
||||
unsigned int ptr;
|
||||
unsigned int latency; // Delay in usec
|
||||
unsigned int bufferSize; // Size of sample buffer
|
||||
};
|
||||
static unsigned char capture_buf[AC108_FRAME_SIZE];
|
||||
/* set up the fixed parameters of pcm PCM hw_parmas */
|
||||
static int ac108_slave_hw_params_half(struct ac108_t *capture, unsigned int rate,snd_pcm_format_t format) {
|
||||
int err;
|
||||
snd_pcm_uframes_t bufferSize = capture->bufferSize;
|
||||
unsigned int latency = capture->latency;
|
||||
|
||||
unsigned int buffer_time = 0;
|
||||
unsigned int period_time = 0;
|
||||
if ((err = snd_pcm_hw_params_malloc(&capture->hw_params)) < 0) return err;
|
||||
|
||||
if ((err = snd_pcm_hw_params_any(capture->pcm, capture->hw_params)) < 0) {
|
||||
SNDERR("Cannot get pcm hw_params");
|
||||
goto out;
|
||||
}
|
||||
if ((err = snd_pcm_hw_params_set_access(capture->pcm, capture->hw_params,
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
||||
SNDERR("Cannot set pcm access RW_INTERLEAVED");
|
||||
goto out;
|
||||
}
|
||||
if ((err = snd_pcm_hw_params_set_channels(capture->pcm, capture->hw_params, 2)) < 0) {
|
||||
SNDERR("Cannot set pcm channels 2");
|
||||
goto out;
|
||||
}
|
||||
if ((err = snd_pcm_hw_params_set_format(capture->pcm, capture->hw_params,
|
||||
format)) < 0) {
|
||||
SNDERR("Cannot set pcm format");
|
||||
goto out;
|
||||
}
|
||||
if ((err = snd_pcm_hw_params_set_rate(capture->pcm, capture->hw_params, rate, 0)) < 0) {
|
||||
SNDERR("Cannot set pcm rate %d", rate);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = snd_pcm_hw_params_get_buffer_time_max(capture->hw_params,
|
||||
&buffer_time, 0);
|
||||
if (buffer_time > 80000)
|
||||
buffer_time = 80000;
|
||||
period_time = buffer_time / 4;
|
||||
|
||||
err = snd_pcm_hw_params_set_period_time_near(capture->pcm, capture->hw_params,
|
||||
&period_time, 0);
|
||||
if (err < 0) {
|
||||
SNDERR("Unable to set_period_time_near");
|
||||
goto out;
|
||||
}
|
||||
err = snd_pcm_hw_params_set_buffer_time_near(capture->pcm, capture->hw_params,
|
||||
&buffer_time, 0);
|
||||
if (err < 0) {
|
||||
SNDERR("Unable to set_buffer_time_near");
|
||||
goto out;
|
||||
}
|
||||
|
||||
capture->bufferSize = bufferSize;
|
||||
capture->latency = latency;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
free(capture->hw_params);
|
||||
capture->hw_params = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* start and stop callbacks - just trigger pcm PCM
|
||||
*/
|
||||
static int ac108_start(snd_pcm_ioplug_t *io) {
|
||||
struct ac108_t *capture = io->private_data;
|
||||
if(!capture->pcm) {
|
||||
SNDERR( "pcm is lost\n");
|
||||
}
|
||||
|
||||
return snd_pcm_start(capture->pcm);
|
||||
}
|
||||
|
||||
static int ac108_stop(snd_pcm_ioplug_t *io) {
|
||||
struct ac108_t *capture = io->private_data;
|
||||
|
||||
return snd_pcm_drop(capture->pcm);
|
||||
}
|
||||
/*
|
||||
* pointer callback
|
||||
*
|
||||
* Calculate the current position from the delay of pcm PCM
|
||||
*/
|
||||
static snd_pcm_sframes_t ac108_pointer(snd_pcm_ioplug_t *io) {
|
||||
|
||||
struct ac108_t *capture = io->private_data;
|
||||
int size;
|
||||
|
||||
assert(capture);
|
||||
|
||||
|
||||
size = snd_pcm_avail(capture->pcm);
|
||||
if (size < 0)
|
||||
return size;
|
||||
|
||||
size = size/2;
|
||||
|
||||
if (size > capture->last_size) {
|
||||
capture->ptr += size - capture->last_size;
|
||||
capture->ptr %= io->buffer_size;
|
||||
}
|
||||
|
||||
//fprintf(stderr, "%s :%d %d %d %d %d %d\n", __func__,capture->ptr ,capture->last_size,size, io->buffer_size,io->appl_ptr, io->hw_ptr);
|
||||
capture->last_size = size;
|
||||
|
||||
return capture->ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* transfer callback
|
||||
*/
|
||||
static snd_pcm_sframes_t ac108_transfer(snd_pcm_ioplug_t *io,
|
||||
const snd_pcm_channel_area_t *dst_areas,
|
||||
snd_pcm_uframes_t dst_offset,
|
||||
snd_pcm_uframes_t size) {
|
||||
struct ac108_t *capture = io->private_data;
|
||||
int chn;
|
||||
unsigned char *dst_samples[io->channels];
|
||||
int dst_steps[io->channels];
|
||||
int bps = snd_pcm_format_width(io->format) / 8; /* bytes per sample */
|
||||
int i;
|
||||
int count = 0;
|
||||
int err = 0;
|
||||
unsigned char *src_buf;
|
||||
unsigned char src_data[4][4];
|
||||
|
||||
|
||||
memset(capture_buf,0,AC108_FRAME_SIZE);
|
||||
|
||||
if(snd_pcm_avail(capture->pcm) > size*2){
|
||||
if ((err = snd_pcm_readi (capture->pcm, capture_buf, size*2)) != size*2) {
|
||||
SNDERR("read from audio interface failed %ld %d %s!\n",size,err,snd_strerror (err));
|
||||
exit(EXIT_FAILURE);
|
||||
size = 0 ;
|
||||
}
|
||||
}else{
|
||||
size = 0;
|
||||
}
|
||||
#if 1
|
||||
/* verify and prepare the contents of areas */
|
||||
for (chn = 0; chn < io->channels; chn++) {
|
||||
if ((dst_areas[chn].first % 8) != 0) {
|
||||
SNDERR("dst_areas[%i].first == %i, aborting...\n", chn, dst_areas[chn].first);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
dst_samples[chn] = /*(signed short *)*/(((unsigned char *)dst_areas[chn].addr) + (dst_areas[chn].first / 8));
|
||||
if ((dst_areas[chn].step % 16) != 0) {
|
||||
SNDERR("dst_areas[%i].step == %i, aborting...\n", chn, dst_areas[chn].step);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
dst_steps[chn] = dst_areas[chn].step / 8;
|
||||
dst_samples[chn] += dst_offset * dst_steps[chn];
|
||||
}
|
||||
#endif
|
||||
// for(i = 0; i < size*2*bps;i++){
|
||||
// fprintf(stderr,"%x ",capture_buf[i]);
|
||||
// if(i%4 == 0)
|
||||
// fprintf(stderr,"\n");
|
||||
// }
|
||||
|
||||
//generate_sine(dst_areas, dst_offset,size, &count);
|
||||
src_buf = capture_buf;
|
||||
#if 1
|
||||
while(count < size){
|
||||
for(chn = 0; chn < 4; chn++){
|
||||
for (i = 0; i < bps; i++){
|
||||
src_data[chn][i] = src_buf[i];
|
||||
}
|
||||
src_buf += bps ;
|
||||
}
|
||||
|
||||
for(chn = 0; chn < io->channels; chn++){
|
||||
for (i = 0; i < bps; i++){
|
||||
*(dst_samples[chn] + i) = src_data[chn][i];
|
||||
//fprintf(stderr,"%x ",*(dst_samples[chn] + i));
|
||||
}
|
||||
//fprintf(stderr,"\n");
|
||||
dst_samples[chn] += dst_steps[chn];
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
capture->last_size -= size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* poll-related callbacks - just pass to pcm PCM
|
||||
*/
|
||||
static int ac108_poll_descriptors_count(snd_pcm_ioplug_t *io) {
|
||||
struct ac108_t *capture = io->private_data;
|
||||
|
||||
return snd_pcm_poll_descriptors_count(capture->pcm);
|
||||
}
|
||||
|
||||
static int ac108_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd,
|
||||
unsigned int space) {
|
||||
struct ac108_t *capture = io->private_data;
|
||||
|
||||
return snd_pcm_poll_descriptors(capture->pcm, pfd, space);
|
||||
}
|
||||
|
||||
static int ac108_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd,
|
||||
unsigned int nfds, unsigned short *revents) {
|
||||
struct ac108_t *capture = io->private_data;
|
||||
|
||||
return snd_pcm_poll_descriptors_revents(capture->pcm, pfd, nfds, revents);
|
||||
}
|
||||
|
||||
/*
|
||||
* close callback
|
||||
*/
|
||||
static int ac108_close(snd_pcm_ioplug_t *io) {
|
||||
struct ac108_t *capture = io->private_data;
|
||||
if (capture->pcm)
|
||||
snd_pcm_close(capture->pcm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setSoftwareParams(struct ac108_t *capture) {
|
||||
snd_pcm_sw_params_t *softwareParams;
|
||||
int err;
|
||||
|
||||
snd_pcm_uframes_t bufferSize = 0;
|
||||
snd_pcm_uframes_t periodSize = 0;
|
||||
snd_pcm_uframes_t startThreshold, stopThreshold;
|
||||
snd_pcm_sw_params_alloca(&softwareParams);
|
||||
|
||||
// Get the current software parameters
|
||||
err = snd_pcm_sw_params_current(capture->pcm, softwareParams);
|
||||
if (err < 0) {
|
||||
SNDERR("Unable to get software parameters: %s", snd_strerror(err));
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Configure ALSA to start the transfer when the buffer is almost full.
|
||||
snd_pcm_get_params(capture->pcm, &bufferSize, &periodSize);
|
||||
|
||||
|
||||
startThreshold = 1;
|
||||
stopThreshold = bufferSize;
|
||||
|
||||
|
||||
err = snd_pcm_sw_params_set_start_threshold(capture->pcm, softwareParams,
|
||||
startThreshold);
|
||||
if (err < 0) {
|
||||
SNDERR("Unable to set start threshold to %lu frames: %s",
|
||||
startThreshold, snd_strerror(err));
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = snd_pcm_sw_params_set_stop_threshold(capture->pcm, softwareParams,
|
||||
stopThreshold);
|
||||
if (err < 0) {
|
||||
SNDERR("Unable to set stop threshold to %lu frames: %s",
|
||||
stopThreshold, snd_strerror(err));
|
||||
goto done;
|
||||
}
|
||||
// Allow the transfer to start when at least periodSize samples can be
|
||||
// processed.
|
||||
err = snd_pcm_sw_params_set_avail_min(capture->pcm, softwareParams,
|
||||
periodSize);
|
||||
if (err < 0) {
|
||||
SNDERR("Unable to configure available minimum to %lu: %s",
|
||||
periodSize, snd_strerror(err));
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Commit the software parameters back to the device.
|
||||
err = snd_pcm_sw_params(capture->pcm, softwareParams);
|
||||
if (err < 0)
|
||||
SNDERR("Unable to configure software parameters: %s",snd_strerror(err));
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
done:
|
||||
snd_pcm_sw_params_free(softwareParams);
|
||||
|
||||
return err;
|
||||
}
|
||||
/*
|
||||
* hw_params callback
|
||||
*
|
||||
* Set up pcm PCM according to the current parameters
|
||||
*/
|
||||
static int ac108_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) {
|
||||
struct ac108_t *capture = io->private_data;
|
||||
snd_pcm_uframes_t period_size;
|
||||
snd_pcm_uframes_t buffer_size;
|
||||
int err;
|
||||
if (!capture->hw_params) {
|
||||
err = ac108_slave_hw_params_half(capture, 2*io->rate,io->format);
|
||||
if (err < 0) {
|
||||
SNDERR("ac108_slave_hw_params_half error\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
period_size = io->period_size;
|
||||
if ((err = snd_pcm_hw_params_set_period_size_near(capture->pcm, capture->hw_params,
|
||||
&period_size, NULL)) < 0) {
|
||||
SNDERR("Cannot set pcm period size %ld", period_size);
|
||||
return err;
|
||||
}
|
||||
buffer_size = io->buffer_size;
|
||||
if ((err = snd_pcm_hw_params_set_buffer_size_near(capture->pcm, capture->hw_params,
|
||||
&buffer_size)) < 0) {
|
||||
SNDERR("Cannot set pcm buffer size %ld", buffer_size);
|
||||
return err;
|
||||
}
|
||||
if ((err = snd_pcm_hw_params(capture->pcm, capture->hw_params)) < 0) {
|
||||
SNDERR("Cannot set pcm hw_params");
|
||||
return err;
|
||||
}
|
||||
setSoftwareParams(capture);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* hw_free callback
|
||||
*/
|
||||
static int ac108_hw_free(snd_pcm_ioplug_t *io) {
|
||||
struct ac108_t *capture = io->private_data;
|
||||
free(capture->hw_params);
|
||||
capture->hw_params = NULL;
|
||||
|
||||
return snd_pcm_hw_free(capture->pcm);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int ac108_prepare(snd_pcm_ioplug_t *io) {
|
||||
struct ac108_t *capture = io->private_data;
|
||||
capture->ptr = 0;
|
||||
capture->last_size =0;
|
||||
return snd_pcm_prepare(capture->pcm);
|
||||
}
|
||||
static int ac108_drain(snd_pcm_ioplug_t *io) {
|
||||
struct ac108_t *capture = io->private_data;
|
||||
|
||||
return snd_pcm_drain(capture->pcm);
|
||||
}
|
||||
#if 0
|
||||
static int ac108_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
static int ac108_delay(snd_pcm_ioplug_t * io, snd_pcm_sframes_t * delayp){
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* callback table
|
||||
*/
|
||||
static snd_pcm_ioplug_callback_t a108_ops = {
|
||||
.start = ac108_start,
|
||||
.stop = ac108_stop,
|
||||
.pointer = ac108_pointer,
|
||||
.transfer = ac108_transfer,
|
||||
.poll_descriptors_count = ac108_poll_descriptors_count,
|
||||
.poll_descriptors = ac108_poll_descriptors,
|
||||
.poll_revents = ac108_poll_revents,
|
||||
.close = ac108_close,
|
||||
.hw_params = ac108_hw_params,
|
||||
.hw_free = ac108_hw_free,
|
||||
// .sw_params = ac108_sw_params,
|
||||
.prepare = ac108_prepare,
|
||||
.drain = ac108_drain,
|
||||
.delay = ac108_delay,
|
||||
};
|
||||
|
||||
|
||||
static int ac108_set_hw_constraint(struct ac108_t *capture) {
|
||||
static unsigned int accesses[] = {
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED
|
||||
};
|
||||
unsigned int formats[] = { SND_PCM_FORMAT_S32,
|
||||
SND_PCM_FORMAT_S16 };
|
||||
|
||||
unsigned int rates[] = {
|
||||
8000,
|
||||
16000,
|
||||
32000,
|
||||
44100,
|
||||
48000,
|
||||
96000
|
||||
};
|
||||
int err;
|
||||
|
||||
|
||||
err = snd_pcm_ioplug_set_param_list(&capture->io,
|
||||
SND_PCM_IOPLUG_HW_ACCESS,
|
||||
ARRAY_SIZE(accesses),
|
||||
accesses);
|
||||
if (err < 0){
|
||||
SNDERR("ioplug cannot set ac108 hw access");
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_ioplug_set_param_list(&capture->io, SND_PCM_IOPLUG_HW_FORMAT,
|
||||
ARRAY_SIZE(formats), formats)) < 0 ||
|
||||
(err = snd_pcm_ioplug_set_param_minmax(&capture->io, SND_PCM_IOPLUG_HW_CHANNELS,
|
||||
1, 4)) < 0 ||
|
||||
(err = snd_pcm_ioplug_set_param_list(&capture->io, SND_PCM_IOPLUG_HW_RATE,
|
||||
ARRAY_SIZE(rates), rates)) < 0)
|
||||
{
|
||||
SNDERR("ioplug cannot set ac108 format channel rate!");
|
||||
return err;
|
||||
}
|
||||
err = snd_pcm_ioplug_set_param_minmax(&capture->io,SND_PCM_IOPLUG_HW_BUFFER_BYTES,
|
||||
1, 4 * 1024 * 1024);
|
||||
if (err < 0){
|
||||
SNDERR("ioplug cannot set ac108 hw buffer bytes");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = snd_pcm_ioplug_set_param_minmax(&capture->io,SND_PCM_IOPLUG_HW_PERIOD_BYTES,
|
||||
128, 2 * 1024 * 1024);
|
||||
if (err < 0) {
|
||||
SNDERR("ioplug cannot set ac108 hw period bytes");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = snd_pcm_ioplug_set_param_minmax(&capture->io, SND_PCM_IOPLUG_HW_PERIODS,3, 1024);
|
||||
if (err < 0) {
|
||||
SNDERR("ioplug cannot set ac108 hw periods");
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main entry point
|
||||
*/
|
||||
SND_PCM_PLUGIN_DEFINE_FUNC(ac108) {
|
||||
snd_config_iterator_t i, next;
|
||||
int err;
|
||||
const char *pcm_string = NULL;
|
||||
struct ac108_t *capture;
|
||||
int channels;
|
||||
if (stream != SND_PCM_STREAM_CAPTURE) {
|
||||
SNDERR("a108 is only for capture");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_config_for_each(i, next, conf) {
|
||||
snd_config_t *n = snd_config_iterator_entry(i);
|
||||
const char *id;
|
||||
if (snd_config_get_id(n, &id) < 0) continue;
|
||||
if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0) continue;
|
||||
|
||||
if (strcmp(id, "slavepcm") == 0) {
|
||||
if (snd_config_get_string(n, &pcm_string) < 0) {
|
||||
SNDERR("ac108 slavepcm must be a string");
|
||||
return -EINVAL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(id, "channels") == 0) {
|
||||
long val;
|
||||
if (snd_config_get_integer(n, &val) < 0) {
|
||||
SNDERR("Invalid type for %s", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
channels = val;
|
||||
if (channels != 2 && channels != 4 && channels != 6) {
|
||||
SNDERR("channels must be 2, 4 or 6");
|
||||
return -EINVAL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
capture = calloc(1, sizeof(*capture));
|
||||
if (!capture) {
|
||||
SNDERR("cannot allocate");
|
||||
return -ENOMEM;
|
||||
}
|
||||
err = snd_pcm_open(&capture->pcm, pcm_string, stream, mode);
|
||||
if (err < 0) goto error;
|
||||
|
||||
|
||||
|
||||
//SND_PCM_NONBLOCK
|
||||
capture->io.version = SND_PCM_IOPLUG_VERSION;
|
||||
capture->io.name = "AC108 decode Plugin";
|
||||
capture->io.mmap_rw = 0;
|
||||
capture->io.callback = &a108_ops;
|
||||
capture->io.private_data = capture;
|
||||
|
||||
err = snd_pcm_ioplug_create(&capture->io, name, stream, mode);
|
||||
if (err < 0) goto error;
|
||||
|
||||
if ((err = ac108_set_hw_constraint(capture)) < 0) {
|
||||
snd_pcm_ioplug_delete(&capture->io);
|
||||
return err;
|
||||
}
|
||||
*pcmp = capture->io.pcm;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (capture->pcm) snd_pcm_close(capture->pcm);
|
||||
free(capture);
|
||||
return err;
|
||||
}
|
||||
|
||||
SND_PCM_PLUGIN_SYMBOL(ac108);
|
126
ac10x.h
Normal file
126
ac10x.h
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* ac10x.h
|
||||
*
|
||||
* (C) Copyright 2017-2018
|
||||
* Seeed Technology Co., Ltd. <www.seeedstudio.com>
|
||||
*
|
||||
* PeterYang <linsheng.yang@seeed.cc>
|
||||
*
|
||||
* (C) Copyright 2010-2017
|
||||
* Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
|
||||
* huangxin <huangxin@reuuimllatech.com>
|
||||
*
|
||||
* some simple description for this code
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
#ifndef __AC10X_H__
|
||||
#define __AC10X_H__
|
||||
|
||||
#define AC101_I2C_ID 4
|
||||
#define _MASTER_AC108 0
|
||||
#define _MASTER_AC101 1
|
||||
#define _MASTER_MULTI_CODEC _MASTER_AC101
|
||||
|
||||
/* enable headset detecting & headset button pressing */
|
||||
#define CONFIG_AC101_SWITCH_DETECT
|
||||
|
||||
/* obsolete */
|
||||
#define CONFIG_AC10X_TRIG_LOCK 0
|
||||
|
||||
|
||||
#ifdef AC101_DEBG
|
||||
#define AC101_DBG(format,args...) printk("[AC101] %s() L%d " format, __func__, __LINE__, ##args)
|
||||
#else
|
||||
#define AC101_DBG(...)
|
||||
#endif
|
||||
|
||||
|
||||
#include "sound-compatible-4.18.h"
|
||||
|
||||
#ifdef CONFIG_AC101_SWITCH_DETECT
|
||||
enum headphone_mode_u {
|
||||
HEADPHONE_IDLE,
|
||||
FOUR_HEADPHONE_PLUGIN,
|
||||
THREE_HEADPHONE_PLUGIN,
|
||||
};
|
||||
#endif
|
||||
|
||||
struct ac10x_priv {
|
||||
struct i2c_client *i2c[4];
|
||||
struct regmap* i2cmap[4];
|
||||
int codec_cnt;
|
||||
unsigned sysclk;
|
||||
#define _FREQ_24_576K 24576000
|
||||
#define _FREQ_22_579K 22579200
|
||||
unsigned mclk; /* master clock or aif_clock/aclk */
|
||||
int clk_id;
|
||||
unsigned char i2s_mode;
|
||||
unsigned char data_protocol;
|
||||
struct delayed_work dlywork;
|
||||
int tdm_chips_cnt;
|
||||
int sysclk_en;
|
||||
|
||||
/* member for ac101 .begin */
|
||||
struct snd_soc_codec *codec;
|
||||
struct i2c_client *i2c101;
|
||||
struct regmap* regmap101;
|
||||
|
||||
struct mutex dac_mutex;
|
||||
u8 dac_enable;
|
||||
spinlock_t lock;
|
||||
u8 aif1_clken;
|
||||
|
||||
struct work_struct codec_resume;
|
||||
struct gpio_desc* gpiod_spk_amp_gate;
|
||||
|
||||
#ifdef CONFIG_AC101_SWITCH_DETECT
|
||||
struct gpio_desc* gpiod_irq;
|
||||
long irq;
|
||||
volatile int irq_cntr;
|
||||
volatile int pullout_cntr;
|
||||
volatile int state;
|
||||
|
||||
enum headphone_mode_u mode;
|
||||
struct work_struct work_switch;
|
||||
struct work_struct work_clear_irq;
|
||||
|
||||
struct input_dev* inpdev;
|
||||
#endif
|
||||
/* member for ac101 .end */
|
||||
};
|
||||
|
||||
|
||||
/* AC101 DAI operations */
|
||||
int ac101_audio_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai);
|
||||
void ac101_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai);
|
||||
int ac101_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt);
|
||||
int ac101_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *codec_dai);
|
||||
int ac101_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai);
|
||||
int ac101_aif_mute(struct snd_soc_dai *codec_dai, int mute);
|
||||
|
||||
/* codec driver specific */
|
||||
int ac101_codec_probe(struct snd_soc_codec *codec);
|
||||
int ac101_codec_remove(struct snd_soc_codec *codec);
|
||||
int ac101_codec_suspend(struct snd_soc_codec *codec);
|
||||
int ac101_codec_resume(struct snd_soc_codec *codec);
|
||||
int ac101_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level);
|
||||
|
||||
/* i2c device specific */
|
||||
int ac101_probe(struct i2c_client *i2c, const struct i2c_device_id *id);
|
||||
void ac101_shutdown(struct i2c_client *i2c);
|
||||
int ac101_remove(struct i2c_client *i2c);
|
||||
|
||||
/* seeed voice card export */
|
||||
int seeed_voice_card_register_set_clock(int stream, int (*set_clock)(int, struct snd_pcm_substream *, int, struct snd_soc_dai *));
|
||||
|
||||
int ac10x_fill_regcache(struct device* dev, struct regmap* map);
|
||||
|
||||
#endif//__AC10X_H__
|
|
@ -1,6 +1,10 @@
|
|||
# The IPC key of dmix or dsnoop plugin must be unique
|
||||
# If 555555 or 666666 is used by other processes, use another one
|
||||
|
||||
|
||||
# use samplerate to resample as speexdsp resample is bad
|
||||
defaults.pcm.rate_converter "samplerate"
|
||||
|
||||
pcm.!default {
|
||||
type asym
|
||||
playback.pcm "playback"
|
||||
|
@ -19,14 +23,14 @@ pcm.capture {
|
|||
|
||||
pcm.dmixed {
|
||||
type dmix
|
||||
slave.pcm "hw:0,0"
|
||||
slave.pcm "hw:seeed2micvoicec"
|
||||
ipc_key 555555
|
||||
}
|
||||
|
||||
pcm.array {
|
||||
type dsnoop
|
||||
slave {
|
||||
pcm "hw:0,0"
|
||||
pcm "hw:seeed2micvoicec"
|
||||
channels 2
|
||||
}
|
||||
ipc_key 666666
|
33
asound_4mic.conf
Normal file
33
asound_4mic.conf
Normal file
|
@ -0,0 +1,33 @@
|
|||
# The IPC key of dmix or dsnoop plugin must be unique
|
||||
# If 555555 or 666666 is used by other processes, use another one
|
||||
|
||||
# use samplerate to resample as speexdsp resample is bad
|
||||
defaults.pcm.rate_converter "samplerate"
|
||||
|
||||
pcm.!default {
|
||||
type asym
|
||||
playback.pcm "playback"
|
||||
capture.pcm "ac108"
|
||||
}
|
||||
|
||||
pcm.playback {
|
||||
type plug
|
||||
slave.pcm "hw:ALSA"
|
||||
}
|
||||
|
||||
# pcm.dmixed {
|
||||
# type dmix
|
||||
# slave.pcm "hw:0,0"
|
||||
# ipc_key 555555
|
||||
# }
|
||||
|
||||
pcm.ac108 {
|
||||
type plug
|
||||
slave.pcm "hw:seeed4micvoicec"
|
||||
}
|
||||
|
||||
# pcm.multiapps {
|
||||
# type dsnoop
|
||||
# ac108-slavepcm "hw:1,0"
|
||||
# ipc_key 666666
|
||||
# }
|
90
asound_6mic.conf
Normal file
90
asound_6mic.conf
Normal file
|
@ -0,0 +1,90 @@
|
|||
# The IPC key of dmix or dsnoop plugin must be unique
|
||||
# If 555555 or 666666 is used by other processes, use another one
|
||||
|
||||
# use samplerate to resample as speexdsp resample is broken
|
||||
defaults.pcm.rate_converter "samplerate"
|
||||
|
||||
pcm.!default {
|
||||
type asym
|
||||
playback.pcm "dmixer"
|
||||
capture.pcm "ac108"
|
||||
}
|
||||
|
||||
|
||||
pcm.ac108 {
|
||||
type plug
|
||||
slave {
|
||||
rate 48000
|
||||
format S32_LE
|
||||
pcm "hw:seeed8micvoicec"
|
||||
}
|
||||
}
|
||||
|
||||
# pcm.multiapps {
|
||||
# type plug
|
||||
# slave.pcm {
|
||||
# type dsnoop
|
||||
# slave {
|
||||
# rate 48000
|
||||
# format S32_LE
|
||||
# pcm "hw:seeed8micvoicec"
|
||||
# }
|
||||
# ipc_key 666666
|
||||
# }
|
||||
# }
|
||||
|
||||
pcm.dmixer {
|
||||
type plug
|
||||
slave {
|
||||
pcm {
|
||||
type dmix
|
||||
ipc_key 555555
|
||||
slave {
|
||||
pcm "hw:seeed8micvoicec"
|
||||
format S32_LE
|
||||
channels 8
|
||||
}
|
||||
bindings {
|
||||
0 0
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
4 4
|
||||
5 5
|
||||
6 6
|
||||
7 7
|
||||
}
|
||||
}
|
||||
channels 8
|
||||
format S32_LE
|
||||
rate 48000
|
||||
}
|
||||
ttable.0.0 1
|
||||
ttable.1.1 1
|
||||
ttable.0.2 1
|
||||
ttable.1.3 1
|
||||
ttable.0.4 1
|
||||
ttable.1.5 1
|
||||
ttable.0.6 1
|
||||
ttable.1.7 1
|
||||
}
|
||||
|
||||
pcm.ac101 {
|
||||
type plug
|
||||
slave {
|
||||
pcm "hw:seeed8micvoicec"
|
||||
channels 8
|
||||
format S32_LE
|
||||
rate 48000
|
||||
}
|
||||
ttable.0.0 1
|
||||
ttable.1.1 1
|
||||
ttable.0.2 1
|
||||
ttable.1.3 1
|
||||
ttable.0.4 1
|
||||
ttable.1.5 1
|
||||
ttable.0.6 1
|
||||
ttable.1.7 1
|
||||
}
|
||||
|
||||
|
14
builddtbo.sh
14
builddtbo.sh
|
@ -1,4 +1,10 @@
|
|||
dtoverlay -r seeed-voicecard
|
||||
dtc -@ -I dts -O dtb -o seeed-voicecard.dtbo seeed-voicecard-overlay.dts
|
||||
cp seeed-voicecard.dtbo /boot/overlays
|
||||
dtoverlay seeed-voicecard
|
||||
#!/bin/sh
|
||||
#dtoverlay -r seeed-2mic-voicecard
|
||||
DTC_FLAGS="-b 0 -Wno-unit_address_vs_reg -I dts -O dtb"
|
||||
|
||||
dtc -@ $DTC_FLAGS -o seeed-2mic-voicecard.dtbo seeed-2mic-voicecard-overlay.dts
|
||||
dtc -@ $DTC_FLAGS -o seeed-4mic-voicecard.dtbo seeed-4mic-voicecard-overlay.dts
|
||||
dtc -@ $DTC_FLAGS -o seeed-8mic-voicecard.dtbo seeed-8mic-voicecard-overlay.dts
|
||||
|
||||
# cp *.dtbo /boot/overlays
|
||||
# dtoverlay seeed-2mic-voicecard
|
||||
|
|
14
dkms.conf
14
dkms.conf
|
@ -1,5 +1,15 @@
|
|||
PACKAGE_NAME="seeed-voicecard"
|
||||
PACKAGE_VERSION="0.1"
|
||||
BUILT_MODULE_NAME[0]="wm8960"
|
||||
PACKAGE_VERSION="0.3"
|
||||
BUILT_MODULE_NAME[0]="snd-soc-wm8960"
|
||||
BUILT_MODULE_NAME[1]="snd-soc-ac108"
|
||||
BUILT_MODULE_NAME[2]="snd-soc-seeed-voicecard"
|
||||
DEST_MODULE_LOCATION[0]="/kernel/sound/soc/codecs"
|
||||
DEST_MODULE_LOCATION[1]="/kernel/sound/soc/codecs"
|
||||
DEST_MODULE_LOCATION[2]="/kernel/sound/soc/bcm"
|
||||
PATCH[0]="back-to-v4.19.diff"
|
||||
PATCH[1]="back-to-v5.4.diff"
|
||||
PATCH[2]="back-to-v5.8.diff"
|
||||
PATCH_MATCH[0]="^4\.19\.*"
|
||||
PATCH_MATCH[1]="^5\.4\.*"
|
||||
PATCH_MATCH[2]="^5\.8\.*"
|
||||
AUTOINSTALL="yes"
|
||||
|
|
200
install.sh
200
install.sh
|
@ -5,22 +5,134 @@ if [[ $EUID -ne 0 ]]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# Check for enough space on /boot volume
|
||||
boot_line=$(df -h | grep /boot | head -n 1)
|
||||
if [ "x${boot_line}" = "x" ]; then
|
||||
echo "Warning: /boot volume not found .."
|
||||
else
|
||||
boot_space=$(echo $boot_line | awk '{print $4;}')
|
||||
free_space=$(echo "${boot_space%?}")
|
||||
unit="${boot_space: -1}"
|
||||
if [[ "$unit" = "K" ]]; then
|
||||
echo "Error: Not enough space left ($boot_space) on /boot"
|
||||
exit 1
|
||||
elif [[ "$unit" = "M" ]]; then
|
||||
if [ "$free_space" -lt "25" ]; then
|
||||
echo "Error: Not enough space left ($boot_space) on /boot"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
ver="0.1"
|
||||
#
|
||||
# make sure that we are on something ARM/Raspberry related
|
||||
# either a bare metal Raspberry or a qemu session with
|
||||
# Raspberry stuff available
|
||||
# - check for /boot/overlays
|
||||
# - dtparam and dtoverlay is available
|
||||
errorFound=0
|
||||
OVERLAYS=/boot/overlays
|
||||
[ -d /boot/firmware/overlays ] && OVERLAYS=/boot/firmware/overlays
|
||||
|
||||
if [ ! -d $OVERLAYS ] ; then
|
||||
echo "$OVERLAYS not found or not a directory" 1>&2
|
||||
errorFound=1
|
||||
fi
|
||||
# should we also check for alsactl and amixer used in seeed-voicecard?
|
||||
PATH=$PATH:/opt/vc/bin
|
||||
for cmd in dtparam dtoverlay ; do
|
||||
if ! which $cmd &>/dev/null ; then
|
||||
echo "$cmd not found" 1>&2
|
||||
echo "You may need to run ./ubuntu-prerequisite.sh"
|
||||
errorFound=1
|
||||
fi
|
||||
done
|
||||
if [ $errorFound = 1 ] ; then
|
||||
echo "Errors found, exiting." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ver="0.3"
|
||||
uname_r=$(uname -r)
|
||||
|
||||
# we create a dir with this version to ensure that 'dkms remove' won't delete
|
||||
# the sources during kernel updates
|
||||
marker="0.0.0"
|
||||
|
||||
apt update
|
||||
apt-get -y install raspberrypi-kernel-headers raspberrypi-kernel
|
||||
apt-get -y install dkms
|
||||
_VER_RUN=
|
||||
function get_kernel_version() {
|
||||
local ZIMAGE IMG_OFFSET
|
||||
|
||||
_VER_RUN=""
|
||||
[ -z "$_VER_RUN" ] && {
|
||||
ZIMAGE=/boot/kernel.img
|
||||
[ -f /boot/firmware/vmlinuz ] && ZIMAGE=/boot/firmware/vmlinuz
|
||||
# 64-bit-only kernel package
|
||||
[ ! -f /boot/kernel.img ] && [ -f /boot/kernel8.img ] && ZIMAGE=/boot/kernel8.img
|
||||
IMG_OFFSET=$(LC_ALL=C grep -abo $'\x1f\x8b\x08\x00' $ZIMAGE | head -n 1 | cut -d ':' -f 1)
|
||||
_VER_RUN=$(dd if=$ZIMAGE obs=64K ibs=4 skip=$(( IMG_OFFSET / 4)) 2>/dev/null | zcat | grep -a -m1 "Linux version" | LC_ALL=C sed -e 's/^.*Linux/Linux/' | strings | awk '{ print $3; }')
|
||||
}
|
||||
echo "$_VER_RUN"
|
||||
return 0
|
||||
}
|
||||
|
||||
function check_kernel_headers() {
|
||||
VER_RUN=$(get_kernel_version)
|
||||
VER_HDR=$(dpkg -L raspberrypi-kernel-headers | egrep -m1 "/lib/modules/[^\/]+/build" | awk -F'/' '{ print $4; }')
|
||||
[ "X$VER_RUN" == "X$VER_HDR" ] && {
|
||||
return 0
|
||||
}
|
||||
VER_HDR=$(dpkg -L linux-headers-$VER_RUN | egrep -m1 "/lib/modules/[^\/]+/build" | awk -F'/' '{ print $4; }')
|
||||
[ "X$VER_RUN" == "X$VER_HDR" ] && {
|
||||
return 0
|
||||
}
|
||||
|
||||
# echo RUN=$VER_RUN HDR=$VER_HDR
|
||||
echo " !!! Your kernel version is $VER_RUN"
|
||||
echo " Not found *** corresponding *** kernel headers with apt-get."
|
||||
echo " This may occur if you have ran 'rpi-update'."
|
||||
echo " Choose *** y *** will revert the kernel to version $VER_HDR then continue."
|
||||
echo " Choose *** N *** will exit without this driver support, by default."
|
||||
read -p "Would you like to proceed? (y/N)" -n 1 -r -s
|
||||
echo
|
||||
if ! [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
apt-get -y --reinstall install raspberrypi-kernel
|
||||
}
|
||||
|
||||
# update and install required packages
|
||||
which apt &>/dev/null
|
||||
if [[ $? -eq 0 ]]; then
|
||||
apt update -y
|
||||
# Raspbian kernel packages
|
||||
apt-get -y install raspberrypi-kernel-headers raspberrypi-kernel
|
||||
# Recent Raspbian has 64-bit kernel on 32-bit userspace
|
||||
apt-get -y install gcc-aarch64-linux-gnu
|
||||
# Ubuntu kernel packages
|
||||
apt-get -y install linux-raspi linux-headers-raspi linux-image-raspi
|
||||
apt-get -y install dkms git i2c-tools libasound2-plugins
|
||||
# rpi-update checker
|
||||
check_kernel_headers
|
||||
fi
|
||||
|
||||
# Arch Linux
|
||||
which pacman &>/dev/null
|
||||
if [[ $? -eq 0 ]]; then
|
||||
pacman -Syu --needed git gcc automake make dkms linux-raspberrypi-headers i2c-tools
|
||||
fi
|
||||
|
||||
# locate currently installed kernels (may be different to running kernel if
|
||||
# it's just been updated)
|
||||
kernels=$(ls /lib/modules | sed "s/^/-k /")
|
||||
base_ver=$(get_kernel_version)
|
||||
base_ver=${base_ver%%[-+]*}
|
||||
#kernels="${base_ver}+ ${base_ver}-v7+ ${base_ver}-v7l+"
|
||||
kernels=$(uname -r)
|
||||
|
||||
function install_module {
|
||||
local _i
|
||||
|
||||
src=$1
|
||||
mod=$2
|
||||
|
||||
|
@ -29,13 +141,19 @@ function install_module {
|
|||
fi
|
||||
|
||||
if [[ -e /usr/src/$mod-$ver || -e /var/lib/dkms/$mod/$ver ]]; then
|
||||
dkms remove -m $mod -v $ver --all
|
||||
dkms remove --force -m $mod -v $ver --all
|
||||
rm -rf /usr/src/$mod-$ver
|
||||
fi
|
||||
|
||||
mkdir -p /usr/src/$mod-$ver
|
||||
cp -a $src/* /usr/src/$mod-$ver/
|
||||
|
||||
dkms add -m $mod -v $ver
|
||||
dkms build $kernels -m $mod -v $ver && dkms install $kernels -m $mod -v $ver
|
||||
for _i in $kernels; do
|
||||
dkms build -k $_i -m $mod -v $ver && {
|
||||
dkms install --force -k $_i -m $mod -v $ver
|
||||
}
|
||||
done
|
||||
|
||||
mkdir -p /var/lib/dkms/$mod/$ver/$marker
|
||||
}
|
||||
|
@ -43,23 +161,61 @@ function install_module {
|
|||
install_module "./" "seeed-voicecard"
|
||||
|
||||
|
||||
(
|
||||
cp seeed-voicecard.dtbo /boot/overlays
|
||||
cp asound.state /var/lib/alsa/asound.state
|
||||
)
|
||||
# install dtbos
|
||||
cp seeed-2mic-voicecard.dtbo $OVERLAYS
|
||||
cp seeed-4mic-voicecard.dtbo $OVERLAYS
|
||||
cp seeed-8mic-voicecard.dtbo $OVERLAYS
|
||||
|
||||
echo 'wm8960' | sudo tee --append /etc/modules > /dev/null
|
||||
#install alsa plugins
|
||||
# no need this plugin now
|
||||
# install -D ac108_plugin/libasound_module_pcm_ac108.so /usr/lib/arm-linux-gnueabihf/alsa-lib/
|
||||
rm -f /usr/lib/arm-linux-gnueabihf/alsa-lib/libasound_module_pcm_ac108.so
|
||||
|
||||
sed -i \
|
||||
-e "s/^dtparam=audio=on/#\0/" \
|
||||
-e "s/^#\(dtparam=i2s=on\)/\1/" \
|
||||
/boot/config.txt
|
||||
grep -q "dtoverlay=i2s-mmap" /boot/config.txt || \
|
||||
echo "dtoverlay=i2s-mmap" >> /boot/config.txt
|
||||
grep -q "dtoverlay=seeed-voicecard" /boot/config.txt || \
|
||||
echo "dtoverlay=seeed-voicecard" >> /boot/config.txt
|
||||
grep -q "dtparam=i2s=on" /boot/config.txt || \
|
||||
echo "dtparam=i2s=on" >> /boot/config.txt
|
||||
#set kernel modules
|
||||
grep -q "^snd-soc-seeed-voicecard$" /etc/modules || \
|
||||
echo "snd-soc-seeed-voicecard" >> /etc/modules
|
||||
grep -q "^snd-soc-ac108$" /etc/modules || \
|
||||
echo "snd-soc-ac108" >> /etc/modules
|
||||
grep -q "^snd-soc-wm8960$" /etc/modules || \
|
||||
echo "snd-soc-wm8960" >> /etc/modules
|
||||
|
||||
#set dtoverlays
|
||||
CONFIG=/boot/config.txt
|
||||
[ -f /boot/firmware/config.txt ] && CONFIG=/boot/firmware/config.txt
|
||||
[ -f /boot/firmware/usercfg.txt ] && CONFIG=/boot/firmware/usercfg.txt
|
||||
|
||||
sed -i -e 's:#dtparam=i2c_arm=on:dtparam=i2c_arm=on:g' $CONFIG || true
|
||||
grep -q "^dtoverlay=i2s-mmap$" $CONFIG || \
|
||||
echo "dtoverlay=i2s-mmap" >> $CONFIG
|
||||
|
||||
|
||||
grep -q "^dtparam=i2s=on$" $CONFIG || \
|
||||
echo "dtparam=i2s=on" >> $CONFIG
|
||||
|
||||
#install config files
|
||||
mkdir /etc/voicecard || true
|
||||
cp *.conf /etc/voicecard
|
||||
cp *.state /etc/voicecard
|
||||
|
||||
#create git repo
|
||||
git_email=$(git config --global --get user.email)
|
||||
git_name=$(git config --global --get user.name)
|
||||
if [ "x${git_email}" == "x" ] || [ "x${git_name}" == "x" ] ; then
|
||||
echo "setup git config"
|
||||
git config --global user.email "respeaker@seeed.cc"
|
||||
git config --global user.name "respeaker"
|
||||
fi
|
||||
echo "git init"
|
||||
git --git-dir=/etc/voicecard/.git init
|
||||
echo "git add --all"
|
||||
git --git-dir=/etc/voicecard/.git --work-tree=/etc/voicecard/ add --all
|
||||
echo "git commit -m \"origin configures\""
|
||||
git --git-dir=/etc/voicecard/.git --work-tree=/etc/voicecard/ commit -m "origin configures"
|
||||
|
||||
cp seeed-voicecard /usr/bin/
|
||||
cp seeed-voicecard.service /lib/systemd/system/
|
||||
systemctl enable seeed-voicecard.service
|
||||
systemctl start seeed-voicecard
|
||||
|
||||
echo "------------------------------------------------------"
|
||||
echo "Please reboot your raspberry pi to apply all settings"
|
||||
|
|
454
patches/back-to-v4.19.diff
Normal file
454
patches/back-to-v4.19.diff
Normal file
|
@ -0,0 +1,454 @@
|
|||
diff --git a/ac101.c b/ac101.c
|
||||
index 23837a7..41c15f3 100644
|
||||
--- a/ac101.c
|
||||
+++ b/ac101.c
|
||||
@@ -955,10 +955,10 @@ void ac101_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai
|
||||
|
||||
AC101_DBG("stream = %s, play: %d, capt: %d, active: %d\n",
|
||||
snd_pcm_stream_str(substream),
|
||||
- codec_dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], codec_dai->stream_active[SNDRV_PCM_STREAM_CAPTURE],
|
||||
- snd_soc_dai_active(codec_dai));
|
||||
+ codec_dai->playback_active, codec_dai->capture_active,
|
||||
+ codec_dai->active);
|
||||
|
||||
- if (!snd_soc_dai_active(codec_dai)) {
|
||||
+ if (!codec_dai->active) {
|
||||
ac10x->aif1_clken = 1;
|
||||
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
|
||||
} else {
|
||||
@@ -1080,7 +1080,7 @@ int ac101_hw_params(struct snd_pcm_substream *substream,
|
||||
freq_out = _FREQ_24_576K;
|
||||
for (i = 0; i < ARRAY_SIZE(codec_aif1_fs); i++) {
|
||||
if (codec_aif1_fs[i].samp_rate == params_rate(params)) {
|
||||
- if (codec_dai->stream_active[SNDRV_PCM_STREAM_CAPTURE] && dmic_used && codec_aif1_fs[i].samp_rate == 44100) {
|
||||
+ if (codec_dai->capture_active && dmic_used && codec_aif1_fs[i].samp_rate == 44100) {
|
||||
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), (0x4<<AIF1_FS));
|
||||
} else {
|
||||
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), ((codec_aif1_fs[i].srbit)<<AIF1_FS));
|
||||
diff --git a/ac108.c b/ac108.c
|
||||
index d5dd12d..0a8c462 100644
|
||||
--- a/ac108.c
|
||||
+++ b/ac108.c
|
||||
@@ -653,7 +653,7 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||
|
||||
dev_dbg(dai->dev, "%s() stream=%s play:%d capt:%d +++\n", __func__,
|
||||
snd_pcm_stream_str(substream),
|
||||
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE]);
|
||||
+ dai->playback_active, dai->capture_active);
|
||||
|
||||
if (ac10x->i2c101) {
|
||||
ret = ac101_hw_params(substream, params, dai);
|
||||
@@ -664,8 +664,8 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||
}
|
||||
}
|
||||
|
||||
- if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK])
|
||||
- || (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->stream_active[SNDRV_PCM_STREAM_CAPTURE])) {
|
||||
+ if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->playback_active)
|
||||
+ || (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->capture_active)) {
|
||||
/* not configure hw_param twice */
|
||||
/* return 0; */
|
||||
}
|
||||
@@ -810,9 +810,6 @@ static int ac108_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int fr
|
||||
|
||||
struct ac10x_priv *ac10x = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
- if (freq != 24000000 || clk_id != SYSCLK_SRC_PLL)
|
||||
- dev_warn(dai->dev, "ac108_set_sysclk freq = %d clk = %d\n", freq, clk_id);
|
||||
-
|
||||
freq = 24000000;
|
||||
clk_id = SYSCLK_SRC_PLL;
|
||||
|
||||
@@ -1124,7 +1121,7 @@ void ac108_aif_shutdown(struct snd_pcm_substream *substream,
|
||||
}
|
||||
}
|
||||
|
||||
-int ac108_aif_mute(struct snd_soc_dai *dai, int mute, int direction) {
|
||||
+int ac108_aif_mute(struct snd_soc_dai *dai, int mute) {
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
@@ -1145,13 +1142,12 @@ static const struct snd_soc_dai_ops ac108_dai_ops = {
|
||||
.hw_params = ac108_hw_params,
|
||||
.prepare = ac108_prepare,
|
||||
.trigger = ac108_trigger,
|
||||
- .mute_stream = ac108_aif_mute,
|
||||
+ .digital_mute = ac108_aif_mute,
|
||||
|
||||
/*DAI format configuration*/
|
||||
.set_fmt = ac108_set_fmt,
|
||||
|
||||
// .hw_free = ac108_hw_free,
|
||||
- .no_capture_mute = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ac108_dai0 = {
|
||||
diff --git a/seeed-voicecard.c b/seeed-voicecard.c
|
||||
index b90af93..af6db74 100644
|
||||
--- a/seeed-voicecard.c
|
||||
+++ b/seeed-voicecard.c
|
||||
@@ -28,8 +28,6 @@
|
||||
#include <sound/simple_card_utils.h>
|
||||
#include "ac10x.h"
|
||||
|
||||
-#define LINUX_VERSION_IS_GEQ(x1,x2,x3) (LINUX_VERSION_CODE >= KERNEL_VERSION(x1,x2,x3))
|
||||
-
|
||||
/*
|
||||
* single codec:
|
||||
* 0 - allow multi codec
|
||||
@@ -42,9 +40,6 @@ struct seeed_card_data {
|
||||
struct seeed_dai_props {
|
||||
struct asoc_simple_dai cpu_dai;
|
||||
struct asoc_simple_dai codec_dai;
|
||||
- struct snd_soc_dai_link_component cpus; /* single cpu */
|
||||
- struct snd_soc_dai_link_component codecs; /* single codec */
|
||||
- struct snd_soc_dai_link_component platforms;
|
||||
unsigned int mclk_fs;
|
||||
} *dai_props;
|
||||
unsigned int mclk_fs;
|
||||
@@ -97,16 +92,16 @@ static int seeed_voice_card_startup(struct snd_pcm_substream *substream)
|
||||
if (ret)
|
||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||
|
||||
- if (asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min) {
|
||||
- priv->channels_playback_default = asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min;
|
||||
+ if (rtd->cpu_dai->driver->playback.channels_min) {
|
||||
+ priv->channels_playback_default = rtd->cpu_dai->driver->playback.channels_min;
|
||||
}
|
||||
- if (asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min) {
|
||||
- priv->channels_capture_default = asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min;
|
||||
+ if (rtd->cpu_dai->driver->capture.channels_min) {
|
||||
+ priv->channels_capture_default = rtd->cpu_dai->driver->capture.channels_min;
|
||||
}
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_override;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_override;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_override;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_override;
|
||||
+ rtd->cpu_dai->driver->playback.channels_min = priv->channels_playback_override;
|
||||
+ rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_override;
|
||||
+ rtd->cpu_dai->driver->capture.channels_min = priv->channels_capture_override;
|
||||
+ rtd->cpu_dai->driver->capture.channels_max = priv->channels_capture_override;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -118,10 +113,10 @@ static void seeed_voice_card_shutdown(struct snd_pcm_substream *substream)
|
||||
struct seeed_dai_props *dai_props =
|
||||
seeed_priv_to_props(priv, rtd->num);
|
||||
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_default;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_default;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_default;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_default;
|
||||
+ rtd->cpu_dai->driver->playback.channels_min = priv->channels_playback_default;
|
||||
+ rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_default;
|
||||
+ rtd->cpu_dai->driver->capture.channels_min = priv->channels_capture_default;
|
||||
+ rtd->cpu_dai->driver->capture.channels_max = priv->channels_capture_default;
|
||||
|
||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||
|
||||
@@ -132,8 +127,8 @@ static int seeed_voice_card_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
|
||||
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct seeed_dai_props *dai_props =
|
||||
seeed_priv_to_props(priv, rtd->num);
|
||||
@@ -197,7 +192,7 @@ static void work_cb_codec_clk(struct work_struct *work)
|
||||
static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
|
||||
+ struct snd_soc_dai *dai = rtd->codec_dai;
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
#if CONFIG_AC10X_TRIG_LOCK
|
||||
unsigned long flags;
|
||||
@@ -206,7 +201,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||
|
||||
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d\n",
|
||||
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE]);
|
||||
+ dai->playback_active, dai->capture_active);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
@@ -228,7 +223,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
/* capture channel resync, if overrun */
|
||||
- if (dai->stream_active[SNDRV_PCM_STREAM_CAPTURE] && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
+ if (dai->capture_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -248,7 +243,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||
|
||||
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d;finished %d\n",
|
||||
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE], ret);
|
||||
+ dai->playback_active, dai->capture_active, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -387,8 +382,8 @@ static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd)
|
||||
static int seeed_voice_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
- struct snd_soc_dai *codec = asoc_rtd_to_codec(rtd, 0);
|
||||
- struct snd_soc_dai *cpu = asoc_rtd_to_cpu(rtd, 0);
|
||||
+ struct snd_soc_dai *codec = rtd->codec_dai;
|
||||
+ struct snd_soc_dai *cpu = rtd->cpu_dai;
|
||||
struct seeed_dai_props *dai_props =
|
||||
seeed_priv_to_props(priv, rtd->num);
|
||||
int ret;
|
||||
@@ -453,19 +448,20 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||
goto dai_link_of_err;
|
||||
}
|
||||
|
||||
- ret = asoc_simple_parse_daifmt(dev, node, codec,
|
||||
+ ret = asoc_simple_card_parse_daifmt(dev, node, codec,
|
||||
prefix, &dai_link->dai_fmt);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
|
||||
|
||||
- ret = asoc_simple_parse_cpu(cpu, dai_link, &single_cpu);
|
||||
+ ret = asoc_simple_card_parse_cpu(cpu, dai_link,
|
||||
+ DAI, CELL, &single_cpu);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
#if _SINGLE_CODEC
|
||||
- ret = asoc_simple_parse_codec(codec, dai_link);
|
||||
+ ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
#else
|
||||
@@ -477,7 +473,7 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||
dev_dbg(dev, "dai_link num_codecs = %d\n", dai_link->num_codecs);
|
||||
#endif
|
||||
|
||||
- ret = asoc_simple_parse_platform(plat, dai_link);
|
||||
+ ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
@@ -502,7 +498,7 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
|
||||
ret = asoc_simple_card_parse_clk_cpu(cpu, dai_link, cpu_dai);
|
||||
#else
|
||||
- ret = asoc_simple_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
|
||||
+ ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
|
||||
#endif
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
@@ -510,16 +506,16 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
|
||||
ret = asoc_simple_card_parse_clk_codec(codec, dai_link, codec_dai);
|
||||
#else
|
||||
- ret = asoc_simple_parse_clk_codec(dev, codec, dai_link, codec_dai);
|
||||
+ ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
|
||||
#endif
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
- ret = asoc_simple_set_dailink_name(dev, dai_link,
|
||||
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
|
||||
"%s-%s",
|
||||
- dai_link->cpus->dai_name,
|
||||
+ dai_link->cpu_dai_name,
|
||||
#if _SINGLE_CODEC
|
||||
- dai_link->codecs->dai_name
|
||||
+ dai_link->codec_dai_name
|
||||
#else
|
||||
dai_link->codecs[0].dai_name
|
||||
#endif
|
||||
@@ -533,19 +529,21 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||
dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
|
||||
dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
|
||||
dev_dbg(dev, "\tcpu : %s / %d\n",
|
||||
- dai_link->cpus->dai_name,
|
||||
+ dai_link->cpu_dai_name,
|
||||
dai_props->cpu_dai.sysclk);
|
||||
dev_dbg(dev, "\tcodec : %s / %d\n",
|
||||
#if _SINGLE_CODEC
|
||||
- dai_link->codecs->dai_name,
|
||||
+ dai_link->codec_dai_name,
|
||||
#else
|
||||
dai_link->codecs[0].dai_name,
|
||||
#endif
|
||||
dai_props->codec_dai.sysclk);
|
||||
|
||||
- asoc_simple_canonicalize_cpu(dai_link, single_cpu);
|
||||
+ asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
|
||||
#if _SINGLE_CODEC
|
||||
- asoc_simple_canonicalize_platform(dai_link);
|
||||
+ ret = asoc_simple_card_canonicalize_dailink(dai_link);
|
||||
+ if (ret < 0)
|
||||
+ goto dai_link_of_err;
|
||||
#endif
|
||||
|
||||
dai_link_of_err:
|
||||
@@ -578,7 +576,7 @@ static int seeed_voice_card_parse_aux_devs(struct device_node *node,
|
||||
aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
|
||||
if (!aux_node)
|
||||
return -EINVAL;
|
||||
- priv->snd_card.aux_dev[i].dlc.of_node = aux_node;
|
||||
+ priv->snd_card.aux_dev[i].codec_of_node = aux_node;
|
||||
}
|
||||
|
||||
priv->snd_card.num_aux_devs = n;
|
||||
@@ -638,7 +636,7 @@ static int seeed_voice_card_parse_of(struct device_node *node,
|
||||
goto card_parse_end;
|
||||
}
|
||||
|
||||
- ret = asoc_simple_parse_card_name(&priv->snd_card, PREFIX);
|
||||
+ ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);
|
||||
if (ret < 0)
|
||||
goto card_parse_end;
|
||||
|
||||
@@ -743,7 +741,7 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||
struct seeed_dai_props *dai_props;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
- int num, ret, i;
|
||||
+ int num, ret;
|
||||
|
||||
/* Get the number of DAI links */
|
||||
if (np && of_get_child_by_name(np, PREFIX "dai-link"))
|
||||
@@ -761,25 +759,6 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||
if (!dai_props || !dai_link)
|
||||
return -ENOMEM;
|
||||
|
||||
- /*
|
||||
- * Use snd_soc_dai_link_component instead of legacy style
|
||||
- * It is codec only. but cpu/platform will be supported in the future.
|
||||
- * see
|
||||
- * soc-core.c :: snd_soc_init_multicodec()
|
||||
- *
|
||||
- * "platform" might be removed
|
||||
- * see
|
||||
- * simple-card-utils.c :: asoc_simple_canonicalize_platform()
|
||||
- */
|
||||
- for (i = 0; i < num; i++) {
|
||||
- dai_link[i].cpus = &dai_props[i].cpus;
|
||||
- dai_link[i].num_cpus = 1;
|
||||
- dai_link[i].codecs = &dai_props[i].codecs;
|
||||
- dai_link[i].num_codecs = 1;
|
||||
- dai_link[i].platforms = &dai_props[i].platforms;
|
||||
- dai_link[i].num_platforms = 1;
|
||||
- }
|
||||
-
|
||||
priv->dai_props = dai_props;
|
||||
priv->dai_link = dai_link;
|
||||
|
||||
@@ -798,9 +777,6 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||
}
|
||||
} else {
|
||||
struct seeed_card_info *cinfo;
|
||||
- struct snd_soc_dai_link_component *cpus;
|
||||
- struct snd_soc_dai_link_component *codecs;
|
||||
- struct snd_soc_dai_link_component *platform;
|
||||
|
||||
cinfo = dev->platform_data;
|
||||
if (!cinfo) {
|
||||
@@ -817,19 +793,13 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- cpus = dai_link->cpus;
|
||||
- cpus->dai_name = cinfo->cpu_dai.name;
|
||||
-
|
||||
- codecs = dai_link->codecs;
|
||||
- codecs->name = cinfo->codec;
|
||||
- codecs->dai_name = cinfo->codec_dai.name;
|
||||
-
|
||||
- platform = dai_link->platforms;
|
||||
- platform->name = cinfo->platform;
|
||||
-
|
||||
priv->snd_card.name = (cinfo->card) ? cinfo->card : cinfo->name;
|
||||
dai_link->name = cinfo->name;
|
||||
dai_link->stream_name = cinfo->name;
|
||||
+ dai_link->platform_name = cinfo->platform;
|
||||
+ dai_link->codec_name = cinfo->codec;
|
||||
+ dai_link->cpu_dai_name = cinfo->cpu_dai.name;
|
||||
+ dai_link->codec_dai_name = cinfo->codec_dai.name;
|
||||
dai_link->dai_fmt = cinfo->daifmt;
|
||||
dai_link->init = seeed_voice_card_dai_init;
|
||||
memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
|
||||
@@ -853,7 +823,7 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
|
||||
err:
|
||||
- asoc_simple_clean_reference(&priv->snd_card);
|
||||
+ asoc_simple_card_clean_reference(&priv->snd_card);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -865,7 +835,7 @@ static int seeed_voice_card_remove(struct platform_device *pdev)
|
||||
|
||||
if (cancel_work_sync(&priv->work_codec_clk) != 0) {
|
||||
}
|
||||
- return asoc_simple_clean_reference(card);
|
||||
+ return asoc_simple_card_clean_reference(card);
|
||||
}
|
||||
|
||||
static const struct of_device_id seeed_voice_of_match[] = {
|
||||
diff --git a/sound-compatible-4.18.h b/sound-compatible-4.18.h
|
||||
index 550b3a7..6c1a014 100644
|
||||
--- a/sound-compatible-4.18.h
|
||||
+++ b/sound-compatible-4.18.h
|
||||
@@ -16,6 +16,10 @@
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
|
||||
+#ifndef __has_attribute
|
||||
+# define __has_attribute(x) __GCC4_has_attribute_##x
|
||||
+# define __GCC4_has_attribute___fallthrough__ 0
|
||||
+#endif
|
||||
#if __has_attribute(__fallthrough__)
|
||||
# define fallthrough __attribute__((__fallthrough__))
|
||||
#else
|
||||
@@ -31,11 +35,7 @@
|
||||
#define snd_soc_codec_get_dapm snd_soc_component_get_dapm
|
||||
#define snd_soc_codec_get_bias_level snd_soc_component_get_bias_level
|
||||
#define snd_soc_kcontrol_codec snd_soc_kcontrol_component
|
||||
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
|
||||
-#define snd_soc_read snd_soc_component_read
|
||||
-#else
|
||||
#define snd_soc_read snd_soc_component_read32
|
||||
-#endif
|
||||
#define snd_soc_register_codec devm_snd_soc_register_component
|
||||
#define snd_soc_unregister_codec snd_soc_unregister_component
|
||||
#define snd_soc_update_bits snd_soc_component_update_bits
|
||||
diff --git a/wm8960.c b/wm8960.c
|
||||
index 465c6dc..34d4dad 100644
|
||||
--- a/wm8960.c
|
||||
+++ b/wm8960.c
|
||||
@@ -796,7 +796,7 @@ static int wm8960_hw_free(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int wm8960_mute(struct snd_soc_dai *dai, int mute, int direction)
|
||||
+static int wm8960_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
@@ -1236,12 +1236,11 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
static const struct snd_soc_dai_ops wm8960_dai_ops = {
|
||||
.hw_params = wm8960_hw_params,
|
||||
.hw_free = wm8960_hw_free,
|
||||
- .mute_stream = wm8960_mute,
|
||||
+ .digital_mute = wm8960_mute,
|
||||
.set_fmt = wm8960_set_dai_fmt,
|
||||
.set_clkdiv = wm8960_set_dai_clkdiv,
|
||||
.set_pll = wm8960_set_dai_pll,
|
||||
.set_sysclk = wm8960_set_dai_sysclk,
|
||||
- .no_capture_mute = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver wm8960_dai = {
|
245
patches/back-to-v5.4.diff
Normal file
245
patches/back-to-v5.4.diff
Normal file
|
@ -0,0 +1,245 @@
|
|||
diff --git a/ac101.c b/ac101.c
|
||||
index be9b1d8..343f030 100644
|
||||
--- a/ac101.c
|
||||
+++ b/ac101.c
|
||||
@@ -955,10 +955,10 @@ void ac101_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai
|
||||
|
||||
AC101_DBG("stream = %s, play: %d, capt: %d, active: %d\n",
|
||||
snd_pcm_stream_str(substream),
|
||||
- codec_dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], codec_dai->stream_active[SNDRV_PCM_STREAM_CAPTURE],
|
||||
- snd_soc_dai_active(codec_dai));
|
||||
+ codec_dai->playback_active, codec_dai->capture_active,
|
||||
+ codec_dai->active);
|
||||
|
||||
- if (!snd_soc_dai_active(codec_dai)) {
|
||||
+ if (!codec_dai->active) {
|
||||
ac10x->aif1_clken = 1;
|
||||
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
|
||||
} else {
|
||||
@@ -1080,7 +1080,7 @@ int ac101_hw_params(struct snd_pcm_substream *substream,
|
||||
freq_out = _FREQ_24_576K;
|
||||
for (i = 0; i < ARRAY_SIZE(codec_aif1_fs); i++) {
|
||||
if (codec_aif1_fs[i].samp_rate == params_rate(params)) {
|
||||
- if (codec_dai->stream_active[SNDRV_PCM_STREAM_CAPTURE] && dmic_used && codec_aif1_fs[i].samp_rate == 44100) {
|
||||
+ if (codec_dai->capture_active && dmic_used && codec_aif1_fs[i].samp_rate == 44100) {
|
||||
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), (0x4<<AIF1_FS));
|
||||
} else {
|
||||
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), ((codec_aif1_fs[i].srbit)<<AIF1_FS));
|
||||
diff --git a/ac108.c b/ac108.c
|
||||
index 4663df0..12ab27b 100644
|
||||
--- a/ac108.c
|
||||
+++ b/ac108.c
|
||||
@@ -653,7 +653,7 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||
|
||||
dev_dbg(dai->dev, "%s() stream=%s play:%d capt:%d +++\n", __func__,
|
||||
snd_pcm_stream_str(substream),
|
||||
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE]);
|
||||
+ dai->playback_active, dai->capture_active);
|
||||
|
||||
if (ac10x->i2c101) {
|
||||
ret = ac101_hw_params(substream, params, dai);
|
||||
@@ -664,8 +664,8 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||
}
|
||||
}
|
||||
|
||||
- if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK])
|
||||
- || (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->stream_active[SNDRV_PCM_STREAM_CAPTURE])) {
|
||||
+ if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->playback_active)
|
||||
+ || (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->capture_active)) {
|
||||
/* not configure hw_param twice */
|
||||
/* return 0; */
|
||||
}
|
||||
@@ -1124,7 +1124,7 @@ void ac108_aif_shutdown(struct snd_pcm_substream *substream,
|
||||
}
|
||||
}
|
||||
|
||||
-int ac108_aif_mute(struct snd_soc_dai *dai, int mute, int direction) {
|
||||
+int ac108_aif_mute(struct snd_soc_dai *dai, int mute) {
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
@@ -1145,13 +1145,12 @@ static const struct snd_soc_dai_ops ac108_dai_ops = {
|
||||
.hw_params = ac108_hw_params,
|
||||
.prepare = ac108_prepare,
|
||||
.trigger = ac108_trigger,
|
||||
- .mute_stream = ac108_aif_mute,
|
||||
+ .digital_mute = ac108_aif_mute,
|
||||
|
||||
/*DAI format configuration*/
|
||||
.set_fmt = ac108_set_fmt,
|
||||
|
||||
// .hw_free = ac108_hw_free,
|
||||
- .no_capture_mute = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ac108_dai0 = {
|
||||
diff --git a/seeed-voicecard.c b/seeed-voicecard.c
|
||||
index c6d9048..43535aa 100644
|
||||
--- a/seeed-voicecard.c
|
||||
+++ b/seeed-voicecard.c
|
||||
@@ -96,16 +96,16 @@ static int seeed_voice_card_startup(struct snd_pcm_substream *substream)
|
||||
if (ret)
|
||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||
|
||||
- if (asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min) {
|
||||
- priv->channels_playback_default = asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min;
|
||||
+ if (rtd->cpu_dai->driver->playback.channels_min) {
|
||||
+ priv->channels_playback_default = rtd->cpu_dai->driver->playback.channels_min;
|
||||
}
|
||||
- if (asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min) {
|
||||
- priv->channels_capture_default = asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min;
|
||||
+ if (rtd->cpu_dai->driver->capture.channels_min) {
|
||||
+ priv->channels_capture_default = rtd->cpu_dai->driver->capture.channels_min;
|
||||
}
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_override;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_override;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_override;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_override;
|
||||
+ rtd->cpu_dai->driver->playback.channels_min = priv->channels_playback_override;
|
||||
+ rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_override;
|
||||
+ rtd->cpu_dai->driver->capture.channels_min = priv->channels_capture_override;
|
||||
+ rtd->cpu_dai->driver->capture.channels_max = priv->channels_capture_override;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -117,10 +117,10 @@ static void seeed_voice_card_shutdown(struct snd_pcm_substream *substream)
|
||||
struct seeed_dai_props *dai_props =
|
||||
seeed_priv_to_props(priv, rtd->num);
|
||||
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_default;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_default;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_default;
|
||||
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_default;
|
||||
+ rtd->cpu_dai->driver->playback.channels_min = priv->channels_playback_default;
|
||||
+ rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_default;
|
||||
+ rtd->cpu_dai->driver->capture.channels_min = priv->channels_capture_default;
|
||||
+ rtd->cpu_dai->driver->capture.channels_max = priv->channels_capture_default;
|
||||
|
||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||
|
||||
@@ -131,8 +131,8 @@ static int seeed_voice_card_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
|
||||
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct seeed_dai_props *dai_props =
|
||||
seeed_priv_to_props(priv, rtd->num);
|
||||
@@ -196,7 +196,7 @@ static void work_cb_codec_clk(struct work_struct *work)
|
||||
static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
|
||||
+ struct snd_soc_dai *dai = rtd->codec_dai;
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
#if CONFIG_AC10X_TRIG_LOCK
|
||||
unsigned long flags;
|
||||
@@ -205,7 +205,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||
|
||||
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d\n",
|
||||
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE]);
|
||||
+ dai->playback_active, dai->capture_active);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
@@ -227,7 +227,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
/* capture channel resync, if overrun */
|
||||
- if (dai->stream_active[SNDRV_PCM_STREAM_CAPTURE] && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
+ if (dai->capture_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -252,7 +247,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||
|
||||
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d;finished %d\n",
|
||||
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE], ret);
|
||||
+ dai->playback_active, dai->capture_active, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -337,8 +337,8 @@ static int asoc_simple_init_dai(struct snd_soc_dai *dai,
|
||||
static int seeed_voice_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
- struct snd_soc_dai *codec = asoc_rtd_to_codec(rtd, 0);
|
||||
- struct snd_soc_dai *cpu = asoc_rtd_to_cpu(rtd, 0);
|
||||
+ struct snd_soc_dai *codec = rtd->codec_dai;
|
||||
+ struct snd_soc_dai *cpu = rtd->cpu_dai;
|
||||
struct seeed_dai_props *dai_props =
|
||||
seeed_priv_to_props(priv, rtd->num);
|
||||
int ret;
|
||||
@@ -636,11 +636,11 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||
* Use snd_soc_dai_link_component instead of legacy style
|
||||
* It is codec only. but cpu/platform will be supported in the future.
|
||||
* see
|
||||
- * soc-core.c :: snd_soc_init_multicodec()
|
||||
+ * soc-core.c :: snd_soc_init_multicodec()
|
||||
*
|
||||
* "platform" might be removed
|
||||
* see
|
||||
- * simple-card-utils.c :: asoc_simple_canonicalize_platform()
|
||||
+ * simple-card-utils.c :: asoc_simple_canonicalize_platform()
|
||||
*/
|
||||
for (i = 0; i < num; i++) {
|
||||
dai_link[i].cpus = &dai_props[i].cpus;
|
||||
diff --git a/sound-compatible-4.18.h b/sound-compatible-4.18.h
|
||||
index 080325b..eefa7de 100644
|
||||
--- a/sound-compatible-4.18.h
|
||||
+++ b/sound-compatible-4.18.h
|
||||
@@ -16,6 +16,10 @@
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
|
||||
+#ifndef __has_attribute
|
||||
+# define __has_attribute(x) __GCC4_has_attribute_##x
|
||||
+# define __GCC4_has_attribute___fallthrough__ 0
|
||||
+#endif
|
||||
#if __has_attribute(__fallthrough__)
|
||||
# define fallthrough __attribute__((__fallthrough__))
|
||||
#else
|
||||
@@ -31,11 +35,7 @@
|
||||
#define snd_soc_codec_get_dapm snd_soc_component_get_dapm
|
||||
#define snd_soc_codec_get_bias_level snd_soc_component_get_bias_level
|
||||
#define snd_soc_kcontrol_codec snd_soc_kcontrol_component
|
||||
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
|
||||
-#define snd_soc_read snd_soc_component_read
|
||||
-#else
|
||||
#define snd_soc_read snd_soc_component_read32
|
||||
-#endif
|
||||
#define snd_soc_register_codec devm_snd_soc_register_component
|
||||
#define snd_soc_unregister_codec snd_soc_unregister_component
|
||||
#define snd_soc_update_bits snd_soc_component_update_bits
|
||||
diff --git a/wm8960.c b/wm8960.c
|
||||
index 465c6dc..34d4dad 100644
|
||||
--- a/wm8960.c
|
||||
+++ b/wm8960.c
|
||||
@@ -796,7 +796,7 @@ static int wm8960_hw_free(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int wm8960_mute(struct snd_soc_dai *dai, int mute, int direction)
|
||||
+static int wm8960_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
@@ -1236,12 +1236,11 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
static const struct snd_soc_dai_ops wm8960_dai_ops = {
|
||||
.hw_params = wm8960_hw_params,
|
||||
.hw_free = wm8960_hw_free,
|
||||
- .mute_stream = wm8960_mute,
|
||||
+ .digital_mute = wm8960_mute,
|
||||
.set_fmt = wm8960_set_dai_fmt,
|
||||
.set_clkdiv = wm8960_set_dai_clkdiv,
|
||||
.set_pll = wm8960_set_dai_pll,
|
||||
.set_sysclk = wm8960_set_dai_sysclk,
|
||||
- .no_capture_mute = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver wm8960_dai = {
|
71
patches/back-to-v5.8.diff
Normal file
71
patches/back-to-v5.8.diff
Normal file
|
@ -0,0 +1,71 @@
|
|||
diff --git a/ac108.c b/ac108.c
|
||||
index 4663df0..67edeae 100644
|
||||
--- a/ac108.c
|
||||
+++ b/ac108.c
|
||||
@@ -1124,7 +1124,7 @@ void ac108_aif_shutdown(struct snd_pcm_substream *substream,
|
||||
}
|
||||
}
|
||||
|
||||
-int ac108_aif_mute(struct snd_soc_dai *dai, int mute, int direction) {
|
||||
+int ac108_aif_mute(struct snd_soc_dai *dai, int mute) {
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
@@ -1145,13 +1145,12 @@ static const struct snd_soc_dai_ops ac108_dai_ops = {
|
||||
.hw_params = ac108_hw_params,
|
||||
.prepare = ac108_prepare,
|
||||
.trigger = ac108_trigger,
|
||||
- .mute_stream = ac108_aif_mute,
|
||||
+ .digital_mute = ac108_aif_mute,
|
||||
|
||||
/*DAI format configuration*/
|
||||
.set_fmt = ac108_set_fmt,
|
||||
|
||||
// .hw_free = ac108_hw_free,
|
||||
- .no_capture_mute = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ac108_dai0 = {
|
||||
diff --git a/sound-compatible-4.18.h b/sound-compatible-4.18.h
|
||||
index 080325b..faed848 100644
|
||||
--- a/sound-compatible-4.18.h
|
||||
+++ b/sound-compatible-4.18.h
|
||||
@@ -31,11 +31,7 @@
|
||||
#define snd_soc_codec_get_dapm snd_soc_component_get_dapm
|
||||
#define snd_soc_codec_get_bias_level snd_soc_component_get_bias_level
|
||||
#define snd_soc_kcontrol_codec snd_soc_kcontrol_component
|
||||
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
|
||||
-#define snd_soc_read snd_soc_component_read
|
||||
-#else
|
||||
#define snd_soc_read snd_soc_component_read32
|
||||
-#endif
|
||||
#define snd_soc_register_codec devm_snd_soc_register_component
|
||||
#define snd_soc_unregister_codec snd_soc_unregister_component
|
||||
#define snd_soc_update_bits snd_soc_component_update_bits
|
||||
diff --git a/wm8960.c b/wm8960.c
|
||||
index 465c6dc..34d4dad 100644
|
||||
--- a/wm8960.c
|
||||
+++ b/wm8960.c
|
||||
@@ -796,7 +796,7 @@ static int wm8960_hw_free(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int wm8960_mute(struct snd_soc_dai *dai, int mute, int direction)
|
||||
+static int wm8960_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
@@ -1236,12 +1236,11 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
static const struct snd_soc_dai_ops wm8960_dai_ops = {
|
||||
.hw_params = wm8960_hw_params,
|
||||
.hw_free = wm8960_hw_free,
|
||||
- .mute_stream = wm8960_mute,
|
||||
+ .digital_mute = wm8960_mute,
|
||||
.set_fmt = wm8960_set_dai_fmt,
|
||||
.set_clkdiv = wm8960_set_dai_clkdiv,
|
||||
.set_pll = wm8960_set_dai_pll,
|
||||
.set_sysclk = wm8960_set_dai_sysclk,
|
||||
- .no_capture_mute = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver wm8960_dai = {
|
8
pulseaudio/91-seeedvoicecard.rules
Normal file
8
pulseaudio/91-seeedvoicecard.rules
Normal file
|
@ -0,0 +1,8 @@
|
|||
SUBSYSTEM!="sound", GOTO="seeedvoicecard_end"
|
||||
ACTION!="change", GOTO="seeedvoicecard_end"
|
||||
KERNEL!="card*", GOTO="seeedvoicecard_end"
|
||||
|
||||
ATTR{id}=="seeed4micvoicec",ENV{PULSE_PROFILE_SET}="seeed-voicecard-4mic.conf"
|
||||
ATTR{id}=="seeed8micvoicec",ENV{PULSE_PROFILE_SET}="seeed-voicecard-8mic.conf"
|
||||
|
||||
LABEL="seeedvoicecard_end"
|
251
pulseaudio/README.md
Normal file
251
pulseaudio/README.md
Normal file
|
@ -0,0 +1,251 @@
|
|||
# PulseAudio Configuration for seeed-voicecard
|
||||
|
||||
Follow this guide if you want to use your seeed-voicecard as a default source/sink of pulseaudio.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Download PulseAudio
|
||||
```
|
||||
sudo apt install -y pulseaudio
|
||||
```
|
||||
|
||||
2. PulseAudio Profiles
|
||||
```
|
||||
cd seeed-voicecard/pulseaudio
|
||||
sudo cp pulse_config_4mic/seeed-voicecard.conf /usr/share/pulseaudio/alsa-mixer/profile-sets/seeed-voicecard-4mic.conf
|
||||
sudo cp pulse_config_6mic/seeed-voicecard.conf /usr/share/pulseaudio/alsa-mixer/profile-sets/seeed-voicecard-8mic.conf
|
||||
```
|
||||
|
||||
3. Add `udev` Rules
|
||||
|
||||
During the system start, when the card "seeed4micvoicec" is detected, the PULSE_PROFILE_SET variable will be set in the udev database, and PulseAudio will be forced to use `seeed-voicecard-4mic.conf`. Similarly, if the card "seeed8micvoicec" is detected, PulseAudio will be forced to use `seeed-voicecard-8mic.conf`.
|
||||
|
||||
```
|
||||
sudo cp 91-seeedvoicecard.rules /etc/udev/rules.d/91-seeedvoicecard.rules
|
||||
```
|
||||
|
||||
### ReSpeaker 4 Mic Array
|
||||
|
||||
<!--
|
||||
1. Download pulseaudio
|
||||
```
|
||||
sudo apt install pulseaudio
|
||||
```
|
||||
|
||||
2. First, you need to write [a profile for pulse](https://www.freedesktop.org/wiki/Software/PulseAudio/Backends/ALSA/Profiles/)
|
||||
```
|
||||
cd seeed-voicecard
|
||||
cd pulseaudio
|
||||
cd pulse_config_4mic
|
||||
sudo cp seeed-voicecard.conf /usr/share/pulseaudio/alsa-mixer/profile-sets/
|
||||
```
|
||||
|
||||
3. Edit `udev rules`
|
||||
|
||||
During the system start, when the card "seeed4micvoicec" is detected, the PULSE_PROFILE_SET variable will be set in the udev database, and PulseAudio will be forced to use `seeed-voicecard.conf`.
|
||||
|
||||
```
|
||||
# have a look at /lib/udev/rules.d/90-pulseaudio.rules
|
||||
sudo vim /lib/udev/rules.d/90-pulseaudio.rules
|
||||
# add the following lines at about line 87(behind the setting for some laptops and before the line GOTO="pulseaudio_end")
|
||||
# Seeed Voicecard
|
||||
ATTR{id}=="seeed4micvoicec",ATTR{number}=="1",ENV{PULSE_PROFILE_SET}="seeed-voicecard.conf"
|
||||
```
|
||||

|
||||
|
||||
The value of `ATTR{number}` can be found with:
|
||||
|
||||
```
|
||||
udevadm info -a -p /sys/class/sound/card0/
|
||||
# or udevadm info -a -p /sys/class/sound/card1/
|
||||
```
|
||||
|
||||
For example, in Raspberry Pi, we can find `ATTR{id}=="seeed4micvoicec"` and `ATTR{number}=="1"` with command `udevadm info -a -p /sys/class/sound/card1/`:
|
||||
|
||||
```
|
||||
pi@raspberrypi:~ $ udevadm info -a -p /sys/class/sound/card1/
|
||||
|
||||
Udevadm info starts with the device specified by the devpath and then
|
||||
walks up the chain of parent devices. It prints for every device
|
||||
found, all possible attributes in the udev rules key format.
|
||||
A rule to match, can be composed by the attributes of the device
|
||||
and the attributes from one single parent device.
|
||||
|
||||
looking at device '/devices/platform/soc/soc:sound/sound/card1':
|
||||
KERNEL=="card1"
|
||||
SUBSYSTEM=="sound"
|
||||
DRIVER==""
|
||||
ATTR{id}=="seeed4micvoicec"
|
||||
ATTR{number}=="1"
|
||||
|
||||
looking at parent device '/devices/platform/soc/soc:sound':
|
||||
KERNELS=="soc:sound"
|
||||
SUBSYSTEMS=="platform"
|
||||
DRIVERS=="seeed-voicecard"
|
||||
ATTRS{driver_override}=="(null)"
|
||||
|
||||
looking at parent device '/devices/platform/soc':
|
||||
KERNELS=="soc"
|
||||
SUBSYSTEMS=="platform"
|
||||
DRIVERS==""
|
||||
ATTRS{driver_override}=="(null)"
|
||||
|
||||
looking at parent device '/devices/platform':
|
||||
KERNELS=="platform"
|
||||
SUBSYSTEMS==""
|
||||
DRIVERS==""
|
||||
``` -->
|
||||
|
||||
1. config `default.pa` and `daemon.conf`
|
||||
```
|
||||
sudo cp pulse_config_4mic/default.pa /etc/pulse/
|
||||
sudo cp pulse_config_4mic/daemon.conf /etc/pulse/
|
||||
```
|
||||
|
||||
2. reboot raspberry pi and check
|
||||
```
|
||||
sudo reboot
|
||||
pulseaudio --start # start pulse at first
|
||||
pactl info # check the setting
|
||||
|
||||
Server String: /run/user/1000/pulse/native
|
||||
Library Protocol Version: 32
|
||||
Server Protocol Version: 32
|
||||
Is Local: yes
|
||||
Client Index: 18
|
||||
Tile Size: 65496
|
||||
User Name: pi
|
||||
Host Name: raspberrypi
|
||||
Server Name: pulseaudio
|
||||
Server Version: 10.0
|
||||
Default Sample Specification: s16le 4ch 96000Hz
|
||||
Default Channel Map: front-left,front-center,front-right,rear-center
|
||||
Default Sink: alsa_output.platform-soc_audio.analog-stereo
|
||||
Default Source: alsa_input.platform-soc_sound.seeed-source
|
||||
Cookie: 3b12:70b3
|
||||
```
|
||||
|
||||
### 6-Mics Circular Array Kit and 4-Mics Linear Array
|
||||
|
||||
<!--
|
||||
1. Download pulseaudio
|
||||
```
|
||||
sudo apt install pulseaudio
|
||||
```
|
||||
|
||||
2. First, you need to write [a profile for pulse](https://www.freedesktop.org/wiki/Software/PulseAudio/Backends/ALSA/Profiles/)
|
||||
```
|
||||
cd seeed-voicecard
|
||||
cd pulseaudio
|
||||
cd pulse_config_6mic
|
||||
sudo cp seeed-voicecard.conf /usr/share/pulseaudio/alsa-mixer/profile-sets/
|
||||
```
|
||||
|
||||
3. Edit `udev rules`
|
||||
|
||||
During the system start, when the card "seeed8micvoicec" is detected, the PULSE_PROFILE_SET variable will be set in the udev database, and PulseAudio will be forced to use `seeed-voicecard.conf`.
|
||||
|
||||
```
|
||||
# have a look at /lib/udev/rules.d/90-pulseaudio.rules
|
||||
sudo vim /lib/udev/rules.d/90-pulseaudio.rules
|
||||
# add the following lines at about line 87(behind the setting for some laptops and before the line GOTO="pulseaudio_end")
|
||||
# Seeed Voicecard
|
||||
ATTR{id}=="seeed8micvoicec",ATTR{number}=="1",ENV{PULSE_PROFILE_SET}="seeed-voicecard.conf"
|
||||
```
|
||||

|
||||
|
||||
The value of `ATTR{number}` can be found with:
|
||||
|
||||
```
|
||||
udevadm info -a -p /sys/class/sound/card0/
|
||||
# or udevadm info -a -p /sys/class/sound/card1/
|
||||
```
|
||||
|
||||
For example, in Raspberry Pi, we can find `ATTR{id}=="seeed8micvoicec"` and `ATTR{number}=="1"` with command `udevadm info -a -p /sys/class/sound/card1/`:
|
||||
|
||||
```
|
||||
pi@raspberrypi:~ $ udevadm info -a -p /sys/class/sound/card1/
|
||||
|
||||
Udevadm info starts with the device specified by the devpath and then
|
||||
walks up the chain of parent devices. It prints for every device
|
||||
found, all possible attributes in the udev rules key format.
|
||||
A rule to match, can be composed by the attributes of the device
|
||||
and the attributes from one single parent device.
|
||||
|
||||
looking at device '/devices/platform/soc/soc:sound/sound/card1':
|
||||
KERNEL=="card1"
|
||||
SUBSYSTEM=="sound"
|
||||
DRIVER==""
|
||||
ATTR{id}=="seeed8micvoicec"
|
||||
ATTR{number}=="1"
|
||||
|
||||
looking at parent device '/devices/platform/soc/soc:sound':
|
||||
KERNELS=="soc:sound"
|
||||
SUBSYSTEMS=="platform"
|
||||
DRIVERS=="seeed-voicecard"
|
||||
ATTRS{driver_override}=="(null)"
|
||||
|
||||
looking at parent device '/devices/platform/soc':
|
||||
KERNELS=="soc"
|
||||
SUBSYSTEMS=="platform"
|
||||
DRIVERS==""
|
||||
ATTRS{driver_override}=="(null)"
|
||||
|
||||
looking at parent device '/devices/platform':
|
||||
KERNELS=="platform"
|
||||
SUBSYSTEMS==""
|
||||
DRIVERS==""
|
||||
``` -->
|
||||
|
||||
1. config `default.pa` and `daemon.conf`
|
||||
```
|
||||
sudo cp pulse_config_6mic/default.pa /etc/pulse/
|
||||
sudo cp pulse_config_6mic/daemon.conf /etc/pulse/
|
||||
```
|
||||
|
||||
2. reboot raspberry pi and check
|
||||
```
|
||||
sudo reboot
|
||||
pulseaudio --start # start pulse at first
|
||||
pactl info # check the setting
|
||||
|
||||
# The output should be like this
|
||||
# You could see the default sink is seeed-2ch and default source is seeed-8ch
|
||||
pi@raspberrypi:~ $ pactl info
|
||||
Server String: /run/user/1000/pulse/native
|
||||
Library Protocol Version: 32
|
||||
Server Protocol Version: 32
|
||||
Is Local: yes
|
||||
Client Index: 6
|
||||
Tile Size: 65496
|
||||
User Name: pi
|
||||
Host Name: raspberrypi
|
||||
Server Name: pulseaudio
|
||||
Server Version: 10.0
|
||||
Default Sample Specification: s32le 8ch 96000Hz
|
||||
Default Channel Map: front-left,front-left-of-center,front-center,front-right,front-right-of-center,rear-center,aux0,aux1
|
||||
Default Sink: alsa_output.platform-soc_sound.seeed-2ch
|
||||
Default Source: alsa_input.platform-soc_sound.seeed-8ch
|
||||
Cookie: 3523:e5af
|
||||
```
|
||||
|
||||
### FAQ
|
||||
|
||||
1. Default Sink/Source not right
|
||||
|
||||
Make sure there is no any other daemon or using the audio device. Then check profile and udev rules.
|
||||
|
||||
`pacmd list-sinks` and `pacmd list-sources` can be used to show the avaiable sinks/sources, after pulseaudio is started.
|
||||
|
||||
2. Can't start PulseAudio
|
||||
|
||||
Check `default.pa` and `daemon.conf`
|
||||
|
||||
3. How to get PulseAudio started automatically
|
||||
|
||||
Normally the PulseAudio server is started automatically. If you want to disable it, you can set `autospawn = no` in `~/.config/pulse/client.conf` or `/etc/pulse/client.conf`.
|
||||
[Click this for more details](https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Running/).
|
||||
|
||||
4. Why the default sample rate is 96000? What if my audio's sample rate is not the same as the default?
|
||||
|
||||
For the other sample rate audio, PulseAudio will resample it into 96K, which means that if your audio's sample rate is lower than 96K, it will get smoothing.
|
87
pulseaudio/pulse_config_4mic/daemon.conf
Normal file
87
pulseaudio/pulse_config_4mic/daemon.conf
Normal file
|
@ -0,0 +1,87 @@
|
|||
# This file is part of PulseAudio.
|
||||
#
|
||||
# PulseAudio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# PulseAudio is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## Configuration file for the PulseAudio daemon. See pulse-daemon.conf(5) for
|
||||
## more information. Default values are commented out. Use either ; or # for
|
||||
## commenting.
|
||||
|
||||
; daemonize = no
|
||||
; fail = yes
|
||||
; allow-module-loading = yes
|
||||
; allow-exit = yes
|
||||
; use-pid-file = yes
|
||||
; system-instance = no
|
||||
; local-server-type = user
|
||||
; enable-shm = yes
|
||||
; enable-memfd = yes
|
||||
; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB
|
||||
; lock-memory = no
|
||||
; cpu-limit = no
|
||||
|
||||
; high-priority = yes
|
||||
; nice-level = -11
|
||||
|
||||
; realtime-scheduling = yes
|
||||
; realtime-priority = 5
|
||||
|
||||
; exit-idle-time = 20
|
||||
; scache-idle-time = 20
|
||||
|
||||
; dl-search-path = (depends on architecture)
|
||||
|
||||
; load-default-script-file = yes
|
||||
; default-script-file = /etc/pulse/default.pa
|
||||
|
||||
; log-target = auto
|
||||
; log-level = notice
|
||||
; log-meta = no
|
||||
; log-time = no
|
||||
; log-backtrace = 0
|
||||
|
||||
; resample-method = speex-float-1
|
||||
; enable-remixing = yes
|
||||
; enable-lfe-remixing = no
|
||||
; lfe-crossover-freq = 0
|
||||
|
||||
; flat-volumes = yes
|
||||
|
||||
; rlimit-fsize = -1
|
||||
; rlimit-data = -1
|
||||
; rlimit-stack = -1
|
||||
; rlimit-core = -1
|
||||
; rlimit-as = -1
|
||||
; rlimit-rss = -1
|
||||
; rlimit-nproc = -1
|
||||
; rlimit-nofile = 256
|
||||
; rlimit-memlock = -1
|
||||
; rlimit-locks = -1
|
||||
; rlimit-sigpending = -1
|
||||
; rlimit-msgqueue = -1
|
||||
; rlimit-nice = 31
|
||||
; rlimit-rtprio = 9
|
||||
; rlimit-rttime = 200000
|
||||
|
||||
default-sample-format = s16le
|
||||
default-sample-rate = 96000
|
||||
; alternate-sample-rate = 48000
|
||||
default-sample-channels = 4
|
||||
; default-channel-map = front-left,front-right
|
||||
|
||||
; default-fragments = 4
|
||||
; default-fragment-size-msec = 25
|
||||
|
||||
; enable-deferred-volume = yes
|
||||
; deferred-volume-safety-margin-usec = 8000
|
||||
; deferred-volume-extra-delay-usec = 0
|
144
pulseaudio/pulse_config_4mic/default.pa
Normal file
144
pulseaudio/pulse_config_4mic/default.pa
Normal file
|
@ -0,0 +1,144 @@
|
|||
#!/usr/bin/pulseaudio -nF
|
||||
#
|
||||
# This file is part of PulseAudio.
|
||||
#
|
||||
# PulseAudio is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# PulseAudio is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This startup script is used only if PulseAudio is started per-user
|
||||
# (i.e. not in system mode)
|
||||
|
||||
.fail
|
||||
|
||||
### Automatically restore the volume of streams and devices
|
||||
load-module module-device-restore
|
||||
load-module module-stream-restore
|
||||
load-module module-card-restore
|
||||
|
||||
### Automatically augment property information from .desktop files
|
||||
### stored in /usr/share/application
|
||||
load-module module-augment-properties
|
||||
|
||||
### Should be after module-*-restore but before module-*-detect
|
||||
load-module module-switch-on-port-available
|
||||
|
||||
### Load audio drivers statically
|
||||
### (it's probably better to not load these drivers manually, but instead
|
||||
### use module-udev-detect -- see below -- for doing this automatically)
|
||||
#load-module module-alsa-sink device="hw:1,0" channels=8 rate=48000 format=s32le
|
||||
#load-module module-alsa-source device="hw:1,0" channels=8 rate=48000 format=s32le
|
||||
#load-module module-oss device="/dev/dsp" sink_name=output source_name=input
|
||||
#load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input
|
||||
#load-module module-null-sink
|
||||
#load-module module-pipe-sink
|
||||
|
||||
### Automatically load driver modules depending on the hardware available
|
||||
.ifexists module-udev-detect.so
|
||||
load-module module-udev-detect
|
||||
#channels=8 rate=48000 format=s32le
|
||||
.else
|
||||
### Use the static hardware detection module (for systems that lack udev support)
|
||||
load-module module-detect
|
||||
.endif
|
||||
|
||||
### Automatically connect sink and source if JACK server is present
|
||||
.ifexists module-jackdbus-detect.so
|
||||
.nofail
|
||||
load-module module-jackdbus-detect channels=2
|
||||
.fail
|
||||
.endif
|
||||
|
||||
### Automatically load driver modules for Bluetooth hardware
|
||||
.ifexists module-bluetooth-policy.so
|
||||
load-module module-bluetooth-policy
|
||||
.endif
|
||||
|
||||
.ifexists module-bluetooth-discover.so
|
||||
load-module module-bluetooth-discover
|
||||
.endif
|
||||
|
||||
### Load several protocols
|
||||
.ifexists module-esound-protocol-unix.so
|
||||
load-module module-esound-protocol-unix
|
||||
.endif
|
||||
load-module module-native-protocol-unix
|
||||
|
||||
### Network access (may be configured with paprefs, so leave this commented
|
||||
### here if you plan to use paprefs)
|
||||
#load-module module-esound-protocol-tcp
|
||||
#load-module module-native-protocol-tcp
|
||||
#load-module module-zeroconf-publish
|
||||
|
||||
### Load the RTP receiver module (also configured via paprefs, see above)
|
||||
#load-module module-rtp-recv
|
||||
|
||||
### Load the RTP sender module (also configured via paprefs, see above)
|
||||
#load-module module-null-sink sink_name=rtp format=s16be channels=2 rate=44100 sink_properties="device.description='RTP Multicast Sink'"
|
||||
#load-module module-rtp-send source=rtp.monitor
|
||||
|
||||
### Load additional modules from GConf settings. This can be configured with the paprefs tool.
|
||||
### Please keep in mind that the modules configured by paprefs might conflict with manually
|
||||
### loaded modules.
|
||||
.ifexists module-gconf.so
|
||||
.nofail
|
||||
load-module module-gconf
|
||||
.fail
|
||||
.endif
|
||||
|
||||
### Automatically restore the default sink/source when changed by the user
|
||||
### during runtime
|
||||
### NOTE: This should be loaded as early as possible so that subsequent modules
|
||||
### that look up the default sink/source get the right value
|
||||
load-module module-default-device-restore
|
||||
|
||||
### Automatically move streams to the default sink if the sink they are
|
||||
### connected to dies, similar for sources
|
||||
load-module module-rescue-streams
|
||||
|
||||
### Make sure we always have a sink around, even if it is a null sink.
|
||||
load-module module-always-sink
|
||||
|
||||
### Honour intended role device property
|
||||
load-module module-intended-roles
|
||||
|
||||
### Automatically suspend sinks/sources that become idle for too long
|
||||
load-module module-suspend-on-idle
|
||||
|
||||
### If autoexit on idle is enabled we want to make sure we only quit
|
||||
### when no local session needs us anymore.
|
||||
.ifexists module-console-kit.so
|
||||
load-module module-console-kit
|
||||
.endif
|
||||
.ifexists module-systemd-login.so
|
||||
load-module module-systemd-login
|
||||
.endif
|
||||
|
||||
### Enable positioned event sounds
|
||||
load-module module-position-event-sounds
|
||||
|
||||
### Cork music/video streams when a phone stream is active
|
||||
load-module module-role-cork
|
||||
|
||||
### Modules to allow autoloading of filters (such as echo cancellation)
|
||||
### on demand. module-filter-heuristics tries to determine what filters
|
||||
### make sense, and module-filter-apply does the heavy-lifting of
|
||||
### loading modules and rerouting streams.
|
||||
load-module module-filter-heuristics
|
||||
load-module module-filter-apply
|
||||
|
||||
### Make some devices default
|
||||
#set-default-sink output
|
||||
#set-default-source input
|
||||
set-default-source alsa_input.platform-soc_sound.seeed-source
|
||||
set-default-sink alsa_output.platform-soc_sound.seeed-sink
|
||||
|
17
pulseaudio/pulse_config_4mic/seeed-voicecard.conf
Normal file
17
pulseaudio/pulse_config_4mic/seeed-voicecard.conf
Normal file
|
@ -0,0 +1,17 @@
|
|||
# /usr/share/pulseaudio/alsa-mixer/profile-sets/seeed-voicecard.conf
|
||||
|
||||
[General]
|
||||
auto-profiles = no
|
||||
[Mapping seeed-source]
|
||||
device-strings = hw:%f
|
||||
channel-map = front-left,front-right,rear-left,rear-right
|
||||
exact-channels = false
|
||||
fallback = yes
|
||||
paths-input = seeed-source
|
||||
priority = 3
|
||||
direction = input
|
||||
|
||||
[Profile input:seeed-source]
|
||||
input-mappings = seeed-source
|
||||
priority = 5
|
||||
skip-probe = yes
|
87
pulseaudio/pulse_config_6mic/daemon.conf
Normal file
87
pulseaudio/pulse_config_6mic/daemon.conf
Normal file
|
@ -0,0 +1,87 @@
|
|||
# This file is part of PulseAudio.
|
||||
#
|
||||
# PulseAudio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# PulseAudio is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## Configuration file for the PulseAudio daemon. See pulse-daemon.conf(5) for
|
||||
## more information. Default values are commented out. Use either ; or # for
|
||||
## commenting.
|
||||
|
||||
; daemonize = no
|
||||
; fail = yes
|
||||
; allow-module-loading = yes
|
||||
; allow-exit = yes
|
||||
; use-pid-file = yes
|
||||
; system-instance = no
|
||||
; local-server-type = user
|
||||
; enable-shm = yes
|
||||
; enable-memfd = yes
|
||||
; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB
|
||||
; lock-memory = no
|
||||
; cpu-limit = no
|
||||
|
||||
; high-priority = yes
|
||||
; nice-level = -11
|
||||
|
||||
; realtime-scheduling = yes
|
||||
; realtime-priority = 5
|
||||
|
||||
; exit-idle-time = 20
|
||||
; scache-idle-time = 20
|
||||
|
||||
; dl-search-path = (depends on architecture)
|
||||
|
||||
; load-default-script-file = yes
|
||||
; default-script-file = /etc/pulse/default.pa
|
||||
|
||||
; log-target = auto
|
||||
; log-level = notice
|
||||
; log-meta = no
|
||||
; log-time = no
|
||||
; log-backtrace = 0
|
||||
|
||||
; resample-method = speex-float-1
|
||||
; enable-remixing = yes
|
||||
; enable-lfe-remixing = no
|
||||
; lfe-crossover-freq = 0
|
||||
|
||||
; flat-volumes = yes
|
||||
|
||||
; rlimit-fsize = -1
|
||||
; rlimit-data = -1
|
||||
; rlimit-stack = -1
|
||||
; rlimit-core = -1
|
||||
; rlimit-as = -1
|
||||
; rlimit-rss = -1
|
||||
; rlimit-nproc = -1
|
||||
; rlimit-nofile = 256
|
||||
; rlimit-memlock = -1
|
||||
; rlimit-locks = -1
|
||||
; rlimit-sigpending = -1
|
||||
; rlimit-msgqueue = -1
|
||||
; rlimit-nice = 31
|
||||
; rlimit-rtprio = 9
|
||||
; rlimit-rttime = 200000
|
||||
|
||||
default-sample-format = s32le
|
||||
default-sample-rate = 96000
|
||||
; alternate-sample-rate = 48000
|
||||
default-sample-channels = 8
|
||||
; default-channel-map = front-left,front-right
|
||||
|
||||
; default-fragments = 4
|
||||
; default-fragment-size-msec = 25
|
||||
|
||||
; enable-deferred-volume = yes
|
||||
; deferred-volume-safety-margin-usec = 8000
|
||||
; deferred-volume-extra-delay-usec = 0
|
143
pulseaudio/pulse_config_6mic/default.pa
Normal file
143
pulseaudio/pulse_config_6mic/default.pa
Normal file
|
@ -0,0 +1,143 @@
|
|||
#!/usr/bin/pulseaudio -nF
|
||||
#
|
||||
# This file is part of PulseAudio.
|
||||
#
|
||||
# PulseAudio is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# PulseAudio is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This startup script is used only if PulseAudio is started per-user
|
||||
# (i.e. not in system mode)
|
||||
|
||||
.fail
|
||||
|
||||
### Automatically restore the volume of streams and devices
|
||||
load-module module-device-restore
|
||||
load-module module-stream-restore
|
||||
load-module module-card-restore
|
||||
|
||||
### Automatically augment property information from .desktop files
|
||||
### stored in /usr/share/application
|
||||
load-module module-augment-properties
|
||||
|
||||
### Should be after module-*-restore but before module-*-detect
|
||||
load-module module-switch-on-port-available
|
||||
|
||||
### Load audio drivers statically
|
||||
### (it's probably better to not load these drivers manually, but instead
|
||||
### use module-udev-detect -- see below -- for doing this automatically)
|
||||
#load-module module-alsa-sink device="hw:1,0" channels=8 rate=48000 format=s32le
|
||||
#load-module module-alsa-source device="hw:1,0" channels=8 rate=48000 format=s32le
|
||||
#load-module module-oss device="/dev/dsp" sink_name=output source_name=input
|
||||
#load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input
|
||||
#load-module module-null-sink
|
||||
#load-module module-pipe-sink
|
||||
|
||||
### Automatically load driver modules depending on the hardware available
|
||||
.ifexists module-udev-detect.so
|
||||
load-module module-udev-detect
|
||||
#channels=8 rate=48000 format=s32le
|
||||
.else
|
||||
### Use the static hardware detection module (for systems that lack udev support)
|
||||
load-module module-detect
|
||||
.endif
|
||||
|
||||
### Automatically connect sink and source if JACK server is present
|
||||
.ifexists module-jackdbus-detect.so
|
||||
.nofail
|
||||
load-module module-jackdbus-detect channels=2
|
||||
.fail
|
||||
.endif
|
||||
|
||||
### Automatically load driver modules for Bluetooth hardware
|
||||
.ifexists module-bluetooth-policy.so
|
||||
load-module module-bluetooth-policy
|
||||
.endif
|
||||
|
||||
.ifexists module-bluetooth-discover.so
|
||||
load-module module-bluetooth-discover
|
||||
.endif
|
||||
|
||||
### Load several protocols
|
||||
.ifexists module-esound-protocol-unix.so
|
||||
load-module module-esound-protocol-unix
|
||||
.endif
|
||||
load-module module-native-protocol-unix
|
||||
|
||||
### Network access (may be configured with paprefs, so leave this commented
|
||||
### here if you plan to use paprefs)
|
||||
#load-module module-esound-protocol-tcp
|
||||
#load-module module-native-protocol-tcp
|
||||
#load-module module-zeroconf-publish
|
||||
|
||||
### Load the RTP receiver module (also configured via paprefs, see above)
|
||||
#load-module module-rtp-recv
|
||||
|
||||
### Load the RTP sender module (also configured via paprefs, see above)
|
||||
#load-module module-null-sink sink_name=rtp format=s16be channels=2 rate=44100 sink_properties="device.description='RTP Multicast Sink'"
|
||||
#load-module module-rtp-send source=rtp.monitor
|
||||
|
||||
### Load additional modules from GConf settings. This can be configured with the paprefs tool.
|
||||
### Please keep in mind that the modules configured by paprefs might conflict with manually
|
||||
### loaded modules.
|
||||
.ifexists module-gconf.so
|
||||
.nofail
|
||||
load-module module-gconf
|
||||
.fail
|
||||
.endif
|
||||
|
||||
### Automatically restore the default sink/source when changed by the user
|
||||
### during runtime
|
||||
### NOTE: This should be loaded as early as possible so that subsequent modules
|
||||
### that look up the default sink/source get the right value
|
||||
load-module module-default-device-restore
|
||||
|
||||
### Automatically move streams to the default sink if the sink they are
|
||||
### connected to dies, similar for sources
|
||||
load-module module-rescue-streams
|
||||
|
||||
### Make sure we always have a sink around, even if it is a null sink.
|
||||
load-module module-always-sink
|
||||
|
||||
### Honour intended role device property
|
||||
load-module module-intended-roles
|
||||
|
||||
### Automatically suspend sinks/sources that become idle for too long
|
||||
load-module module-suspend-on-idle
|
||||
|
||||
### If autoexit on idle is enabled we want to make sure we only quit
|
||||
### when no local session needs us anymore.
|
||||
.ifexists module-console-kit.so
|
||||
load-module module-console-kit
|
||||
.endif
|
||||
.ifexists module-systemd-login.so
|
||||
load-module module-systemd-login
|
||||
.endif
|
||||
|
||||
### Enable positioned event sounds
|
||||
load-module module-position-event-sounds
|
||||
|
||||
### Cork music/video streams when a phone stream is active
|
||||
load-module module-role-cork
|
||||
|
||||
### Modules to allow autoloading of filters (such as echo cancellation)
|
||||
### on demand. module-filter-heuristics tries to determine what filters
|
||||
### make sense, and module-filter-apply does the heavy-lifting of
|
||||
### loading modules and rerouting streams.
|
||||
load-module module-filter-heuristics
|
||||
load-module module-filter-apply
|
||||
|
||||
### Make some devices default
|
||||
#set-default-sink output
|
||||
#set-default-source input
|
||||
set-default-source alsa_input.platform-soc_sound.seeed-8ch
|
||||
set-default-sink alsa_output.platform-soc_sound.seeed-2ch
|
34
pulseaudio/pulse_config_6mic/seeed-voicecard.conf
Normal file
34
pulseaudio/pulse_config_6mic/seeed-voicecard.conf
Normal file
|
@ -0,0 +1,34 @@
|
|||
# /usr/share/pulseaudio/alsa-mixer/profile-sets/seeed-voiced.conf
|
||||
|
||||
[General]
|
||||
auto-profiles = no
|
||||
[Mapping seeed-8ch]
|
||||
device-strings = hw:%f
|
||||
channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
|
||||
exact-channels = false
|
||||
fallback = yes
|
||||
paths-input = seeed-8ch
|
||||
priority = 3
|
||||
direction = input
|
||||
[Mapping seeed-2ch]
|
||||
device-strings = hw:%f
|
||||
channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
|
||||
exact-channels = false
|
||||
exact-channels = false
|
||||
fallback = yes
|
||||
paths-output = seeed-2ch
|
||||
direction = output
|
||||
priority = 2
|
||||
[Profile output:seeed-2ch+input:seeed-8ch]
|
||||
output-mappings = seeed-2ch
|
||||
input-mappings = seeed-8ch
|
||||
priority = 100
|
||||
skip-probe = yes
|
||||
[Profile output:seeed-2ch]
|
||||
output-mappings = seeed-2ch
|
||||
priority = 4
|
||||
skip-probe = yes
|
||||
[Profile input:seeed-8ch]
|
||||
input-mappings = seeed-8ch
|
||||
priority = 5
|
||||
skip-probe = yes
|
BIN
pulseaudio/udev_rules_4mic.png
Normal file
BIN
pulseaudio/udev_rules_4mic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 192 KiB |
BIN
pulseaudio/udev_rules_6mic.png
Normal file
BIN
pulseaudio/udev_rules_6mic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 483 KiB |
|
@ -38,49 +38,13 @@
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
fragment@3 {
|
||||
target = <&sound>;
|
||||
master_overlay: __dormant__ {
|
||||
compatible = "simple-audio-card";
|
||||
simple-audio-card,format = "i2s";
|
||||
simple-audio-card,name = "seeed-voicecard";
|
||||
simple-audio-card,bitclock-master = <&dailink0_master>;
|
||||
simple-audio-card,frame-master = <&dailink0_master>;
|
||||
status = "okay";
|
||||
simple-audio-card,widgets =
|
||||
"Microphone", "Mic Jack",
|
||||
"Line", "Line In",
|
||||
"Line", "Line Out",
|
||||
"Speaker", "Speaker",
|
||||
"Headphone", "Headphone Jack";
|
||||
simple-audio-card,routing =
|
||||
"Headphone Jack", "HP_L",
|
||||
"Headphone Jack", "HP_R",
|
||||
"Speaker", "SPK_LP",
|
||||
"Speaker", "SPK_LN",
|
||||
"LINPUT1", "Mic Jack",
|
||||
"LINPUT3", "Mic Jack",
|
||||
"RINPUT1", "Mic Jack",
|
||||
"RINPUT2", "Mic Jack";
|
||||
|
||||
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&i2s>;
|
||||
};
|
||||
dailink0_master: simple-audio-card,codec {
|
||||
sound-dai = <&wm8960>;
|
||||
clocks = <&wm8960_mclk>;
|
||||
clock-names = "mclk";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fragment@4 {
|
||||
target = <&sound>;
|
||||
slave_overlay: __overlay__ {
|
||||
compatible = "simple-audio-card";
|
||||
simple-audio-card,format = "i2s";
|
||||
simple-audio-card,name = "seeed-voicecard";
|
||||
simple-audio-card,name = "seeed-2mic-voicecard";
|
||||
status = "okay";
|
||||
simple-audio-card,widgets =
|
||||
"Microphone", "Mic Jack",
|
||||
|
@ -114,8 +78,7 @@
|
|||
};
|
||||
|
||||
__overrides__ {
|
||||
alsaname = <&master_overlay>,"simple-audio-card,name",
|
||||
<&slave_overlay>,"simple-audio-card,name";
|
||||
alsaname = <&slave_overlay>,"simple-audio-card,name";
|
||||
compatible = <&wm8960>,"compatible";
|
||||
master = <0>,"=2!3";
|
||||
};
|
BIN
seeed-2mic-voicecard.dtbo
Normal file
BIN
seeed-2mic-voicecard.dtbo
Normal file
Binary file not shown.
75
seeed-4mic-voicecard-overlay.dts
Normal file
75
seeed-4mic-voicecard-overlay.dts
Normal file
|
@ -0,0 +1,75 @@
|
|||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/ {
|
||||
compatible = "brcm,bcm2708";
|
||||
|
||||
fragment@0 {
|
||||
target = <&i2s>;
|
||||
__overlay__ {
|
||||
#sound-dai-cells = <0>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
fragment@1 {
|
||||
target-path = "/";
|
||||
__overlay__ {
|
||||
ac108_mclk: codec-mclk {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <24000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fragment@2 {
|
||||
target = <&i2c1>;
|
||||
__overlay__ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
|
||||
ac108_a: ac108@3b{
|
||||
compatible = "x-power,ac108_0";
|
||||
reg = <0x3b>;
|
||||
#sound-dai-cells = <0>;
|
||||
data-protocol = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
fragment@3 {
|
||||
target = <&sound>;
|
||||
|
||||
sound_overlay: __overlay__ {
|
||||
compatible = "seeed-voicecard";
|
||||
seeed-voice-card,format = "dsp_a";
|
||||
seeed-voice-card,name = "seeed-4mic-voicecard";
|
||||
status = "okay";
|
||||
|
||||
seeed-voice-card,bitclock-master = <&codec_dai>;
|
||||
seeed-voice-card,frame-master = <&codec_dai>;
|
||||
seeed-voice-card,channels-playback-override = <4>;
|
||||
seeed-voice-card,channels-capture-override = <4>;
|
||||
|
||||
cpu_dai: seeed-voice-card,cpu {
|
||||
sound-dai = <&i2s>;
|
||||
dai-tdm-slot-num = <2>;
|
||||
dai-tdm-slot-width = <32>;
|
||||
dai-tdm-slot-tx-mask = <1 1 0 0>;
|
||||
dai-tdm-slot-rx-mask = <1 1 0 0>;
|
||||
};
|
||||
codec_dai: seeed-voice-card,codec {
|
||||
sound-dai = <&ac108_a>;
|
||||
clocks = <&ac108_mclk>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
__overrides__ {
|
||||
card-name = <&sound_overlay>,"seeed-voice-card,name";
|
||||
};
|
||||
};
|
||||
|
BIN
seeed-4mic-voicecard.dtbo
Normal file
BIN
seeed-4mic-voicecard.dtbo
Normal file
Binary file not shown.
118
seeed-8mic-voicecard-overlay.dts
Normal file
118
seeed-8mic-voicecard-overlay.dts
Normal file
|
@ -0,0 +1,118 @@
|
|||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/ {
|
||||
compatible = "brcm,bcm2708";
|
||||
|
||||
fragment@0 {
|
||||
target = <&i2s>;
|
||||
__overlay__ {
|
||||
#sound-dai-cells = <0>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
fragment@1 {
|
||||
target-path = "/";
|
||||
__overlay__ {
|
||||
ac10x_mclk: codec-mclk {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <24000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fragment@2 {
|
||||
target = <&gpio>;
|
||||
__overlay__ {
|
||||
spk_amp_pins: spk_pins {
|
||||
brcm,pins = <17 22>;
|
||||
brcm,function = <1 0>; /* out in */
|
||||
brcm,pull = <0 0>; /* - - */
|
||||
};
|
||||
gpclk0_pins: gpclk0_pins {
|
||||
brcm,pins = <4>;
|
||||
brcm,function = <4>; /* alt func 0 */
|
||||
brcm,pull = <0>; /* - */
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fragment@3 {
|
||||
target = <&i2c1>;
|
||||
__overlay__ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
|
||||
ac101: ac101@1a{
|
||||
compatible = "x-power,ac101";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spk_amp_pins &gpclk0_pins>;
|
||||
spk-amp-switch-gpios = <&gpio 17 0>;
|
||||
switch-irq-gpios = <&gpio 22 0>;
|
||||
reg = <0x1a>;
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
||||
|
||||
ac108_a: ac108@35{
|
||||
compatible = "x-power,ac108_0";
|
||||
reg = <0x35>;
|
||||
#sound-dai-cells = <0>;
|
||||
data-protocol = <0>;
|
||||
tdm-chips-count = <2>;
|
||||
};
|
||||
|
||||
ac108_b: ac108@3b{
|
||||
compatible = "x-power,ac108_1";
|
||||
reg = <0x3b>;
|
||||
#sound-dai-cells = <0>;
|
||||
data-protocol = <0>;
|
||||
tdm-chips-count = <2>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fragment@4 {
|
||||
target = <&sound>;
|
||||
|
||||
sound_overlay: __overlay__ {
|
||||
compatible = "seeed-voicecard";
|
||||
seeed-voice-card,name = "seeed-8mic-voicecard";
|
||||
seeed-voice-card,channels-playback-override = <8>;
|
||||
seeed-voice-card,channels-capture-override = <8>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
|
||||
seeed-voice-card,dai-link@0 {
|
||||
format = "dsp_a";
|
||||
bitclock-master = <&codec0_dai>;
|
||||
frame-master = <&codec0_dai>;
|
||||
/* bitclock-inversion; */
|
||||
/* frame-inversion; */
|
||||
reg = <0>;
|
||||
|
||||
cpu {
|
||||
sound-dai = <&i2s>;
|
||||
dai-tdm-slot-num = <2>;
|
||||
dai-tdm-slot-width = <32>;
|
||||
dai-tdm-slot-tx-mask = <1 1 0 0>;
|
||||
dai-tdm-slot-rx-mask = <1 1 0 0>;
|
||||
};
|
||||
|
||||
codec0_dai: codec {
|
||||
sound-dai = <&ac108_a>;
|
||||
clocks = <&ac10x_mclk>;
|
||||
system-clock-id = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
__overrides__ {
|
||||
card-name = <&sound_overlay>,"seeed-voice-card,name";
|
||||
};
|
||||
};
|
||||
|
BIN
seeed-8mic-voicecard.dtbo
Normal file
BIN
seeed-8mic-voicecard.dtbo
Normal file
Binary file not shown.
163
seeed-voicecard
Executable file
163
seeed-voicecard
Executable file
|
@ -0,0 +1,163 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2018 Baozhu Zuo <zuobaozhu@gmail.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
set -x
|
||||
#exec 1>/var/log/$(basename $0).log 2>&1
|
||||
|
||||
export PATH=$PATH:/opt/vc/bin
|
||||
OVERLAYS=/boot/overlays
|
||||
[ -d /boot/firmware/overlays ] && OVERLAYS=/boot/firmware/overlays
|
||||
|
||||
#enable i2c interface
|
||||
dtparam -d $OVERLAYS i2c_arm=on
|
||||
modprobe i2c-dev
|
||||
|
||||
#enable spi interface
|
||||
dtparam -d $OVERLAYS spi=on
|
||||
|
||||
_VER_RUN=
|
||||
function get_kernel_version() {
|
||||
local ZIMAGE IMG_OFFSET
|
||||
|
||||
_VER_RUN=""
|
||||
[ -z "$_VER_RUN" ] && {
|
||||
ZIMAGE=/boot/kernel.img
|
||||
IMG_OFFSET=$(LC_ALL=C grep -abo $'\x1f\x8b\x08\x00' $ZIMAGE | head -n 1 | cut -d ':' -f 1)
|
||||
# 64-bit-only kernel package
|
||||
[ ! -f /boot/kernel.img ] && [ -f /boot/kernel8.img ] && ZIMAGE=/boot/kernel8.img
|
||||
_VER_RUN=$(dd if=$ZIMAGE obs=64K ibs=4 skip=$(( IMG_OFFSET / 4)) 2>/dev/null | zcat | grep -a -m1 "Linux version" | LC_ALL=C sed -e 's/^.*Linux/Linux/' | strings | awk '{ print $3; }')
|
||||
}
|
||||
echo "$_VER_RUN"
|
||||
return 0
|
||||
}
|
||||
|
||||
CONFIG=/boot/config.txt
|
||||
[ -f /boot/firmware/usercfg.txt ] && CONFIG=/boot/firmware/usercfg.txt
|
||||
|
||||
get_overlay() {
|
||||
ov=$1
|
||||
if grep -q -E "^dtoverlay=$ov" $CONFIG; then
|
||||
echo 0
|
||||
else
|
||||
echo 1
|
||||
fi
|
||||
}
|
||||
|
||||
do_overlay() {
|
||||
ov=$1
|
||||
RET=$2
|
||||
DEFAULT=--defaultno
|
||||
CURRENT=0
|
||||
if [ $(get_overlay $ov) -eq 0 ]; then
|
||||
DEFAULT=
|
||||
CURRENT=1
|
||||
fi
|
||||
if [ $RET -eq $CURRENT ]; then
|
||||
ASK_TO_REBOOT=1
|
||||
fi
|
||||
if [ $RET -eq 0 ]; then
|
||||
sed $CONFIG -i -e "s/^#dtoverlay=$ov/dtoverlay=$ov/"
|
||||
if ! grep -q -E "^dtoverlay=$ov" $CONFIG; then
|
||||
printf "dtoverlay=$ov\n" >> $CONFIG
|
||||
fi
|
||||
STATUS=enabled
|
||||
elif [ $RET -eq 1 ]; then
|
||||
sed $CONFIG -i -e "s/^dtoverlay=$ov/#dtoverlay=$ov/"
|
||||
STATUS=disabled
|
||||
else
|
||||
return $RET
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
is_1a=$(i2cdetect -y 1 0x1a 0x1a | egrep "(1a|UU)" | awk '{print $2}')
|
||||
is_35=$(i2cdetect -y 1 0x35 0x35 | egrep "(35|UU)" | awk '{print $2}')
|
||||
is_3b=$(i2cdetect -y 1 0x3b 0x3b | egrep "(3b|UU)" | awk '{print $2}')
|
||||
|
||||
RPI_HATS="seeed-2mic-voicecard seeed-4mic-voicecard seeed-8mic-voicecard"
|
||||
overlay=""
|
||||
|
||||
if [ "x${is_1a}" != "x" ] && [ "x${is_35}" == "x" ] ; then
|
||||
echo "install 2mic"
|
||||
overlay=seeed-2mic-voicecard
|
||||
asound_conf=/etc/voicecard/asound_2mic.conf
|
||||
asound_state=/etc/voicecard/wm8960_asound.state
|
||||
fi
|
||||
|
||||
if [ "x${is_3b}" != "x" ] && [ "x${is_35}" == "x" ] ; then
|
||||
echo "install 4mic"
|
||||
overlay=seeed-4mic-voicecard
|
||||
asound_conf=/etc/voicecard/asound_4mic.conf
|
||||
asound_state=/etc/voicecard/ac108_asound.state
|
||||
fi
|
||||
|
||||
if [ "x${is_3b}" != "x" ] && [ "x${is_35}" != "x" ] ; then
|
||||
echo "install 6mic"
|
||||
overlay=seeed-8mic-voicecard
|
||||
asound_conf=/etc/voicecard/asound_6mic.conf
|
||||
asound_state=/etc/voicecard/ac108_6mic.state
|
||||
fi
|
||||
|
||||
if [ "$overlay" ]; then
|
||||
echo Install $overlay ...
|
||||
|
||||
# Remove old configuration
|
||||
rm /etc/asound.conf
|
||||
rm /var/lib/alsa/asound.state
|
||||
|
||||
kernel_ver=$(uname -r) # get_kernel_version)
|
||||
# echo kernel_ver=$kernel_ver
|
||||
|
||||
# TODO: dynamic dtoverlay Bug of v4.19.x
|
||||
# no DT node phandle inserted.
|
||||
if [[ "$kernel_ver" =~ ^4\.19.*$ || "$kernel_ver" =~ ^5\.*$ ]]; then
|
||||
for i in $RPI_HATS; do
|
||||
if [ "$i" == "$overlay" ]; then
|
||||
/bin/true #do_overlay $overlay 0
|
||||
else
|
||||
echo Uninstall $i ...
|
||||
/bin/true #do_overlay $i 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
#make sure the driver loads correctly
|
||||
dtoverlay -d $OVERLAYS $overlay || true
|
||||
|
||||
|
||||
echo "create $overlay asound configure file"
|
||||
ln -s $asound_conf /etc/asound.conf
|
||||
echo "create $overlay asound status file"
|
||||
ln -s $asound_state /var/lib/alsa/asound.state
|
||||
fi
|
||||
|
||||
alsactl restore
|
||||
|
||||
#Force 3.5mm ('headphone') jack
|
||||
# The Raspberry Pi 4, released on 24th Jun 2019, has two HDMI ports,
|
||||
# and can drive two displays with audios for two users simultaneously,
|
||||
# in a "multiseat" configuration. The earlier single virtual ALSA
|
||||
# option for re-directing audio playback between headphone jack and HDMI
|
||||
# via a 'Routing' mixer setting was turned off eventually to allow
|
||||
# simultaneous usage of all 3 playback devices.
|
||||
if aplay -l | grep -q "bcm2835 ALSA"; then
|
||||
amixer cset numid=3 1 || true
|
||||
fi
|
926
seeed-voicecard.c
Normal file
926
seeed-voicecard.c
Normal file
|
@ -0,0 +1,926 @@
|
|||
/*
|
||||
* SEEED voice card
|
||||
*
|
||||
* (C) Copyright 2017-2018
|
||||
* Seeed Technology Co., Ltd. <www.seeedstudio.com>
|
||||
*
|
||||
* base on ASoC simple sound card support
|
||||
*
|
||||
* Copyright (C) 2012 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
/* #undef DEBUG */
|
||||
#include <linux/version.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/string.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dai.h>
|
||||
#include <sound/simple_card_utils.h>
|
||||
#include "ac10x.h"
|
||||
|
||||
#define LINUX_VERSION_IS_GEQ(x1,x2,x3) (LINUX_VERSION_CODE >= KERNEL_VERSION(x1,x2,x3))
|
||||
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,13,0)
|
||||
#define asoc_simple_parse_clk_cpu(dev, node, dai_link, simple_dai) \
|
||||
asoc_simple_parse_clk(dev, node, simple_dai, dai_link->cpus)
|
||||
#define asoc_simple_parse_clk_codec(dev, node, dai_link, simple_dai) \
|
||||
asoc_simple_parse_clk(dev, node, simple_dai, dai_link->codecs)
|
||||
#define asoc_simple_parse_cpu(node, dai_link, is_single_link) \
|
||||
asoc_simple_parse_dai(node, dai_link->cpus, is_single_link)
|
||||
#define asoc_simple_parse_codec(node, dai_link) \
|
||||
asoc_simple_parse_dai(node, dai_link->codecs, NULL)
|
||||
#define asoc_simple_parse_platform(node, dai_link) \
|
||||
asoc_simple_parse_dai(node, dai_link->platforms, NULL)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* single codec:
|
||||
* 0 - allow multi codec
|
||||
* 1 - yes
|
||||
*/
|
||||
#define _SINGLE_CODEC 1
|
||||
|
||||
struct seeed_card_data {
|
||||
struct snd_soc_card snd_card;
|
||||
struct seeed_dai_props {
|
||||
struct asoc_simple_dai cpu_dai;
|
||||
struct asoc_simple_dai codec_dai;
|
||||
struct snd_soc_dai_link_component cpus; /* single cpu */
|
||||
struct snd_soc_dai_link_component codecs; /* single codec */
|
||||
struct snd_soc_dai_link_component platforms;
|
||||
unsigned int mclk_fs;
|
||||
} *dai_props;
|
||||
unsigned int mclk_fs;
|
||||
unsigned channels_playback_default;
|
||||
unsigned channels_playback_override;
|
||||
unsigned channels_capture_default;
|
||||
unsigned channels_capture_override;
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
#if CONFIG_AC10X_TRIG_LOCK
|
||||
spinlock_t lock;
|
||||
#endif
|
||||
struct work_struct work_codec_clk;
|
||||
#define TRY_STOP_MAX 3
|
||||
int try_stop;
|
||||
};
|
||||
|
||||
struct seeed_card_info {
|
||||
const char *name;
|
||||
const char *card;
|
||||
const char *codec;
|
||||
const char *platform;
|
||||
|
||||
unsigned int daifmt;
|
||||
struct asoc_simple_dai cpu_dai;
|
||||
struct asoc_simple_dai codec_dai;
|
||||
};
|
||||
|
||||
#define seeed_priv_to_card(priv) (&(priv)->snd_card)
|
||||
#define seeed_priv_to_dev(priv) ((priv)->snd_card.dev)
|
||||
#define seeed_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
|
||||
#define seeed_priv_to_props(priv, i) ((priv)->dai_props + (i))
|
||||
|
||||
#define DAI "sound-dai"
|
||||
#define CELL "#sound-dai-cells"
|
||||
#define PREFIX "seeed-voice-card,"
|
||||
|
||||
static int seeed_voice_card_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct seeed_dai_props *dai_props =
|
||||
seeed_priv_to_props(priv, rtd->num);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(dai_props->cpu_dai.clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(dai_props->codec_dai.clk);
|
||||
if (ret)
|
||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||
|
||||
if (asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min) {
|
||||
priv->channels_playback_default = asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min;
|
||||
}
|
||||
if (asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min) {
|
||||
priv->channels_capture_default = asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min;
|
||||
}
|
||||
asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_override;
|
||||
asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_override;
|
||||
asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_override;
|
||||
asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_override;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void seeed_voice_card_shutdown(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct seeed_dai_props *dai_props =
|
||||
seeed_priv_to_props(priv, rtd->num);
|
||||
|
||||
asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_default;
|
||||
asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_default;
|
||||
asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_default;
|
||||
asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_default;
|
||||
|
||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||
|
||||
clk_disable_unprepare(dai_props->codec_dai.clk);
|
||||
}
|
||||
|
||||
static int seeed_voice_card_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
|
||||
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct seeed_dai_props *dai_props =
|
||||
seeed_priv_to_props(priv, rtd->num);
|
||||
unsigned int mclk, mclk_fs = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (priv->mclk_fs)
|
||||
mclk_fs = priv->mclk_fs;
|
||||
else if (dai_props->mclk_fs)
|
||||
mclk_fs = dai_props->mclk_fs;
|
||||
|
||||
if (mclk_fs) {
|
||||
mclk = params_rate(params) * mclk_fs;
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
|
||||
SND_SOC_CLOCK_IN);
|
||||
if (ret && ret != -ENOTSUPP)
|
||||
goto err;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
|
||||
SND_SOC_CLOCK_OUT);
|
||||
if (ret && ret != -ENOTSUPP)
|
||||
goto err;
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define _SET_CLOCK_CNT 2
|
||||
static int (* _set_clock[_SET_CLOCK_CNT])(int y_start_n_stop, struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai);
|
||||
|
||||
int seeed_voice_card_register_set_clock(int stream, int (*set_clock)(int, struct snd_pcm_substream *, int, struct snd_soc_dai *)) {
|
||||
if (! _set_clock[stream]) {
|
||||
_set_clock[stream] = set_clock;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(seeed_voice_card_register_set_clock);
|
||||
|
||||
/*
|
||||
* work_cb_codec_clk: clear audio codec inner clock.
|
||||
*/
|
||||
static void work_cb_codec_clk(struct work_struct *work)
|
||||
{
|
||||
struct seeed_card_data *priv = container_of(work, struct seeed_card_data, work_codec_clk);
|
||||
int r = 0;
|
||||
|
||||
if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) {
|
||||
r = r || _set_clock[SNDRV_PCM_STREAM_CAPTURE](0, NULL, 0, NULL); /* not using 2nd to 4th arg if 1st == 0 */
|
||||
}
|
||||
if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) {
|
||||
r = r || _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0, NULL, 0, NULL); /* not using 2nd to 4th arg if 1st == 0 */
|
||||
}
|
||||
|
||||
if (r && priv->try_stop++ < TRY_STOP_MAX) {
|
||||
if (0 != schedule_work(&priv->work_codec_clk)) {}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
#if CONFIG_AC10X_TRIG_LOCK
|
||||
unsigned long flags;
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d\n",
|
||||
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||
dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active, dai->stream[SNDRV_PCM_STREAM_CAPTURE].active);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
if (cancel_work_sync(&priv->work_codec_clk) != 0) {}
|
||||
#if CONFIG_AC10X_TRIG_LOCK
|
||||
/* I know it will degrades performance, but I have no choice */
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
#endif
|
||||
// if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](1, substream, cmd, dai);
|
||||
// if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](1, substream, cmd, dai);
|
||||
#if CONFIG_AC10X_TRIG_LOCK
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
/* capture channel resync, if overrun */
|
||||
if (dai->stream[SNDRV_PCM_STREAM_CAPTURE].active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* interrupt environment */
|
||||
if (in_irq() || in_nmi() || in_serving_softirq()) {
|
||||
priv->try_stop = 0;
|
||||
if (0 != schedule_work(&priv->work_codec_clk)) {
|
||||
}
|
||||
} else {
|
||||
// if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](0, NULL, 0, NULL); /* not using 2nd to 4th arg if 1st == 0 */
|
||||
// if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0, NULL, 0, NULL); /* not using 2nd to 4th arg if 1st == 0 */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d;finished %d\n",
|
||||
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||
dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active, dai->stream[SNDRV_PCM_STREAM_CAPTURE].active, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops seeed_voice_card_ops = {
|
||||
.startup = seeed_voice_card_startup,
|
||||
.shutdown = seeed_voice_card_shutdown,
|
||||
.hw_params = seeed_voice_card_hw_params,
|
||||
.trigger = seeed_voice_card_trigger,
|
||||
};
|
||||
|
||||
static int asoc_simple_parse_dai(struct device_node *node,
|
||||
struct snd_soc_dai_link_component *dlc,
|
||||
int *is_single_link)
|
||||
{
|
||||
struct of_phandle_args args;
|
||||
int ret;
|
||||
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Get node via "sound-dai = <&phandle port>"
|
||||
* it will be used as xxx_of_node on soc_bind_dai_link()
|
||||
*/
|
||||
ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* 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, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dlc->of_node = args.np;
|
||||
|
||||
if (is_single_link)
|
||||
*is_single_link = !args.args_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asoc_simple_init_dai(struct snd_soc_dai *dai,
|
||||
struct asoc_simple_dai *simple_dai)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!simple_dai)
|
||||
return 0;
|
||||
|
||||
if (simple_dai->sysclk) {
|
||||
ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
|
||||
simple_dai->clk_direction);
|
||||
if (ret && ret != -ENOTSUPP) {
|
||||
dev_err(dai->dev, "simple-card: set_sysclk error\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (simple_dai->slots) {
|
||||
ret = snd_soc_dai_set_bclk_ratio(dai,
|
||||
simple_dai->slots *
|
||||
simple_dai->slot_width);
|
||||
if (ret && ret != -ENOTSUPP) {
|
||||
dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
|
||||
static inline int asoc_simple_component_is_codec(struct snd_soc_component *component)
|
||||
{
|
||||
return component->driver->endianness;
|
||||
}
|
||||
|
||||
static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai_link *dai_link = rtd->dai_link;
|
||||
struct snd_soc_component *component;
|
||||
struct snd_soc_pcm_stream *params;
|
||||
struct snd_pcm_hardware hw;
|
||||
int i, ret, stream;
|
||||
|
||||
/* Only Codecs */
|
||||
for_each_rtd_components(rtd, i, component) {
|
||||
if (!asoc_simple_component_is_codec(component))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assumes the capabilities are the same for all supported streams */
|
||||
for (stream = 0; stream < 2; stream++) {
|
||||
ret = snd_soc_runtime_calc_hw(rtd, &hw, stream);
|
||||
if (ret == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "simple-card: no valid dai_link params\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
params = devm_kzalloc(rtd->dev, sizeof(*params), GFP_KERNEL);
|
||||
if (!params)
|
||||
return -ENOMEM;
|
||||
|
||||
params->formats = hw.formats;
|
||||
params->rates = hw.rates;
|
||||
params->rate_min = hw.rate_min;
|
||||
params->rate_max = hw.rate_max;
|
||||
params->channels_min = hw.channels_min;
|
||||
params->channels_max = hw.channels_max;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,4,0)
|
||||
dai_link->c2c_params = params;
|
||||
dai_link->num_c2c_params = 1;
|
||||
#else
|
||||
/* apparently this goes back to 5.6.x */
|
||||
dai_link->params = params;
|
||||
dai_link->num_params = 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int seeed_voice_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_dai *codec = asoc_rtd_to_codec(rtd, 0);
|
||||
struct snd_soc_dai *cpu = asoc_rtd_to_cpu(rtd, 0);
|
||||
struct seeed_dai_props *dai_props =
|
||||
seeed_priv_to_props(priv, rtd->num);
|
||||
int ret;
|
||||
|
||||
ret = asoc_simple_init_dai(codec, &dai_props->codec_dai);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = asoc_simple_init_dai(cpu, &dai_props->cpu_dai);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
|
||||
ret = asoc_simple_init_dai_link_params(rtd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
dev_dbg(rtd->card->dev, "codec \"%s\" mapping to cpu \"%s\"\n", codec->name, cpu->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||
struct seeed_card_data *priv,
|
||||
int idx,
|
||||
bool is_top_level_node)
|
||||
{
|
||||
struct device *dev = seeed_priv_to_dev(priv);
|
||||
struct snd_soc_dai_link *dai_link = seeed_priv_to_link(priv, idx);
|
||||
struct seeed_dai_props *dai_props = seeed_priv_to_props(priv, idx);
|
||||
struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
|
||||
struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
|
||||
struct device_node *cpu = NULL;
|
||||
struct device_node *plat = NULL;
|
||||
struct device_node *codec = NULL;
|
||||
char prop[128];
|
||||
char *prefix = "";
|
||||
int ret, single_cpu;
|
||||
|
||||
/* For single DAI link & old style of DT node */
|
||||
if (is_top_level_node)
|
||||
prefix = PREFIX;
|
||||
|
||||
snprintf(prop, sizeof(prop), "%scpu", prefix);
|
||||
cpu = of_get_child_by_name(node, prop);
|
||||
|
||||
if (!cpu) {
|
||||
ret = -EINVAL;
|
||||
dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
|
||||
goto dai_link_of_err;
|
||||
}
|
||||
|
||||
snprintf(prop, sizeof(prop), "%splat", prefix);
|
||||
plat = of_get_child_by_name(node, prop);
|
||||
|
||||
snprintf(prop, sizeof(prop), "%scodec", prefix);
|
||||
codec = of_get_child_by_name(node, prop);
|
||||
|
||||
if (!codec) {
|
||||
ret = -EINVAL;
|
||||
dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
|
||||
goto dai_link_of_err;
|
||||
}
|
||||
|
||||
ret = asoc_simple_parse_daifmt(dev, node, codec,
|
||||
prefix, &dai_link->dai_fmt);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
|
||||
|
||||
ret = asoc_simple_parse_cpu(cpu, dai_link, &single_cpu);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
#if _SINGLE_CODEC
|
||||
ret = asoc_simple_parse_codec(codec, dai_link);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
#else
|
||||
ret = snd_soc_of_get_dai_link_codecs(dev, codec, dai_link);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "parse codec info error %d\n", ret);
|
||||
goto dai_link_of_err;
|
||||
}
|
||||
dev_dbg(dev, "dai_link num_codecs = %d\n", dai_link->num_codecs);
|
||||
#endif
|
||||
|
||||
ret = asoc_simple_parse_platform(plat, dai_link);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
ret = snd_soc_of_parse_tdm_slot(cpu, &cpu_dai->tx_slot_mask,
|
||||
&cpu_dai->rx_slot_mask,
|
||||
&cpu_dai->slots,
|
||||
&cpu_dai->slot_width);
|
||||
dev_dbg(dev, "cpu_dai : slot,width,tx,rx = %d,%d,%d,%d\n",
|
||||
cpu_dai->slots, cpu_dai->slot_width,
|
||||
cpu_dai->tx_slot_mask, cpu_dai->rx_slot_mask
|
||||
);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
ret = snd_soc_of_parse_tdm_slot(codec, &codec_dai->tx_slot_mask,
|
||||
&codec_dai->rx_slot_mask,
|
||||
&codec_dai->slots,
|
||||
&codec_dai->slot_width);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
|
||||
ret = asoc_simple_card_parse_clk_cpu(cpu, dai_link, cpu_dai);
|
||||
#else
|
||||
ret = asoc_simple_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
|
||||
#endif
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
|
||||
ret = asoc_simple_card_parse_clk_codec(codec, dai_link, codec_dai);
|
||||
#else
|
||||
ret = asoc_simple_parse_clk_codec(dev, codec, dai_link, codec_dai);
|
||||
#endif
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
ret = asoc_simple_set_dailink_name(dev, dai_link,
|
||||
"%s-%s",
|
||||
dai_link->cpus->dai_name,
|
||||
#if _SINGLE_CODEC
|
||||
dai_link->codecs->dai_name
|
||||
#else
|
||||
dai_link->codecs[0].dai_name
|
||||
#endif
|
||||
);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
dai_link->ops = &seeed_voice_card_ops;
|
||||
dai_link->init = seeed_voice_card_dai_init;
|
||||
|
||||
dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
|
||||
dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
|
||||
dev_dbg(dev, "\tcpu : %s / %d\n",
|
||||
dai_link->cpus->dai_name,
|
||||
dai_props->cpu_dai.sysclk);
|
||||
dev_dbg(dev, "\tcodec : %s / %d\n",
|
||||
#if _SINGLE_CODEC
|
||||
dai_link->codecs->dai_name,
|
||||
#else
|
||||
dai_link->codecs[0].dai_name,
|
||||
#endif
|
||||
dai_props->codec_dai.sysclk);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,13,0)
|
||||
asoc_simple_canonicalize_cpu(dai_link->cpus, single_cpu);
|
||||
#if _SINGLE_CODEC
|
||||
asoc_simple_canonicalize_platform(dai_link->platforms, dai_link->cpus);
|
||||
#endif
|
||||
#else
|
||||
asoc_simple_canonicalize_cpu(dai_link, single_cpu);
|
||||
#if _SINGLE_CODEC
|
||||
asoc_simple_canonicalize_platform(dai_link);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
dai_link_of_err:
|
||||
of_node_put(cpu);
|
||||
of_node_put(codec);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int seeed_voice_card_parse_aux_devs(struct device_node *node,
|
||||
struct seeed_card_data *priv)
|
||||
{
|
||||
struct device *dev = seeed_priv_to_dev(priv);
|
||||
struct device_node *aux_node;
|
||||
int i, n, len;
|
||||
|
||||
if (!of_find_property(node, PREFIX "aux-devs", &len))
|
||||
return 0; /* Ok to have no aux-devs */
|
||||
|
||||
n = len / sizeof(__be32);
|
||||
if (n <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
priv->snd_card.aux_dev = devm_kzalloc(dev,
|
||||
n * sizeof(*priv->snd_card.aux_dev), GFP_KERNEL);
|
||||
if (!priv->snd_card.aux_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
|
||||
if (!aux_node)
|
||||
return -EINVAL;
|
||||
priv->snd_card.aux_dev[i].dlc.of_node = aux_node;
|
||||
}
|
||||
|
||||
priv->snd_card.num_aux_devs = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int seeed_voice_card_parse_of(struct device_node *node,
|
||||
struct seeed_card_data *priv)
|
||||
{
|
||||
struct device *dev = seeed_priv_to_dev(priv);
|
||||
struct device_node *dai_link;
|
||||
int ret;
|
||||
|
||||
if (!node)
|
||||
return -EINVAL;
|
||||
|
||||
dai_link = of_get_child_by_name(node, PREFIX "dai-link");
|
||||
|
||||
/* The off-codec widgets */
|
||||
if (of_property_read_bool(node, PREFIX "widgets")) {
|
||||
ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
|
||||
PREFIX "widgets");
|
||||
if (ret)
|
||||
goto card_parse_end;
|
||||
}
|
||||
|
||||
/* DAPM routes */
|
||||
if (of_property_read_bool(node, PREFIX "routing")) {
|
||||
ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
|
||||
PREFIX "routing");
|
||||
if (ret)
|
||||
goto card_parse_end;
|
||||
}
|
||||
|
||||
/* Factor to mclk, used in hw_params() */
|
||||
of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
|
||||
|
||||
/* Single/Muti DAI link(s) & New style of DT node */
|
||||
if (dai_link) {
|
||||
struct device_node *np = NULL;
|
||||
int i = 0;
|
||||
|
||||
for_each_child_of_node(node, np) {
|
||||
dev_dbg(dev, "\tlink %d:\n", i);
|
||||
ret = seeed_voice_card_dai_link_of(np, priv,
|
||||
i, false);
|
||||
if (ret < 0) {
|
||||
of_node_put(np);
|
||||
goto card_parse_end;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
/* For single DAI link & old style of DT node */
|
||||
ret = seeed_voice_card_dai_link_of(node, priv, 0, true);
|
||||
if (ret < 0)
|
||||
goto card_parse_end;
|
||||
}
|
||||
|
||||
ret = asoc_simple_parse_card_name(&priv->snd_card, PREFIX);
|
||||
if (ret < 0)
|
||||
goto card_parse_end;
|
||||
|
||||
ret = seeed_voice_card_parse_aux_devs(node, priv);
|
||||
|
||||
priv->channels_playback_default = 0;
|
||||
priv->channels_playback_override = 2;
|
||||
priv->channels_capture_default = 0;
|
||||
priv->channels_capture_override = 2;
|
||||
of_property_read_u32(node, PREFIX "channels-playback-default",
|
||||
&priv->channels_playback_default);
|
||||
of_property_read_u32(node, PREFIX "channels-playback-override",
|
||||
&priv->channels_playback_override);
|
||||
of_property_read_u32(node, PREFIX "channels-capture-default",
|
||||
&priv->channels_capture_default);
|
||||
of_property_read_u32(node, PREFIX "channels-capture-override",
|
||||
&priv->channels_capture_override);
|
||||
|
||||
card_parse_end:
|
||||
of_node_put(dai_link);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
inline void seeed_debug_dai(struct seeed_card_data *priv,
|
||||
char *name,
|
||||
struct asoc_simple_dai *dai)
|
||||
{
|
||||
struct device *dev = seeed_priv_to_dev(priv);
|
||||
|
||||
if (dai->name)
|
||||
dev_dbg(dev, "%s dai name = %s\n",
|
||||
name, dai->name);
|
||||
if (dai->sysclk)
|
||||
dev_dbg(dev, "%s sysclk = %d\n",
|
||||
name, dai->sysclk);
|
||||
|
||||
dev_dbg(dev, "%s direction = %s\n",
|
||||
name, dai->clk_direction ? "OUT" : "IN");
|
||||
|
||||
if (dai->slots)
|
||||
dev_dbg(dev, "%s slots = %d\n", name, dai->slots);
|
||||
if (dai->slot_width)
|
||||
dev_dbg(dev, "%s slot width = %d\n", name, dai->slot_width);
|
||||
if (dai->tx_slot_mask)
|
||||
dev_dbg(dev, "%s tx slot mask = %d\n", name, dai->tx_slot_mask);
|
||||
if (dai->rx_slot_mask)
|
||||
dev_dbg(dev, "%s rx slot mask = %d\n", name, dai->rx_slot_mask);
|
||||
if (dai->clk)
|
||||
dev_dbg(dev, "%s clk %luHz\n", name, clk_get_rate(dai->clk));
|
||||
}
|
||||
|
||||
inline void seeed_debug_info(struct seeed_card_data *priv)
|
||||
{
|
||||
struct snd_soc_card *card = seeed_priv_to_card(priv);
|
||||
struct device *dev = seeed_priv_to_dev(priv);
|
||||
|
||||
int i;
|
||||
|
||||
if (card->name)
|
||||
dev_dbg(dev, "Card Name: %s\n", card->name);
|
||||
|
||||
for (i = 0; i < card->num_links; i++) {
|
||||
struct seeed_dai_props *props = seeed_priv_to_props(priv, i);
|
||||
struct snd_soc_dai_link *link = seeed_priv_to_link(priv, i);
|
||||
|
||||
dev_dbg(dev, "DAI%d\n", i);
|
||||
|
||||
seeed_debug_dai(priv, "cpu", &props->cpu_dai);
|
||||
seeed_debug_dai(priv, "codec", &props->codec_dai);
|
||||
|
||||
if (link->name)
|
||||
dev_dbg(dev, "dai name = %s\n", link->name);
|
||||
|
||||
dev_dbg(dev, "dai format = %04x\n", link->dai_fmt);
|
||||
|
||||
/*
|
||||
if (props->adata.convert_rate)
|
||||
dev_dbg(dev, "convert_rate = %d\n",
|
||||
props->adata.convert_rate);
|
||||
if (props->adata.convert_channels)
|
||||
dev_dbg(dev, "convert_channels = %d\n",
|
||||
props->adata.convert_channels);
|
||||
if (props->codec_conf && props->codec_conf->name_prefix)
|
||||
dev_dbg(dev, "name prefix = %s\n",
|
||||
props->codec_conf->name_prefix);
|
||||
*/
|
||||
if (props->mclk_fs)
|
||||
dev_dbg(dev, "mclk-fs = %d\n",
|
||||
props->mclk_fs);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define seeed_debug_info(priv)
|
||||
#endif /* DEBUG */
|
||||
|
||||
static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct seeed_card_data *priv;
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
struct seeed_dai_props *dai_props;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
int num, ret, i;
|
||||
|
||||
/* Get the number of DAI links */
|
||||
if (np && of_get_child_by_name(np, PREFIX "dai-link"))
|
||||
num = of_get_child_count(np);
|
||||
else
|
||||
num = 1;
|
||||
|
||||
/* Allocate the private data and the DAI link array */
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
|
||||
dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL);
|
||||
if (!dai_props || !dai_link)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Use snd_soc_dai_link_component instead of legacy style
|
||||
* It is codec only. but cpu/platform will be supported in the future.
|
||||
* see
|
||||
* soc-core.c :: snd_soc_init_multicodec()
|
||||
*
|
||||
* "platform" might be removed
|
||||
* see
|
||||
* simple-card-utils.c :: asoc_simple_canonicalize_platform()
|
||||
*/
|
||||
for (i = 0; i < num; i++) {
|
||||
dai_link[i].cpus = &dai_props[i].cpus;
|
||||
dai_link[i].num_cpus = 1;
|
||||
dai_link[i].codecs = &dai_props[i].codecs;
|
||||
dai_link[i].num_codecs = 1;
|
||||
dai_link[i].platforms = &dai_props[i].platforms;
|
||||
dai_link[i].num_platforms = 1;
|
||||
}
|
||||
|
||||
priv->dai_props = dai_props;
|
||||
priv->dai_link = dai_link;
|
||||
|
||||
/* Init snd_soc_card */
|
||||
priv->snd_card.owner = THIS_MODULE;
|
||||
priv->snd_card.dev = dev;
|
||||
priv->snd_card.dai_link = priv->dai_link;
|
||||
priv->snd_card.num_links = num;
|
||||
|
||||
if (np && of_device_is_available(np)) {
|
||||
ret = seeed_voice_card_parse_of(np, priv);
|
||||
if (ret < 0) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "parse error %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
struct seeed_card_info *cinfo;
|
||||
struct snd_soc_dai_link_component *cpus;
|
||||
struct snd_soc_dai_link_component *codecs;
|
||||
struct snd_soc_dai_link_component *platform;
|
||||
|
||||
cinfo = dev->platform_data;
|
||||
if (!cinfo) {
|
||||
dev_err(dev, "no info for seeed-voice-card\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!cinfo->name ||
|
||||
!cinfo->codec_dai.name ||
|
||||
!cinfo->codec ||
|
||||
!cinfo->platform ||
|
||||
!cinfo->cpu_dai.name) {
|
||||
dev_err(dev, "insufficient seeed_voice_card_info settings\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpus = dai_link->cpus;
|
||||
cpus->dai_name = cinfo->cpu_dai.name;
|
||||
|
||||
codecs = dai_link->codecs;
|
||||
codecs->name = cinfo->codec;
|
||||
codecs->dai_name = cinfo->codec_dai.name;
|
||||
|
||||
platform = dai_link->platforms;
|
||||
platform->name = cinfo->platform;
|
||||
|
||||
priv->snd_card.name = (cinfo->card) ? cinfo->card : cinfo->name;
|
||||
dai_link->name = cinfo->name;
|
||||
dai_link->stream_name = cinfo->name;
|
||||
dai_link->dai_fmt = cinfo->daifmt;
|
||||
dai_link->init = seeed_voice_card_dai_init;
|
||||
memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
|
||||
sizeof(priv->dai_props->cpu_dai));
|
||||
memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
|
||||
sizeof(priv->dai_props->codec_dai));
|
||||
}
|
||||
|
||||
snd_soc_card_set_drvdata(&priv->snd_card, priv);
|
||||
|
||||
#if CONFIG_AC10X_TRIG_LOCK
|
||||
spin_lock_init(&priv->lock);
|
||||
#endif
|
||||
|
||||
INIT_WORK(&priv->work_codec_clk, work_cb_codec_clk);
|
||||
|
||||
seeed_debug_info(priv);
|
||||
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
|
||||
err:
|
||||
asoc_simple_clean_reference(&priv->snd_card);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int seeed_voice_card_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(card);
|
||||
|
||||
if (cancel_work_sync(&priv->work_codec_clk) != 0) {
|
||||
}
|
||||
asoc_simple_clean_reference(card);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id seeed_voice_of_match[] = {
|
||||
{ .compatible = "seeed-voicecard", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, seeed_voice_of_match);
|
||||
|
||||
static struct platform_driver seeed_voice_card = {
|
||||
.driver = {
|
||||
.name = "seeed-voicecard",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
.of_match_table = seeed_voice_of_match,
|
||||
},
|
||||
.probe = seeed_voice_card_probe,
|
||||
.remove = seeed_voice_card_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(seeed_voice_card);
|
||||
|
||||
MODULE_ALIAS("platform:seeed-voice-card");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("ASoC SEEED Voice Card");
|
||||
MODULE_AUTHOR("PeterYang<linsheng.yang@seeed.cc>");
|
Binary file not shown.
12
seeed-voicecard.service
Normal file
12
seeed-voicecard.service
Normal file
|
@ -0,0 +1,12 @@
|
|||
[Unit]
|
||||
Description=Seeed Voicecard service
|
||||
After=alsa-restore.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/bin/seeed-voicecard
|
||||
User=root
|
||||
|
||||
[Install]
|
||||
WantedBy=sysinit.target
|
47
sound-compatible-4.18.h
Normal file
47
sound-compatible-4.18.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* (C) Copyright 2017-2018
|
||||
* Seeed Technology Co., Ltd. <www.seeedstudio.com>
|
||||
*
|
||||
* PeterYang <linsheng.yang@seeed.cc>
|
||||
*/
|
||||
#ifndef __SOUND_COMPATIBLE_4_18_H__
|
||||
#define __SOUND_COMPATIBLE_4_18_H__
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
|
||||
#define __NO_SND_SOC_CODEC_DRV 1
|
||||
#else
|
||||
#define __NO_SND_SOC_CODEC_DRV 0
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
|
||||
#if __has_attribute(__fallthrough__)
|
||||
# define fallthrough __attribute__((__fallthrough__))
|
||||
#else
|
||||
# define fallthrough do {} while (0) /* fallthrough */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __NO_SND_SOC_CODEC_DRV
|
||||
#define codec component
|
||||
#define snd_soc_codec snd_soc_component
|
||||
#define snd_soc_codec_driver snd_soc_component_driver
|
||||
#define snd_soc_codec_get_drvdata snd_soc_component_get_drvdata
|
||||
#define snd_soc_codec_get_dapm snd_soc_component_get_dapm
|
||||
#define snd_soc_codec_get_bias_level snd_soc_component_get_bias_level
|
||||
#define snd_soc_kcontrol_codec snd_soc_kcontrol_component
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
|
||||
#define snd_soc_read snd_soc_component_read
|
||||
#else
|
||||
#define snd_soc_read snd_soc_component_read32
|
||||
#endif
|
||||
#define snd_soc_register_codec devm_snd_soc_register_component
|
||||
#define snd_soc_unregister_codec snd_soc_unregister_component
|
||||
#define snd_soc_update_bits snd_soc_component_update_bits
|
||||
#define snd_soc_write snd_soc_component_write
|
||||
#define snd_soc_add_codec_controls snd_soc_add_component_controls
|
||||
#endif
|
||||
|
||||
#endif//__SOUND_COMPATIBLE_4_18_H__
|
||||
|
44
tools/coherence.py
Normal file
44
tools/coherence.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
"""
|
||||
Estimate the magnitude squared coherence estimate,
|
||||
|
||||
- requirements
|
||||
sudo apt install python-numpy python-scipy python-matplotlib
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import wave
|
||||
import numpy as np
|
||||
from scipy import signal
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print('Usage: python {} audio.wav'.format(sys.argv[0]))
|
||||
sys.exit(1)
|
||||
|
||||
wav = wave.open(sys.argv[1], 'rb')
|
||||
channels = wav.getnchannels()
|
||||
frames = wav.readframes(wav.getnframes())
|
||||
fs = wav.getframerate()
|
||||
wav.close()
|
||||
|
||||
print("channels: %d" % channels)
|
||||
print("rate : %d" % fs)
|
||||
print("frames : %d" % wav.getnframes())
|
||||
|
||||
array = np.fromstring(frames, dtype='int16')
|
||||
|
||||
ch0 = array[0::channels]
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
for ch in range(1, channels):
|
||||
f, c = signal.coherence(ch0, array[ch::channels], fs, nperseg=1024)
|
||||
ax.semilogy(f, c, label="CO 1-%d" % (ch + 1))
|
||||
|
||||
legend = ax.legend(loc='lower right', shadow=True, fontsize='small')
|
||||
|
||||
plt.xlabel('frequency [Hz]')
|
||||
plt.ylabel('Coherence')
|
||||
plt.show()
|
||||
|
83
tools/phase_test.py
Normal file
83
tools/phase_test.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
import sys
|
||||
import wave
|
||||
import numpy as np
|
||||
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print('Usage: {} multi.wav'.format(sys.argv[0]))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
multi = wave.open(sys.argv[1], 'rb')
|
||||
rate = multi.getframerate()
|
||||
channels = multi.getnchannels()
|
||||
|
||||
if channels <= 1:
|
||||
sys.exit(1)
|
||||
|
||||
N = rate
|
||||
|
||||
window = np.hanning(N)
|
||||
|
||||
interp = 4*8
|
||||
max_offset = int(rate * 0.1 / 340 * interp)
|
||||
|
||||
def gcc_phat(sig, refsig, fs=1, max_tau=None, interp=16):
|
||||
'''
|
||||
This function computes the offset between the signal sig and the reference signal refsig
|
||||
using the Generalized Cross Correlation - Phase Transform (GCC-PHAT)method.
|
||||
'''
|
||||
|
||||
# make sure the length for the FFT is larger or equal than len(sig) + len(refsig)
|
||||
n = sig.shape[0] + refsig.shape[0]
|
||||
|
||||
# Generalized Cross Correlation Phase Transform
|
||||
SIG = np.fft.rfft(sig, n=n)
|
||||
REFSIG = np.fft.rfft(refsig, n=n)
|
||||
R = SIG * np.conj(REFSIG)
|
||||
#R /= np.abs(R)
|
||||
|
||||
cc = np.fft.irfft(R, n=(interp * n))
|
||||
|
||||
max_shift = int(interp * n / 2)
|
||||
if max_tau:
|
||||
max_shift = np.minimum(int(interp * fs * max_tau), max_shift)
|
||||
|
||||
cc = np.concatenate((cc[-max_shift:], cc[:max_shift+1]))
|
||||
|
||||
# find max cross correlation index
|
||||
shift = np.argmax(np.abs(cc)) - max_shift
|
||||
|
||||
tau = shift / float(interp * fs)
|
||||
|
||||
return tau, cc
|
||||
|
||||
|
||||
print(multi.getsampwidth())
|
||||
|
||||
while True:
|
||||
data = multi.readframes(N)
|
||||
|
||||
if len(data) != multi.getsampwidth() * N * channels:
|
||||
print("done")
|
||||
break
|
||||
|
||||
if multi.getsampwidth() == 2:
|
||||
data = np.fromstring(data, dtype='int16')
|
||||
else:
|
||||
data = np.fromstring(data, dtype='int32')
|
||||
ref_buf = data[0::channels]
|
||||
|
||||
offsets = []
|
||||
for ch in range(1, channels):
|
||||
sig_buf = data[ch::channels]
|
||||
tau, _ = gcc_phat(sig_buf * window, ref_buf * window, fs=1, max_tau=max_offset, interp=interp)
|
||||
# tau, _ = gcc_phat(sig_buf, ref_buf, fs=rate, max_tau=1)
|
||||
|
||||
offsets.append(tau)
|
||||
|
||||
print(offsets)
|
||||
|
||||
print(multi.getframerate())
|
||||
|
||||
multi.close()
|
37
ubuntu-prerequisite.sh
Executable file
37
ubuntu-prerequisite.sh
Executable file
|
@ -0,0 +1,37 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright (c) Hin-Tak Leung 2020
|
||||
#
|
||||
# Overview:
|
||||
# This script compiles and install the Broadcom VideoCore tools,
|
||||
# configure the dynamic loader for the non-standard library location,
|
||||
# and update the loader cache.
|
||||
#
|
||||
# A few steps explicitly requires root privilege, which are
|
||||
# marked with "sudo". The rest is just checking for duplicate/previous
|
||||
# action.
|
||||
#
|
||||
# This derived from my command history on ubuntu 20.04.1 .YMMV
|
||||
|
||||
sudo apt install -y git gcc g++ make alsa-utils cmake
|
||||
|
||||
git clone git://github.com/raspberrypi/userland.git
|
||||
pushd userland/
|
||||
|
||||
arch=$(uname -m)
|
||||
if [[ "$arch" =~ aarch64 ]]; then
|
||||
./buildme --aarch64
|
||||
else
|
||||
./buildme
|
||||
fi
|
||||
# ./buildme already includes "sudo make install" at the end
|
||||
|
||||
popd
|
||||
|
||||
# matches Raspbian's location:
|
||||
if [ ! -f /etc/ld.so.conf.d/00-vmcs.conf ] ; then
|
||||
echo "/opt/vc/lib" | sudo tee -a /etc/ld.so.conf.d/00-vmcs.conf
|
||||
sudo ldconfig -v
|
||||
else
|
||||
echo "/etc/ld.so.conf.d/00-vmcs.conf exists - no need to update ld.cache!"
|
||||
fi
|
100
uninstall.sh
Executable file
100
uninstall.sh
Executable file
|
@ -0,0 +1,100 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root (use sudo)" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
is_Raspberry=$(cat /proc/device-tree/model | awk '{print $1}')
|
||||
if [ "x${is_Raspberry}" != "xRaspberry" ] ; then
|
||||
echo "Sorry, this drivers only works on raspberry pi"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
uname_r=$(uname -r)
|
||||
|
||||
CONFIG=/boot/config.txt
|
||||
[ -f /boot/firmware/config.txt ] && CONFIG=/boot/firmware/config.txt
|
||||
[ -f /boot/firmware/usercfg.txt ] && CONFIG=/boot/firmware/usercfg.txt
|
||||
|
||||
get_overlay() {
|
||||
ov=$1
|
||||
if grep -q -E "^dtoverlay=$ov" $CONFIG; then
|
||||
echo 0
|
||||
else
|
||||
echo 1
|
||||
fi
|
||||
}
|
||||
|
||||
do_overlay() {
|
||||
ov=$1
|
||||
RET=$2
|
||||
DEFAULT=--defaultno
|
||||
CURRENT=0
|
||||
if [ $(get_overlay $ov) -eq 0 ]; then
|
||||
DEFAULT=
|
||||
CURRENT=1
|
||||
fi
|
||||
if [ $RET -eq $CURRENT ]; then
|
||||
ASK_TO_REBOOT=1
|
||||
fi
|
||||
if [ $RET -eq 0 ]; then
|
||||
sed $CONFIG -i -e "s/^#dtoverlay=$ov/dtoverlay=$ov/"
|
||||
if ! grep -q -E "^dtoverlay=$ov" $CONFIG; then
|
||||
printf "dtoverlay=$ov\n" >> $CONFIG
|
||||
fi
|
||||
STATUS=enabled
|
||||
elif [ $RET -eq 1 ]; then
|
||||
sed $CONFIG -i -e "s/^dtoverlay=$ov/#dtoverlay=$ov/"
|
||||
STATUS=disabled
|
||||
else
|
||||
return $RET
|
||||
fi
|
||||
}
|
||||
|
||||
RPI_HATS="seeed-2mic-voicecard seeed-4mic-voicecard seeed-8mic-voicecard"
|
||||
|
||||
PATH=$PATH:/opt/vc/bin
|
||||
echo "remove dtbos"
|
||||
for i in $RPI_HATS; do
|
||||
dtoverlay -r $i
|
||||
done
|
||||
OVERLAYS=/boot/overlays
|
||||
[ -d /boot/firmware/overlays ] && OVERLAYS=/boot/firmware/overlays
|
||||
|
||||
rm ${OVERLAYS}/seeed-2mic-voicecard.dtbo || true
|
||||
rm ${OVERLAYS}/seeed-4mic-voicecard.dtbo || true
|
||||
rm ${OVERLAYS}/seeed-8mic-voicecard.dtbo || true
|
||||
|
||||
echo "remove alsa configs"
|
||||
rm -rf /etc/voicecard/ || true
|
||||
|
||||
echo "disabled seeed-voicecard.service "
|
||||
systemctl stop seeed-voicecard.service
|
||||
systemctl disable seeed-voicecard.service
|
||||
|
||||
echo "remove seeed-voicecard"
|
||||
rm /usr/bin/seeed-voicecard || true
|
||||
rm /lib/systemd/system/seeed-voicecard.service || true
|
||||
|
||||
echo "remove dkms"
|
||||
rm -rf /var/lib/dkms/seeed-voicecard || true
|
||||
|
||||
echo "remove kernel modules"
|
||||
rm /lib/modules/*/kernel/sound/soc/codecs/snd-soc-wm8960.ko || true
|
||||
rm /lib/modules/*/kernel/sound/soc/codecs/snd-soc-ac108.ko || true
|
||||
rm /lib/modules/*/kernel/sound/soc/bcm/snd-soc-seeed-voicecard.ko || true
|
||||
rm /lib/modules/*/updates/dkms/snd-soc-wm8960.ko || true
|
||||
rm /lib/modules/*/updates/dkms/snd-soc-ac108.ko || true
|
||||
rm /lib/modules/*/updates/dkms/snd-soc-seeed-voicecard.ko || true
|
||||
|
||||
echo "remove $CONFIG configuration"
|
||||
for i in $RPI_HATS; do
|
||||
echo Uninstall $i ...
|
||||
do_overlay $i 1
|
||||
done
|
||||
|
||||
echo "------------------------------------------------------"
|
||||
echo "Please reboot your raspberry pi to apply all settings"
|
||||
echo "Thank you!"
|
||||
echo "------------------------------------------------------"
|
29
wm8960.c
29
wm8960.c
|
@ -25,6 +25,7 @@
|
|||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/wm8960.h>
|
||||
#include "sound-compatible-4.18.h"
|
||||
|
||||
#include "wm8960.h"
|
||||
|
||||
|
@ -226,11 +227,12 @@ static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
|
|||
static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(lineinboost_tlv, -1500, 300, 1);
|
||||
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(micboost_tlv,
|
||||
static const DECLARE_TLV_DB_RANGE(micboost_tlv,
|
||||
0, 1, TLV_DB_SCALE_ITEM(0, 1300, 0),
|
||||
2, 3, TLV_DB_SCALE_ITEM(2000, 900, 0),
|
||||
);
|
||||
|
||||
|
||||
static const struct snd_kcontrol_new wm8960_snd_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,
|
||||
0, 63, 0, inpga_tlv),
|
||||
|
@ -506,7 +508,11 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
|
|||
* list each time to find the desired power state do so now
|
||||
* and save the result.
|
||||
*/
|
||||
#if __NO_SND_SOC_CODEC_DRV
|
||||
list_for_each_entry(w, &codec->card->widgets, list) {
|
||||
#else
|
||||
list_for_each_entry(w, &codec->component.card->widgets, list) {
|
||||
#endif
|
||||
if (w->dapm != dapm)
|
||||
continue;
|
||||
if (strcmp(w->name, "LOUT1 PGA") == 0)
|
||||
|
@ -747,6 +753,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
|
|||
iface |= 0x000c;
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
default:
|
||||
dev_err(codec->dev, "unsupported width %d\n",
|
||||
params_width(params));
|
||||
|
@ -789,7 +796,7 @@ static int wm8960_hw_free(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wm8960_mute(struct snd_soc_dai *dai, int mute)
|
||||
static int wm8960_mute(struct snd_soc_dai *dai, int mute, int direction)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
|
@ -1229,11 +1236,12 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
|||
static const struct snd_soc_dai_ops wm8960_dai_ops = {
|
||||
.hw_params = wm8960_hw_params,
|
||||
.hw_free = wm8960_hw_free,
|
||||
.digital_mute = wm8960_mute,
|
||||
.mute_stream = wm8960_mute,
|
||||
.set_fmt = wm8960_set_dai_fmt,
|
||||
.set_clkdiv = wm8960_set_dai_clkdiv,
|
||||
.set_pll = wm8960_set_dai_pll,
|
||||
.set_sysclk = wm8960_set_dai_sysclk,
|
||||
.no_capture_mute = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver wm8960_dai = {
|
||||
|
@ -1251,7 +1259,11 @@ static struct snd_soc_dai_driver wm8960_dai = {
|
|||
.rates = WM8960_RATES,
|
||||
.formats = WM8960_FORMATS,},
|
||||
.ops = &wm8960_dai_ops,
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0)
|
||||
.symmetric_rate = 1,
|
||||
#else
|
||||
.symmetric_rates = 1,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int wm8960_probe(struct snd_soc_codec *codec)
|
||||
|
@ -1275,6 +1287,11 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
|
|||
.probe = wm8960_probe,
|
||||
.set_bias_level = wm8960_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
#if __NO_SND_SOC_CODEC_DRV
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct regmap_config wm8960_regmap = {
|
||||
|
@ -1301,8 +1318,7 @@ static void wm8960_set_pdata_from_of(struct i2c_client *i2c,
|
|||
pdata->shared_lrclk = true;
|
||||
}
|
||||
|
||||
static int wm8960_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
static int wm8960_i2c_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);
|
||||
struct wm8960_priv *wm8960;
|
||||
|
@ -1367,10 +1383,9 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int wm8960_i2c_remove(struct i2c_client *client)
|
||||
static void wm8960_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id wm8960_i2c_id[] = {
|
||||
|
|
BIN
wm8960.ko
BIN
wm8960.ko
Binary file not shown.
|
@ -2,7 +2,7 @@ state.ALSA {
|
|||
control.1 {
|
||||
iface MIXER
|
||||
name 'PCM Playback Volume'
|
||||
value -1995
|
||||
value -1994
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
|
@ -10,7 +10,7 @@ state.ALSA {
|
|||
range '-10239 - 400'
|
||||
dbmin -9999999
|
||||
dbmax 400
|
||||
dbvalue.0 -1995
|
||||
dbvalue.0 -1994
|
||||
}
|
||||
}
|
||||
control.2 {
|
||||
|
@ -65,12 +65,12 @@ state.ALSA {
|
|||
}
|
||||
}
|
||||
}
|
||||
state.seeedvoicecard {
|
||||
state.seeed2micvoicec {
|
||||
control.1 {
|
||||
iface MIXER
|
||||
name 'Capture Volume'
|
||||
value.0 63
|
||||
value.1 63
|
||||
value.0 39
|
||||
value.1 39
|
||||
comment {
|
||||
access 'read write'
|
||||
type INTEGER
|
||||
|
@ -78,8 +78,8 @@ state.seeedvoicecard {
|
|||
range '0 - 63'
|
||||
dbmin -1725
|
||||
dbmax 3000
|
||||
dbvalue.0 3000
|
||||
dbvalue.1 3000
|
||||
dbvalue.0 1200
|
||||
dbvalue.1 1200
|
||||
}
|
||||
}
|
||||
control.2 {
|
Loading…
Add table
Reference in a new issue