Compare commits

..

No commits in common. "v6.6-order-bugfix" and "v1,0" have entirely different histories.

53 changed files with 136 additions and 10101 deletions

674
LICENSE
View file

@ -1,674 +0,0 @@
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>.

View file

@ -1,52 +1,11 @@
# 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: all:
make -C /lib/modules/$(uname_r)/build M=$(PWD) modules make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean: clean:
make -C /lib/modules/$(uname_r)/build M=$(PWD) clean make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
install: install:
sudo cp snd-soc-ac108.ko ${DEST}/sound/soc/codecs/ sudo cp wm8960.ko /lib/modules/$(shell uname -r)
sudo cp snd-soc-wm8960.ko ${DEST}/sound/soc/codecs/
sudo cp snd-soc-seeed-voicecard.ko ${DEST}/sound/soc/bcm/
sudo depmod -a sudo depmod -a
.PHONY: all clean install
endif

View file

@ -1,64 +1,59 @@
# seeed-voicecard # seeed-voicecard
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. [![Join the chat at https://gitter.im/seeed-voicecard/Lobby](https://badges.gitter.im/seeed-voicecard/Lobby.svg)](https://gitter.im/seeed-voicecard/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
### Install seeed-voicecard 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 and install all linux kernel drivers
```bash Get the seeed voice card source code.
git clone https://github.com/HinTak/seeed-voicecard ```
git clone https://github.com/respeaker/seeed-voicecard
cd seeed-voicecard cd seeed-voicecard
sudo ./install.sh sudo ./install.sh
sudo reboot reboot
```
## ReSpeaker Documentation
Up to date documentation for reSpeaker products can be found in [Seeed Studio Wiki](https://wiki.seeedstudio.com/ReSpeaker/)!
![](https://files.seeedstudio.com/wiki/ReSpeakerProductGuide/img/Raspberry_Pi_Mic_Array_Solutions.png)
### Coherence
Estimate the magnitude squared coherence using Welchs method.
![4-mics-linear-array-kit coherence](https://user-images.githubusercontent.com/3901856/37277486-beb1dd96-261f-11e8-898b-84405bfc7cea.png)
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
``` ```
### uninstall seeed-voicecard Check that the sound card name matches the source code seeed-voicecard.
If you want to upgrade the driver , you need uninstall the driver first.
``` ```
pi@raspberrypi:~/seeed-voicecard $ sudo ./uninstall.sh pi@raspberrypi:~/seeed-voicecard$ aplay -l
... **** List of PLAYBACK Hardware Devices ****
------------------------------------------------------ card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
Please reboot your raspberry pi to apply all settings Subdevices: 8/8
Thank you! 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$
``` ```
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 ! 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).

1701
ac101.c

File diff suppressed because it is too large Load diff

View file

@ -1,432 +0,0 @@
/*
* 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__

1554
ac108.c

File diff suppressed because it is too large Load diff

774
ac108.h
View file

@ -1,774 +0,0 @@
/*
* 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

View file

@ -1,367 +0,0 @@
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
}
}
}

View file

@ -1,181 +0,0 @@
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
}
}
}

View file

@ -1,58 +0,0 @@
# 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)

View file

@ -1,5 +0,0 @@
#seeed-4mic-voicecard alsa plugin
```
sudo apt install libasound2-dev
make && sudo make install
```

View file

@ -1,77 +0,0 @@
#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;
}

View file

@ -1,11 +0,0 @@
#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);

View file

@ -1,536 +0,0 @@
//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
View file

@ -1,126 +0,0 @@
/*
* 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__

View file

@ -1,10 +1,6 @@
# The IPC key of dmix or dsnoop plugin must be unique # The IPC key of dmix or dsnoop plugin must be unique
# If 555555 or 666666 is used by other processes, use another one # 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 { pcm.!default {
type asym type asym
playback.pcm "playback" playback.pcm "playback"
@ -23,14 +19,14 @@ pcm.capture {
pcm.dmixed { pcm.dmixed {
type dmix type dmix
slave.pcm "hw:seeed2micvoicec" slave.pcm "hw:0,0"
ipc_key 555555 ipc_key 555555
} }
pcm.array { pcm.array {
type dsnoop type dsnoop
slave { slave {
pcm "hw:seeed2micvoicec" pcm "hw:0,0"
channels 2 channels 2
} }
ipc_key 666666 ipc_key 666666

View file

@ -2,7 +2,7 @@ state.ALSA {
control.1 { control.1 {
iface MIXER iface MIXER
name 'PCM Playback Volume' name 'PCM Playback Volume'
value -1994 value -1995
comment { comment {
access 'read write' access 'read write'
type INTEGER type INTEGER
@ -10,7 +10,7 @@ state.ALSA {
range '-10239 - 400' range '-10239 - 400'
dbmin -9999999 dbmin -9999999
dbmax 400 dbmax 400
dbvalue.0 -1994 dbvalue.0 -1995
} }
} }
control.2 { control.2 {
@ -65,12 +65,12 @@ state.ALSA {
} }
} }
} }
state.seeed2micvoicec { state.seeedvoicecard {
control.1 { control.1 {
iface MIXER iface MIXER
name 'Capture Volume' name 'Capture Volume'
value.0 39 value.0 63
value.1 39 value.1 63
comment { comment {
access 'read write' access 'read write'
type INTEGER type INTEGER
@ -78,8 +78,8 @@ state.seeed2micvoicec {
range '0 - 63' range '0 - 63'
dbmin -1725 dbmin -1725
dbmax 3000 dbmax 3000
dbvalue.0 1200 dbvalue.0 3000
dbvalue.1 1200 dbvalue.1 3000
} }
} }
control.2 { control.2 {

View file

@ -1,33 +0,0 @@
# 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
# }

View file

@ -1,90 +0,0 @@
# 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
}

View file

@ -1,10 +1,4 @@
#!/bin/sh dtoverlay -r seeed-voicecard
#dtoverlay -r seeed-2mic-voicecard dtc -@ -I dts -O dtb -o seeed-voicecard.dtbo seeed-voicecard-overlay.dts
DTC_FLAGS="-b 0 -Wno-unit_address_vs_reg -I dts -O dtb" cp seeed-voicecard.dtbo /boot/overlays
dtoverlay seeed-voicecard
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

View file

@ -1,15 +1,5 @@
PACKAGE_NAME="seeed-voicecard" PACKAGE_NAME="seeed-voicecard"
PACKAGE_VERSION="0.3" PACKAGE_VERSION="0.1"
BUILT_MODULE_NAME[0]="snd-soc-wm8960" BUILT_MODULE_NAME[0]="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[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" AUTOINSTALL="yes"

View file

@ -5,134 +5,22 @@ if [[ $EUID -ne 0 ]]; then
exit 1 exit 1
fi 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 # we create a dir with this version to ensure that 'dkms remove' won't delete
# the sources during kernel updates # the sources during kernel updates
marker="0.0.0" marker="0.0.0"
_VER_RUN= apt update
function get_kernel_version() { apt-get -y install raspberrypi-kernel-headers raspberrypi-kernel
local ZIMAGE IMG_OFFSET apt-get -y install dkms
_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 # locate currently installed kernels (may be different to running kernel if
# it's just been updated) # it's just been updated)
base_ver=$(get_kernel_version) kernels=$(ls /lib/modules | sed "s/^/-k /")
base_ver=${base_ver%%[-+]*}
#kernels="${base_ver}+ ${base_ver}-v7+ ${base_ver}-v7l+"
kernels=$(uname -r)
function install_module { function install_module {
local _i
src=$1 src=$1
mod=$2 mod=$2
@ -141,19 +29,13 @@ function install_module {
fi fi
if [[ -e /usr/src/$mod-$ver || -e /var/lib/dkms/$mod/$ver ]]; then if [[ -e /usr/src/$mod-$ver || -e /var/lib/dkms/$mod/$ver ]]; then
dkms remove --force -m $mod -v $ver --all dkms remove -m $mod -v $ver --all
rm -rf /usr/src/$mod-$ver rm -rf /usr/src/$mod-$ver
fi fi
mkdir -p /usr/src/$mod-$ver mkdir -p /usr/src/$mod-$ver
cp -a $src/* /usr/src/$mod-$ver/ cp -a $src/* /usr/src/$mod-$ver/
dkms add -m $mod -v $ver dkms add -m $mod -v $ver
for _i in $kernels; do dkms build $kernels -m $mod -v $ver && dkms install $kernels -m $mod -v $ver
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 mkdir -p /var/lib/dkms/$mod/$ver/$marker
} }
@ -161,61 +43,23 @@ function install_module {
install_module "./" "seeed-voicecard" install_module "./" "seeed-voicecard"
# install dtbos (
cp seeed-2mic-voicecard.dtbo $OVERLAYS cp seeed-voicecard.dtbo /boot/overlays
cp seeed-4mic-voicecard.dtbo $OVERLAYS cp asound.state /var/lib/alsa/asound.state
cp seeed-8mic-voicecard.dtbo $OVERLAYS )
#install alsa plugins echo 'wm8960' | sudo tee --append /etc/modules > /dev/null
# 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
#set kernel modules sed -i \
grep -q "^snd-soc-seeed-voicecard$" /etc/modules || \ -e "s/^dtparam=audio=on/#\0/" \
echo "snd-soc-seeed-voicecard" >> /etc/modules -e "s/^#\(dtparam=i2s=on\)/\1/" \
grep -q "^snd-soc-ac108$" /etc/modules || \ /boot/config.txt
echo "snd-soc-ac108" >> /etc/modules grep -q "dtoverlay=i2s-mmap" /boot/config.txt || \
grep -q "^snd-soc-wm8960$" /etc/modules || \ echo "dtoverlay=i2s-mmap" >> /boot/config.txt
echo "snd-soc-wm8960" >> /etc/modules grep -q "dtoverlay=seeed-voicecard" /boot/config.txt || \
echo "dtoverlay=seeed-voicecard" >> /boot/config.txt
#set dtoverlays grep -q "dtparam=i2s=on" /boot/config.txt || \
CONFIG=/boot/config.txt echo "dtparam=i2s=on" >> /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 "------------------------------------------------------"
echo "Please reboot your raspberry pi to apply all settings" echo "Please reboot your raspberry pi to apply all settings"

View file

@ -1,454 +0,0 @@
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 = {

View file

@ -1,245 +0,0 @@
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 = {

View file

@ -1,71 +0,0 @@
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 = {

View file

@ -1,8 +0,0 @@
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"

View file

@ -1,251 +0,0 @@
# 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"
```
![](./udev_rules_4mic.png)
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"
```
![](./udev_rules_6mic.png)
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.

View file

@ -1,87 +0,0 @@
# 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

View file

@ -1,144 +0,0 @@
#!/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

View file

@ -1,17 +0,0 @@
# /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

View file

@ -1,87 +0,0 @@
# 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

View file

@ -1,143 +0,0 @@
#!/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

View file

@ -1,34 +0,0 @@
# /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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 483 KiB

Binary file not shown.

View file

@ -1,75 +0,0 @@
/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";
};
};

Binary file not shown.

View file

@ -1,118 +0,0 @@
/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";
};
};

Binary file not shown.

View file

@ -1,163 +0,0 @@
#!/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

View file

@ -38,13 +38,49 @@
}; };
}; };
fragment@3 { 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>; target = <&sound>;
slave_overlay: __overlay__ { slave_overlay: __overlay__ {
compatible = "simple-audio-card"; compatible = "simple-audio-card";
simple-audio-card,format = "i2s"; simple-audio-card,format = "i2s";
simple-audio-card,name = "seeed-2mic-voicecard"; simple-audio-card,name = "seeed-voicecard";
status = "okay"; status = "okay";
simple-audio-card,widgets = simple-audio-card,widgets =
"Microphone", "Mic Jack", "Microphone", "Mic Jack",
@ -78,7 +114,8 @@
}; };
__overrides__ { __overrides__ {
alsaname = <&slave_overlay>,"simple-audio-card,name"; alsaname = <&master_overlay>,"simple-audio-card,name",
<&slave_overlay>,"simple-audio-card,name";
compatible = <&wm8960>,"compatible"; compatible = <&wm8960>,"compatible";
master = <0>,"=2!3"; master = <0>,"=2!3";
}; };

View file

@ -1,926 +0,0 @@
/*
* 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>");

BIN
seeed-voicecard.dtbo Normal file

Binary file not shown.

View file

@ -1,12 +0,0 @@
[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

View file

@ -1,47 +0,0 @@
/*
* (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__

View file

@ -1,44 +0,0 @@
"""
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()

View file

@ -1,83 +0,0 @@
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()

View file

@ -1,37 +0,0 @@
#!/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

View file

@ -1,100 +0,0 @@
#!/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 "------------------------------------------------------"

View file

@ -25,7 +25,6 @@
#include <sound/initval.h> #include <sound/initval.h>
#include <sound/tlv.h> #include <sound/tlv.h>
#include <sound/wm8960.h> #include <sound/wm8960.h>
#include "sound-compatible-4.18.h"
#include "wm8960.h" #include "wm8960.h"
@ -227,12 +226,11 @@ 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(bypass_tlv, -2100, 300, 0);
static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
static const DECLARE_TLV_DB_SCALE(lineinboost_tlv, -1500, 300, 1); static const DECLARE_TLV_DB_SCALE(lineinboost_tlv, -1500, 300, 1);
static const DECLARE_TLV_DB_RANGE(micboost_tlv, static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(micboost_tlv,
0, 1, TLV_DB_SCALE_ITEM(0, 1300, 0), 0, 1, TLV_DB_SCALE_ITEM(0, 1300, 0),
2, 3, TLV_DB_SCALE_ITEM(2000, 900, 0), 2, 3, TLV_DB_SCALE_ITEM(2000, 900, 0),
); );
static const struct snd_kcontrol_new wm8960_snd_controls[] = { static const struct snd_kcontrol_new wm8960_snd_controls[] = {
SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL, SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,
0, 63, 0, inpga_tlv), 0, 63, 0, inpga_tlv),
@ -508,11 +506,7 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
* list each time to find the desired power state do so now * list each time to find the desired power state do so now
* and save the result. * 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) { list_for_each_entry(w, &codec->component.card->widgets, list) {
#endif
if (w->dapm != dapm) if (w->dapm != dapm)
continue; continue;
if (strcmp(w->name, "LOUT1 PGA") == 0) if (strcmp(w->name, "LOUT1 PGA") == 0)
@ -753,7 +747,6 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
iface |= 0x000c; iface |= 0x000c;
break; break;
} }
fallthrough;
default: default:
dev_err(codec->dev, "unsupported width %d\n", dev_err(codec->dev, "unsupported width %d\n",
params_width(params)); params_width(params));
@ -796,7 +789,7 @@ static int wm8960_hw_free(struct snd_pcm_substream *substream,
return 0; 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; struct snd_soc_codec *codec = dai->codec;
@ -1236,12 +1229,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 = { static const struct snd_soc_dai_ops wm8960_dai_ops = {
.hw_params = wm8960_hw_params, .hw_params = wm8960_hw_params,
.hw_free = wm8960_hw_free, .hw_free = wm8960_hw_free,
.mute_stream = wm8960_mute, .digital_mute = wm8960_mute,
.set_fmt = wm8960_set_dai_fmt, .set_fmt = wm8960_set_dai_fmt,
.set_clkdiv = wm8960_set_dai_clkdiv, .set_clkdiv = wm8960_set_dai_clkdiv,
.set_pll = wm8960_set_dai_pll, .set_pll = wm8960_set_dai_pll,
.set_sysclk = wm8960_set_dai_sysclk, .set_sysclk = wm8960_set_dai_sysclk,
.no_capture_mute = 1,
}; };
static struct snd_soc_dai_driver wm8960_dai = { static struct snd_soc_dai_driver wm8960_dai = {
@ -1259,11 +1251,7 @@ static struct snd_soc_dai_driver wm8960_dai = {
.rates = WM8960_RATES, .rates = WM8960_RATES,
.formats = WM8960_FORMATS,}, .formats = WM8960_FORMATS,},
.ops = &wm8960_dai_ops, .ops = &wm8960_dai_ops,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0)
.symmetric_rate = 1,
#else
.symmetric_rates = 1, .symmetric_rates = 1,
#endif
}; };
static int wm8960_probe(struct snd_soc_codec *codec) static int wm8960_probe(struct snd_soc_codec *codec)
@ -1286,12 +1274,7 @@ static int wm8960_probe(struct snd_soc_codec *codec)
static const struct snd_soc_codec_driver soc_codec_dev_wm8960 = { static const struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
.probe = wm8960_probe, .probe = wm8960_probe,
.set_bias_level = wm8960_set_bias_level, .set_bias_level = wm8960_set_bias_level,
.suspend_bias_off = true, .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 = { static const struct regmap_config wm8960_regmap = {
@ -1318,7 +1301,8 @@ static void wm8960_set_pdata_from_of(struct i2c_client *i2c,
pdata->shared_lrclk = true; pdata->shared_lrclk = true;
} }
static int wm8960_i2c_probe(struct i2c_client *i2c) static int wm8960_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{ {
struct wm8960_data *pdata = dev_get_platdata(&i2c->dev); struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);
struct wm8960_priv *wm8960; struct wm8960_priv *wm8960;
@ -1383,9 +1367,10 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
return ret; return ret;
} }
static void wm8960_i2c_remove(struct i2c_client *client) static int wm8960_i2c_remove(struct i2c_client *client)
{ {
snd_soc_unregister_codec(&client->dev); snd_soc_unregister_codec(&client->dev);
return 0;
} }
static const struct i2c_device_id wm8960_i2c_id[] = { static const struct i2c_device_id wm8960_i2c_id[] = {

BIN
wm8960.ko Normal file

Binary file not shown.