summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authora02204102016-12-12 09:01:22 -0600
committera02204102016-12-12 09:01:22 -0600
commit9db89c082af747a34b54d8bad7e9d8e8b2df7ebd (patch)
tree7feacdee09ec380e3975970afe8843314be09532
downloadtas2559-android-driver-9db89c082af747a34b54d8bad7e9d8e8b2df7ebd.tar.gz
tas2559-android-driver-9db89c082af747a34b54d8bad7e9d8e8b2df7ebd.tar.xz
tas2559-android-driver-9db89c082af747a34b54d8bad7e9d8e8b2df7ebd.zip
draft version
-rwxr-xr-xKconfig12
-rwxr-xr-xLicense text GPLv2.txt339
-rwxr-xr-xMakefile2
-rwxr-xr-xdai_link.readme28
-rwxr-xr-xdts.readme18
-rwxr-xr-xtas2559-codec.c572
-rwxr-xr-xtas2559-codec.h34
-rwxr-xr-xtas2559-core.c1532
-rwxr-xr-xtas2559-core.h54
-rwxr-xr-xtas2559-misc.c608
-rwxr-xr-xtas2559-misc.h63
-rwxr-xr-xtas2559-regmap.c766
-rwxr-xr-xtas2559.h453
-rwxr-xr-xtas2560-core.c286
-rwxr-xr-xtas2560-core.h37
-rwxr-xr-xtas2560.h125
-rwxr-xr-xtiload.c360
-rwxr-xr-xtiload.h57
18 files changed, 5346 insertions, 0 deletions
diff --git a/Kconfig b/Kconfig
new file mode 100755
index 0000000..853ba22
--- /dev/null
+++ b/Kconfig
@@ -0,0 +1,12 @@
1
2menuconfig SND_SOC_TAS2559
3 tristate "Texas Instruments TAS2559 SmartAmp(R)"
4
5if SND_SOC_TAS2559
6config TAS2559_CODEC
7 bool "Codec Driver support"
8
9config TAS2559_MISC
10 bool "Misc Driver support"
11
12endif # SND_SOC_TAS2559
diff --git a/License text GPLv2.txt b/License text GPLv2.txt
new file mode 100755
index 0000000..d159169
--- /dev/null
+++ b/License text GPLv2.txt
@@ -0,0 +1,339 @@
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 Preamble
10
11 The licenses for most software are designed to take away your
12freedom to share and change it. By contrast, the GNU General Public
13License is intended to guarantee your freedom to share and change free
14software--to make sure the software is free for all its users. This
15General Public License applies to most of the Free Software
16Foundation's software and to any other program whose authors commit to
17using it. (Some other Free Software Foundation software is covered by
18the GNU Lesser General Public License instead.) You can apply it to
19your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge for
24this service if you wish), that you receive source code or can get it
25if you want it, that you can change the software or use pieces of it
26in new free programs; and that you know you can do these things.
27
28 To protect your rights, we need to make restrictions that forbid
29anyone to deny you these rights or to ask you to surrender the rights.
30These restrictions translate to certain responsibilities for you if you
31distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34gratis or for a fee, you must give the recipients all the rights that
35you have. You must make sure that they, too, receive or can get the
36source code. And you must show them these terms so they know their
37rights.
38
39 We protect your rights with two steps: (1) copyright the software, and
40(2) offer you this license which gives you legal permission to copy,
41distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44that everyone understands that there is no warranty for this free
45software. If the software is modified by someone else and passed on, we
46want its recipients to know that what they have is not the original, so
47that any problems introduced by others will not reflect on the original
48authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51patents. We wish to avoid the danger that redistributors of a free
52program will individually obtain patent licenses, in effect making the
53program proprietary. To prevent this, we have made it clear that any
54patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57modification follow.
58
59 GNU GENERAL PUBLIC LICENSE
60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
62 0. This License applies to any program or other work which contains
63a notice placed by the copyright holder saying it may be distributed
64under the terms of this General Public License. The "Program", below,
65refers to any such program or work, and a "work based on the Program"
66means either the Program or any derivative work under copyright law:
67that is to say, a work containing the Program or a portion of it,
68either verbatim or with modifications and/or translated into another
69language. (Hereinafter, translation is included without limitation in
70the term "modification".) Each licensee is addressed as "you".
71
72Activities other than copying, distribution and modification are not
73covered by this License; they are outside its scope. The act of
74running the Program is not restricted, and the output from the Program
75is covered only if its contents constitute a work based on the
76Program (independent of having been made by running the Program).
77Whether that is true depends on what the Program does.
78
79 1. You may copy and distribute verbatim copies of the Program's
80source code as you receive it, in any medium, provided that you
81conspicuously and appropriately publish on each copy an appropriate
82copyright notice and disclaimer of warranty; keep intact all the
83notices that refer to this License and to the absence of any warranty;
84and give any other recipients of the Program a copy of this License
85along with the Program.
86
87You may charge a fee for the physical act of transferring a copy, and
88you may at your option offer warranty protection in exchange for a fee.
89
90 2. You may modify your copy or copies of the Program or any portion
91of it, thus forming a work based on the Program, and copy and
92distribute such modifications or work under the terms of Section 1
93above, provided that you also meet all of these conditions:
94
95 a) You must cause the modified files to carry prominent notices
96 stating that you changed the files and the date of any change.
97
98 b) You must cause any work that you distribute or publish, that in
99 whole or in part contains or is derived from the Program or any
100 part thereof, to be licensed as a whole at no charge to all third
101 parties under the terms of this License.
102
103 c) If the modified program normally reads commands interactively
104 when run, you must cause it, when started running for such
105 interactive use in the most ordinary way, to print or display an
106 announcement including an appropriate copyright notice and a
107 notice that there is no warranty (or else, saying that you provide
108 a warranty) and that users may redistribute the program under
109 these conditions, and telling the user how to view a copy of this
110 License. (Exception: if the Program itself is interactive but
111 does not normally print such an announcement, your work based on
112 the Program is not required to print an announcement.)
113
114These requirements apply to the modified work as a whole. If
115identifiable sections of that work are not derived from the Program,
116and can be reasonably considered independent and separate works in
117themselves, then this License, and its terms, do not apply to those
118sections when you distribute them as separate works. But when you
119distribute the same sections as part of a whole which is a work based
120on the Program, the distribution of the whole must be on the terms of
121this License, whose permissions for other licensees extend to the
122entire whole, and thus to each and every part regardless of who wrote it.
123
124Thus, it is not the intent of this section to claim rights or contest
125your rights to work written entirely by you; rather, the intent is to
126exercise the right to control the distribution of derivative or
127collective works based on the Program.
128
129In addition, mere aggregation of another work not based on the Program
130with the Program (or with a work based on the Program) on a volume of
131a storage or distribution medium does not bring the other work under
132the scope of this License.
133
134 3. You may copy and distribute the Program (or a work based on it,
135under Section 2) in object code or executable form under the terms of
136Sections 1 and 2 above provided that you also do one of the following:
137
138 a) Accompany it with the complete corresponding machine-readable
139 source code, which must be distributed under the terms of Sections
140 1 and 2 above on a medium customarily used for software interchange; or,
141
142 b) Accompany it with a written offer, valid for at least three
143 years, to give any third party, for a charge no more than your
144 cost of physically performing source distribution, a complete
145 machine-readable copy of the corresponding source code, to be
146 distributed under the terms of Sections 1 and 2 above on a medium
147 customarily used for software interchange; or,
148
149 c) Accompany it with the information you received as to the offer
150 to distribute corresponding source code. (This alternative is
151 allowed only for noncommercial distribution and only if you
152 received the program in object code or executable form with such
153 an offer, in accord with Subsection b above.)
154
155The source code for a work means the preferred form of the work for
156making modifications to it. For an executable work, complete source
157code means all the source code for all modules it contains, plus any
158associated interface definition files, plus the scripts used to
159control compilation and installation of the executable. However, as a
160special exception, the source code distributed need not include
161anything that is normally distributed (in either source or binary
162form) with the major components (compiler, kernel, and so on) of the
163operating system on which the executable runs, unless that component
164itself accompanies the executable.
165
166If distribution of executable or object code is made by offering
167access to copy from a designated place, then offering equivalent
168access to copy the source code from the same place counts as
169distribution of the source code, even though third parties are not
170compelled to copy the source along with the object code.
171
172 4. You may not copy, modify, sublicense, or distribute the Program
173except as expressly provided under this License. Any attempt
174otherwise to copy, modify, sublicense or distribute the Program is
175void, and will automatically terminate your rights under this License.
176However, parties who have received copies, or rights, from you under
177this License will not have their licenses terminated so long as such
178parties remain in full compliance.
179
180 5. You are not required to accept this License, since you have not
181signed it. However, nothing else grants you permission to modify or
182distribute the Program or its derivative works. These actions are
183prohibited by law if you do not accept this License. Therefore, by
184modifying or distributing the Program (or any work based on the
185Program), you indicate your acceptance of this License to do so, and
186all its terms and conditions for copying, distributing or modifying
187the Program or works based on it.
188
189 6. Each time you redistribute the Program (or any work based on the
190Program), the recipient automatically receives a license from the
191original licensor to copy, distribute or modify the Program subject to
192these terms and conditions. You may not impose any further
193restrictions on the recipients' exercise of the rights granted herein.
194You are not responsible for enforcing compliance by third parties to
195this License.
196
197 7. If, as a consequence of a court judgment or allegation of patent
198infringement or for any other reason (not limited to patent issues),
199conditions are imposed on you (whether by court order, agreement or
200otherwise) that contradict the conditions of this License, they do not
201excuse you from the conditions of this License. If you cannot
202distribute so as to satisfy simultaneously your obligations under this
203License and any other pertinent obligations, then as a consequence you
204may not distribute the Program at all. For example, if a patent
205license would not permit royalty-free redistribution of the Program by
206all those who receive copies directly or indirectly through you, then
207the only way you could satisfy both it and this License would be to
208refrain entirely from distribution of the Program.
209
210If any portion of this section is held invalid or unenforceable under
211any particular circumstance, the balance of the section is intended to
212apply and the section as a whole is intended to apply in other
213circumstances.
214
215It is not the purpose of this section to induce you to infringe any
216patents or other property right claims or to contest validity of any
217such claims; this section has the sole purpose of protecting the
218integrity of the free software distribution system, which is
219implemented by public license practices. Many people have made
220generous contributions to the wide range of software distributed
221through that system in reliance on consistent application of that
222system; it is up to the author/donor to decide if he or she is willing
223to distribute software through any other system and a licensee cannot
224impose that choice.
225
226This section is intended to make thoroughly clear what is believed to
227be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230certain countries either by patents or by copyrighted interfaces, the
231original copyright holder who places the Program under this License
232may add an explicit geographical distribution limitation excluding
233those countries, so that distribution is permitted only in or among
234countries not thus excluded. In such case, this License incorporates
235the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238of the General Public License from time to time. Such new versions will
239be similar in spirit to the present version, but may differ in detail to
240address new problems or concerns.
241
242Each version is given a distinguishing version number. If the Program
243specifies a version number of this License which applies to it and "any
244later version", you have the option of following the terms and conditions
245either of that version or of any later version published by the Free
246Software Foundation. If the Program does not specify a version number of
247this License, you may choose any version ever published by the Free Software
248Foundation.
249
250 10. If you wish to incorporate parts of the Program into other free
251programs whose distribution conditions are different, write to the author
252to ask for permission. For software which is copyrighted by the Free
253Software Foundation, write to the Free Software Foundation; we sometimes
254make exceptions for this. Our decision will be guided by the two goals
255of preserving the free status of all derivatives of our free software and
256of promoting the sharing and reuse of software generally.
257
258 NO WARRANTY
259
260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268REPAIR OR CORRECTION.
269
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278POSSIBILITY OF SUCH DAMAGES.
279
280 END OF TERMS AND CONDITIONS
281
282 How to Apply These Terms to Your New Programs
283
284 If you develop a new program, and you want it to be of the greatest
285possible use to the public, the best way to achieve this is to make it
286free software which everyone can redistribute and change under these terms.
287
288 To do so, attach the following notices to the program. It is safest
289to attach them to the start of each source file to most effectively
290convey the exclusion of warranty; and each file should have at least
291the "copyright" line and a pointer to where the full notice is found.
292
293 <one line to give the program's name and a brief idea of what it does.>
294 Copyright (C) <year> <name of author>
295
296 This program is free software; you can redistribute it and/or modify
297 it under the terms of the GNU General Public License as published by
298 the Free Software Foundation; either version 2 of the License, or
299 (at your option) any later version.
300
301 This program is distributed in the hope that it will be useful,
302 but WITHOUT ANY WARRANTY; without even the implied warranty of
303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 GNU General Public License for more details.
305
306 You should have received a copy of the GNU General Public License along
307 with this program; if not, write to the Free Software Foundation, Inc.,
308 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
310Also add information on how to contact you by electronic and paper mail.
311
312If the program is interactive, make it output a short notice like this
313when it starts in an interactive mode:
314
315 Gnomovision version 69, Copyright (C) year name of author
316 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 This is free software, and you are welcome to redistribute it
318 under certain conditions; type `show c' for details.
319
320The hypothetical commands `show w' and `show c' should show the appropriate
321parts of the General Public License. Of course, the commands you use may
322be called something other than `show w' and `show c'; they could even be
323mouse-clicks or menu items--whatever suits your program.
324
325You should also get your employer (if you work as a programmer) or your
326school, if any, to sign a "copyright disclaimer" for the program, if
327necessary. Here is a sample; alter the names:
328
329 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
332 <signature of Ty Coon>, 1 April 1989
333 Ty Coon, President of Vice
334
335This General Public License does not permit incorporating your program into
336proprietary programs. If your program is a subroutine library, you may
337consider it more useful to permit linking proprietary applications with the
338library. If this is what you want to do, use the GNU Lesser General
339Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100755
index 0000000..238d2dc
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
1snd-soc-tas2559-objs := tas2559-core.o tas2560-core.o tas2559-regmap.o tas2559-codec.o tas2559-misc.o tiload.o
2obj-$(CONFIG_SND_SOC_TAS2559) += snd-soc-tas2559.o \ No newline at end of file
diff --git a/dai_link.readme b/dai_link.readme
new file mode 100755
index 0000000..6817c94
--- /dev/null
+++ b/dai_link.readme
@@ -0,0 +1,28 @@
1example for connecting CPU DAI
2
3#if defined(CONFIG_TAS2559_CODEC)
4 {
5 .name = LPASS_BE_PRI_MI2S_RX,
6 .stream_name = "Primary MI2S Hostless Playback",
7 .cpu_dai_name = "msm-dai-q6-mi2s.0",
8 .platform_name = "msm-pcm-routing",
9 .codec_name = "tas2559.3-004f",
10 .codec_dai_name = "tas2559 ASI1",
11 .no_pcm = 1,
12 .be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
13 .be_hw_params_fixup = msm_be_prim_mi2s_hw_params_fixup,
14 .ops = &msm8974_prim_mi2s_be_ops,
15 },
16 {
17 .name = LPASS_BE_PRI_MI2S_TX,
18 .stream_name = "Primary MI2S Hostless Capture",
19 .cpu_dai_name = "msm-dai-q6-mi2s.0",
20 .platform_name = "msm-pcm-routing",
21 .codec_name = "tas2559.3-004f",
22 .codec_dai_name = "tas2559 ASI1",
23 .no_pcm = 1,
24 .be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
25 .be_hw_params_fixup = msm_be_prim_mi2s_hw_params_fixup,
26 .ops = &msm8974_prim_mi2s_be_ops,
27 },
28#endif \ No newline at end of file
diff --git a/dts.readme b/dts.readme
new file mode 100755
index 0000000..e6c516e
--- /dev/null
+++ b/dts.readme
@@ -0,0 +1,18 @@
1example for dts:
2
3 tas2559@4f{
4 #sound-dai-cells = <1>;
5 compatible = "ti,tas2559";
6 reg = <0x4f>;
7 ti,cdc-reset-gpio = <&msmgpio 73 0>;
8 ti,irq-gpio = <&msmgpio 59 0>;
9 ti,bit-rate = <16>; /* 16, 20, 24, 32 */
10 ti,dev-a-addr = <0x4c>; /* TAS2559 */
11 ti,dev-a-channel = <0>; /* 0, left; 1, right */
12 ti,dev-a-load = <0>; /* 0, 8Ohm; 1, 6Ohm; 2, 4Ohm */
13 ti,dev-b-addr = <0x4d>; /* TAS2560 */
14 ti,dev-b-channel = <1>; /* 0, left; 1, right */
15 ti,dev-b-load = <0>; /* 0, 8Ohm; 1, 6Ohm; 2, 4Ohm */
16 status = "ok";
17 };
18 \ No newline at end of file
diff --git a/tas2559-codec.c b/tas2559-codec.c
new file mode 100755
index 0000000..f511417
--- /dev/null
+++ b/tas2559-codec.c
@@ -0,0 +1,572 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tas2559-codec.c
19**
20** Description:
21** ALSA SoC driver for Texas Instruments TAS2559 High Performance 4W Smart Amplifier
22**
23** =============================================================================
24*/
25
26#ifdef CONFIG_TAS2559_CODEC
27
28#define DEBUG
29#include <linux/module.h>
30#include <linux/moduleparam.h>
31#include <linux/init.h>
32#include <linux/delay.h>
33#include <linux/pm.h>
34#include <linux/i2c.h>
35#include <linux/gpio.h>
36#include <linux/regulator/consumer.h>
37#include <linux/firmware.h>
38#include <linux/regmap.h>
39#include <linux/of.h>
40#include <linux/of_gpio.h>
41#include <linux/slab.h>
42#include <linux/syscalls.h>
43#include <linux/fcntl.h>
44#include <asm/uaccess.h>
45#include <sound/core.h>
46#include <sound/pcm.h>
47#include <sound/pcm_params.h>
48#include <sound/soc.h>
49#include <sound/initval.h>
50#include <sound/tlv.h>
51
52#include "tas2559-core.h"
53#include "tas2559-codec.h"
54
55#undef KCONTROL_CODEC
56
57static unsigned int tas2559_codec_read(struct snd_soc_codec *pCodec,
58 unsigned int nRegister)
59{
60 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(pCodec);
61
62 dev_err(pTAS2559->dev, "%s, ERROR, shouldn't be here\n", __FUNCTION__);
63 return 0;
64}
65
66static int tas2559_codec_write(struct snd_soc_codec *pCodec, unsigned int nRegister,
67 unsigned int nValue)
68{
69 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(pCodec);
70
71 dev_err(pTAS2559->dev, "%s, ERROR, shouldn't be here\n", __FUNCTION__);
72
73 return 0;
74}
75
76static const struct snd_soc_dapm_widget tas2559_dapm_widgets[] = {
77 SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
78 SND_SOC_DAPM_AIF_IN("ASI2", "ASI2 Playback", 0, SND_SOC_NOPM, 0, 0),
79 SND_SOC_DAPM_AIF_IN("ASIM", "ASIM Playback", 0, SND_SOC_NOPM, 0, 0),
80 SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
81
82 SND_SOC_DAPM_OUT_DRV("ClassD", SND_SOC_NOPM, 0, 0, NULL, 0),
83
84 SND_SOC_DAPM_SUPPLY("PLL", SND_SOC_NOPM, 0, 0, NULL, 0),
85 SND_SOC_DAPM_SUPPLY("NDivider", SND_SOC_NOPM, 0, 0, NULL, 0),
86
87 SND_SOC_DAPM_OUTPUT("OUT")
88};
89
90static const struct snd_soc_dapm_route tas2559_audio_map[] = {
91 {"DAC", NULL, "ASI1"},
92 {"DAC", NULL, "ASI2"},
93 {"DAC", NULL, "ASIM"},
94 {"ClassD", NULL, "DAC"},
95 {"OUT", NULL, "ClassD"},
96 {"DAC", NULL, "PLL"},
97 {"DAC", NULL, "NDivider"},
98};
99
100static int tas2559_startup(struct snd_pcm_substream *substream,
101 struct snd_soc_dai *dai)
102{
103 struct snd_soc_codec *codec = dai->codec;
104 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
105
106 dev_dbg(pTAS2559->dev, "%s\n", __func__);
107
108 return 0;
109}
110
111static void tas2559_shutdown(struct snd_pcm_substream *substream,
112 struct snd_soc_dai *dai)
113{
114 struct snd_soc_codec *codec = dai->codec;
115 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
116
117 dev_dbg(pTAS2559->dev, "%s\n", __func__);
118}
119
120static int tas2559_mute(struct snd_soc_dai *dai, int mute)
121{
122 struct snd_soc_codec *codec = dai->codec;
123 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
124
125 dev_dbg(pTAS2559->dev, "%s\n", __func__);
126
127 tas2559_enable(pTAS2559, !mute);
128
129 return 0;
130}
131
132static int tas2559_set_dai_sysclk(struct snd_soc_dai *pDAI,
133 int nClkID, unsigned int nFreqency, int nDir)
134{
135 struct snd_soc_codec *pCodec = pDAI->codec;
136 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(pCodec);
137
138 dev_dbg(pTAS2559->dev, "tas2559_set_dai_sysclk: freq = %u\n", nFreqency);
139
140 return 0;
141}
142
143static int tas2559_hw_params(struct snd_pcm_substream *pSubstream,
144 struct snd_pcm_hw_params *pParams, struct snd_soc_dai *pDAI)
145{
146 struct snd_soc_codec *pCodec = pDAI->codec;
147 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(pCodec);
148
149 dev_dbg(pTAS2559->dev, "%s\n", __func__);
150
151 tas2559_set_sampling_rate(pTAS2559, params_rate(pParams));
152
153 return 0;
154}
155
156static int tas2559_set_dai_fmt(struct snd_soc_dai *pDAI, unsigned int nFormat)
157{
158 struct snd_soc_codec *codec = pDAI->codec;
159 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
160
161 dev_dbg(pTAS2559->dev, "%s\n", __func__);
162
163 return 0;
164}
165
166static int tas2559_prepare(struct snd_pcm_substream *pSubstream,
167 struct snd_soc_dai *pDAI)
168{
169 struct snd_soc_codec *codec = pDAI->codec;
170 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
171
172 dev_dbg(pTAS2559->dev, "%s\n", __func__);
173
174 return 0;
175}
176
177static int tas2559_set_bias_level(struct snd_soc_codec *pCodec,
178 enum snd_soc_bias_level eLevel)
179{
180 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(pCodec);
181
182 dev_dbg(pTAS2559->dev, "%s: %d\n", __func__, eLevel);
183
184 return 0;
185}
186
187static int tas2559_codec_probe(struct snd_soc_codec *pCodec)
188{
189 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(pCodec);
190
191 dev_dbg(pTAS2559->dev, "%s\n", __func__);
192
193 return 0;
194}
195
196static int tas2559_codec_remove(struct snd_soc_codec *pCodec)
197{
198 return 0;
199}
200
201static int tas2559_power_ctrl_get(struct snd_kcontrol *pKcontrol,
202 struct snd_ctl_elem_value *pValue)
203{
204#ifdef KCONTROL_CODEC
205 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
206#else
207 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
208#endif
209 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
210
211 pValue->value.integer.value[0] = pTAS2559->mbPowerUp;
212 dev_dbg(pTAS2559->dev, "tas2559_power_ctrl_get = %d\n",
213 pTAS2559->mbPowerUp);
214
215 return 0;
216}
217
218static int tas2559_power_ctrl_put(struct snd_kcontrol *pKcontrol,
219 struct snd_ctl_elem_value *pValue)
220{
221#ifdef KCONTROL_CODEC
222 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
223#else
224 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
225#endif
226 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
227
228 pTAS2559->mbPowerUp = pValue->value.integer.value[0];
229
230 dev_dbg(pTAS2559->dev, "tas2559_power_ctrl_put = %d\n",
231 pTAS2559->mbPowerUp);
232
233 if (pTAS2559->mbPowerUp == 1)
234 tas2559_enable(pTAS2559, true);
235 if (pTAS2559->mbPowerUp == 0)
236 tas2559_enable(pTAS2559, false);
237
238 return 0;
239}
240
241static int tas2559_fs_get(struct snd_kcontrol *pKcontrol,
242 struct snd_ctl_elem_value *pValue)
243{
244#ifdef KCONTROL_CODEC
245 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
246#else
247 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
248#endif
249 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
250
251 int nFS = 48000;
252
253 if (pTAS2559->mpFirmware->mnConfigurations)
254 nFS = pTAS2559->mpFirmware->mpConfigurations[pTAS2559->mnCurrentConfiguration].mnSamplingRate;
255
256 pValue->value.integer.value[0] = nFS;
257
258 dev_dbg(pTAS2559->dev, "tas2559_fs_get = %d\n", nFS);
259 return 0;
260}
261
262static int tas2559_fs_put(struct snd_kcontrol *pKcontrol,
263 struct snd_ctl_elem_value *pValue)
264{
265#ifdef KCONTROL_CODEC
266 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
267#else
268 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
269#endif
270 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
271 int ret = 0;
272 int nFS = pValue->value.integer.value[0];
273
274 dev_info(pTAS2559->dev, "tas2559_fs_put = %d\n", nFS);
275
276 ret = tas2559_set_sampling_rate(pTAS2559, nFS);
277
278 return ret;
279}
280
281static int tas2559_program_get(struct snd_kcontrol *pKcontrol,
282 struct snd_ctl_elem_value *pValue)
283{
284#ifdef KCONTROL_CODEC
285 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
286#else
287 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
288#endif
289 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
290
291 pValue->value.integer.value[0] = pTAS2559->mnCurrentProgram;
292 dev_dbg(pTAS2559->dev, "tas2559_program_get = %d\n",
293 pTAS2559->mnCurrentProgram);
294
295 return 0;
296}
297
298static int tas2559_program_put(struct snd_kcontrol *pKcontrol,
299 struct snd_ctl_elem_value *pValue)
300{
301#ifdef KCONTROL_CODEC
302 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
303#else
304 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
305#endif
306 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
307 unsigned int nProgram = pValue->value.integer.value[0];
308 int ret = 0;
309
310 ret = tas2559_set_program(pTAS2559, nProgram);
311
312 return ret;
313}
314
315static int tas2559_configuration_get(struct snd_kcontrol *pKcontrol,
316 struct snd_ctl_elem_value *pValue)
317{
318#ifdef KCONTROL_CODEC
319 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
320#else
321 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
322#endif
323 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
324
325 pValue->value.integer.value[0] = pTAS2559->mnCurrentConfiguration;
326 dev_dbg(pTAS2559->dev, "tas2559_configuration_get = %d\n",
327 pTAS2559->mnCurrentConfiguration);
328
329 return 0;
330}
331
332static int tas2559_configuration_put(struct snd_kcontrol *pKcontrol,
333 struct snd_ctl_elem_value *pValue)
334{
335#ifdef KCONTROL_CODEC
336 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
337#else
338 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
339#endif
340 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
341 unsigned int nConfiguration = pValue->value.integer.value[0];
342 int ret = 0;
343
344 ret = tas2559_set_config(pTAS2559, nConfiguration);
345
346 return ret;
347}
348
349static int tas2559_calibration_get(struct snd_kcontrol *pKcontrol,
350 struct snd_ctl_elem_value *pValue)
351{
352#ifdef KCONTROL_CODEC
353 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
354#else
355 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
356#endif
357 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
358
359 pValue->value.integer.value[0] = pTAS2559->mnCurrentCalibration;
360 dev_info(pTAS2559->dev,
361 "tas2559_calibration_get = %d\n",
362 pTAS2559->mnCurrentCalibration);
363
364 return 0;
365}
366
367static int tas2559_calibration_put(struct snd_kcontrol *pKcontrol,
368 struct snd_ctl_elem_value *pValue)
369{
370#ifdef KCONTROL_CODEC
371 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
372#else
373 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
374#endif
375 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
376 unsigned int nCalibration = pValue->value.integer.value[0];
377 int ret = 0;
378
379 ret = tas2559_set_calibration(pTAS2559, nCalibration);
380
381 return ret;
382}
383
384static int tas2559_DevA_DAC_gain_get(struct snd_kcontrol *pKcontrol,
385 struct snd_ctl_elem_value *pValue)
386{
387#ifdef KCONTROL_CODEC
388 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
389#else
390 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
391#endif
392 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
393 unsigned char nGain = 0;
394 int ret = -1;
395
396 ret = tas2559_get_DAC_gain(pTAS2559, DevA, &nGain);
397 if(ret >= 0){
398 pValue->value.integer.value[0] = nGain;
399 }
400
401 dev_dbg(pTAS2559->dev, "%s, ret = %d, %d\n", __func__, ret, nGain);
402
403 return ret;
404}
405
406static int tas2559_DevA_DAC_gain_set(struct snd_kcontrol *pKcontrol,
407 struct snd_ctl_elem_value *pValue)
408{
409#ifdef KCONTROL_CODEC
410 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
411#else
412 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
413#endif
414 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
415 unsigned int nGain = pValue->value.integer.value[0];
416 int ret = 0;
417
418 ret = tas2559_set_DAC_gain(pTAS2559, DevA, nGain);
419
420 return ret;
421}
422
423static int tas2559_DevB_DAC_gain_get(struct snd_kcontrol *pKcontrol,
424 struct snd_ctl_elem_value *pValue)
425{
426#ifdef KCONTROL_CODEC
427 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
428#else
429 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
430#endif
431 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
432 unsigned char nGain = 0;
433 int ret = -1;
434
435 ret = tas2559_get_DAC_gain(pTAS2559, DevB, &nGain);
436 if(ret >= 0){
437 pValue->value.integer.value[0] = nGain;
438 }
439
440 dev_dbg(pTAS2559->dev, "%s, ret = %d, %d\n", __func__, ret, nGain);
441
442 return ret;
443}
444
445static int tas2559_DevB_DAC_gain_set(struct snd_kcontrol *pKcontrol,
446 struct snd_ctl_elem_value *pValue)
447{
448#ifdef KCONTROL_CODEC
449 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
450#else
451 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
452#endif
453 struct tas2559_priv *pTAS2559 = snd_soc_codec_get_drvdata(codec);
454 unsigned int nGain = pValue->value.integer.value[0];
455 int ret = 0;
456
457 ret = tas2559_set_DAC_gain(pTAS2559, DevB, nGain);
458
459 return ret;
460}
461
462static const struct snd_kcontrol_new tas2559_snd_controls[] = {
463 SOC_SINGLE_EXT("DevA DAC Playback Volume", SND_SOC_NOPM, 0, 0x0f, 0,
464 tas2559_DevA_DAC_gain_get, tas2559_DevA_DAC_gain_set),
465 SOC_SINGLE_EXT("DevB DAC Playback Volume", SND_SOC_NOPM, 0, 0x0f, 0,
466 tas2559_DevB_DAC_gain_get, tas2559_DevB_DAC_gain_set),
467 SOC_SINGLE_EXT("PowerCtrl", SND_SOC_NOPM, 0, 0x0001, 0,
468 tas2559_power_ctrl_get, tas2559_power_ctrl_put),
469 SOC_SINGLE_EXT("Program", SND_SOC_NOPM, 0, 0x00FF, 0, tas2559_program_get,
470 tas2559_program_put),
471 SOC_SINGLE_EXT("Configuration", SND_SOC_NOPM, 0, 0x00FF, 0,
472 tas2559_configuration_get, tas2559_configuration_put),
473 SOC_SINGLE_EXT("FS", SND_SOC_NOPM, 8000, 48000, 0,
474 tas2559_fs_get, tas2559_fs_put),
475 SOC_SINGLE_EXT("Calibration", SND_SOC_NOPM, 0, 0x00FF, 0,
476 tas2559_calibration_get, tas2559_calibration_put),
477};
478
479static struct snd_soc_codec_driver soc_codec_driver_tas2559 = {
480 .probe = tas2559_codec_probe,
481 .remove = tas2559_codec_remove,
482 .read = tas2559_codec_read,
483 .write = tas2559_codec_write,
484 .set_bias_level = tas2559_set_bias_level,
485 .idle_bias_off = true,
486 //.ignore_pmdown_time = true,
487 .controls = tas2559_snd_controls,
488 .num_controls = ARRAY_SIZE(tas2559_snd_controls),
489 .dapm_widgets = tas2559_dapm_widgets,
490 .num_dapm_widgets = ARRAY_SIZE(tas2559_dapm_widgets),
491 .dapm_routes = tas2559_audio_map,
492 .num_dapm_routes = ARRAY_SIZE(tas2559_audio_map),
493};
494
495static struct snd_soc_dai_ops tas2559_dai_ops = {
496 .startup = tas2559_startup,
497 .shutdown = tas2559_shutdown,
498 .digital_mute = tas2559_mute,
499 .hw_params = tas2559_hw_params,
500 .prepare = tas2559_prepare,
501 .set_sysclk = tas2559_set_dai_sysclk,
502 .set_fmt = tas2559_set_dai_fmt,
503};
504
505#define TAS2559_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
506 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
507static struct snd_soc_dai_driver tas2559_dai_driver[] = {
508 {
509 .name = "tas2559 ASI1",
510 .id = 0,
511 .playback = {
512 .stream_name = "ASI1 Playback",
513 .channels_min = 2,
514 .channels_max = 2,
515 .rates = SNDRV_PCM_RATE_8000_192000,
516 .formats = TAS2559_FORMATS,
517 },
518 .ops = &tas2559_dai_ops,
519 .symmetric_rates = 1,
520 },
521 {
522 .name = "tas2559 ASI2",
523 .id = 1,
524 .playback = {
525 .stream_name = "ASI2 Playback",
526 .channels_min = 2,
527 .channels_max = 2,
528 .rates = SNDRV_PCM_RATE_8000_192000,
529 .formats = TAS2559_FORMATS,
530 },
531 .ops = &tas2559_dai_ops,
532 .symmetric_rates = 1,
533 },
534 {
535 .name = "tas2559 ASIM",
536 .id = 2,
537 .playback = {
538 .stream_name = "ASIM Playback",
539 .channels_min = 2,
540 .channels_max = 2,
541 .rates = SNDRV_PCM_RATE_8000_192000,
542 .formats = TAS2559_FORMATS,
543 },
544 .ops = &tas2559_dai_ops,
545 .symmetric_rates = 1,
546 },
547};
548
549int tas2559_register_codec(struct tas2559_priv *pTAS2559)
550{
551 int nResult = 0;
552
553 dev_info(pTAS2559->dev, "%s, enter\n", __FUNCTION__);
554
555 nResult = snd_soc_register_codec(pTAS2559->dev,
556 &soc_codec_driver_tas2559,
557 tas2559_dai_driver, ARRAY_SIZE(tas2559_dai_driver));
558
559 return nResult;
560}
561
562int tas2559_deregister_codec(struct tas2559_priv *pTAS2559)
563{
564 snd_soc_unregister_codec(pTAS2559->dev);
565
566 return 0;
567}
568
569MODULE_AUTHOR("Texas Instruments Inc.");
570MODULE_DESCRIPTION("TAS2559 ALSA SOC Smart Amplifier Stereo driver");
571MODULE_LICENSE("GPLv2");
572#endif
diff --git a/tas2559-codec.h b/tas2559-codec.h
new file mode 100755
index 0000000..398300c
--- /dev/null
+++ b/tas2559-codec.h
@@ -0,0 +1,34 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tas2559-codec.h
19**
20** Description:
21** header file for tas2559-codec.c
22**
23** =============================================================================
24*/
25
26#ifndef _TAS2559_CODEC_H
27#define _TAS2559_CODEC_H
28
29#include "tas2559.h"
30
31int tas2559_register_codec(struct tas2559_priv *pTAS2559);
32int tas2559_deregister_codec(struct tas2559_priv *pTAS2559);
33
34#endif /* _TAS2559_CODEC_H */
diff --git a/tas2559-core.c b/tas2559-core.c
new file mode 100755
index 0000000..e51fbe8
--- /dev/null
+++ b/tas2559-core.c
@@ -0,0 +1,1532 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tas2559-core.c
19**
20** Description:
21** TAS2559 common functions for Android Linux
22**
23** =============================================================================
24*/
25
26#define DEBUG
27#include <linux/module.h>
28#include <linux/moduleparam.h>
29#include <linux/init.h>
30#include <linux/delay.h>
31#include <linux/pm.h>
32#include <linux/i2c.h>
33#include <linux/gpio.h>
34#include <linux/regulator/consumer.h>
35#include <linux/firmware.h>
36#include <linux/regmap.h>
37#include <linux/of.h>
38#include <linux/of_gpio.h>
39#include <linux/slab.h>
40#include <linux/syscalls.h>
41#include <linux/fcntl.h>
42#include <asm/uaccess.h>
43
44#include "tas2559-core.h"
45#include "tas2560-core.h"
46
47#define TAS2559_CAL_NAME "/data/tas2559_cal.bin"
48
49static void tas2559_load_configuration(struct tas2559_priv *pTAS2559,
50 unsigned int nConfiguration, bool bLoadSame);
51
52#define TAS2559_UDELAY 0xFFFFFFFE
53#define TAS2559_MDELAY 0xFFFFFFFD
54
55#define FW_ERR_HEADER -1
56#define FW_ERR_SIZE -2
57
58#define TAS2559_BLOCK_PLL 0x00
59#define TAS2559_BLOCK_PGM_ALL 0x0d
60#define TAS2559_BLOCK_PGM_DEV_A 0x01
61#define TAS2559_BLOCK_PGM_DEV_B 0x08
62#define TAS2559_BLOCK_CFG_COEFF_DEV_A 0x03
63#define TAS2559_BLOCK_CFG_COEFF_DEV_B 0x0a
64#define TAS2559_BLOCK_CFG_PRE_DEV_A 0x04
65#define TAS2559_BLOCK_CFG_PRE_DEV_B 0x0b
66#define TAS2559_BLOCK_CFG_POST 0x05
67#define TAS2559_BLOCK_CFG_POST_POWER 0x06
68#define TAS2559_BLOCK_CFG_CAL_A 0x10
69#define TAS2559_BLOCK_CFG_CAL_B 0x20
70
71static unsigned int p_tas2559_dboost_data[] = {
72 TAS2559_DBOOST_CTL_REG, 0x08, //enable, 0x0c=disable
73 TAS2559_DBOOST_CFG_REG, 0x03, //threshold -18dB +hysteresis 4dB
74 0xFFFFFFFF, 0xFFFFFFFF
75};
76
77//This is only needed for PG1.0
78static unsigned int p_tas2559_vpred_comp_data[] =
79{
80//Reverse attenuation compensation for Vpred 0.5dB
81 TAS2559_VPRED_COMP_REG, 0x04, 0x43, 0xca, 0xd0, 0x22,
82 0xFFFFFFFF, 0xFFFFFFFF
83};
84
85//This is only needed for PG1.0.
86static unsigned int p_tas2559_thermal_foldback_data[] = {
87 TAS2559_THERMAL_FOLDBACK_REG, 0x04, 0x48, 0x00, 0x00, 0x00, //disable
88 0xFFFFFFFF, 0xFFFFFFFF
89};
90
91static unsigned int p_tas2559_boost_8Ohm_data[] =
92{
93 TAS2559_BOOST_HEADROOM, 0x04, 0x04, 0xcc, 0xcc, 0xcc, // boost headroom 600mv
94 TAS2559_BOOSTOFF_EFFICIENCY, 0x04, 0x67, 0xae,0x14,0x7a, //boost off efficiency 0.81
95 0xFFFFFFFF, 0xFFFFFFFF
96};
97
98static unsigned int p_tas2559_boost_6Ohm_data[] =
99{
100 TAS2559_BOOST_HEADROOM, 0x04, 0x06, 0x66, 0x66, 0x66, // boost headroom 800mv
101 0xFFFFFFFF, 0xFFFFFFFF
102};
103
104static unsigned int p_tas2559_boost_4Ohm_data[] =
105{
106 TAS2559_BOOST_HEADROOM, 0x04, 0x06, 0x66, 0x66, 0x66, // boost headroom 800mv
107 TAS2559_BOOSTON_EFFICIENCY, 0x04, 0x73, 0x33, 0x33, 0x33,
108 TAS2559_BOOSTOFF_EFFICIENCY, 0x04, 0x60, 0x00,0x00,0x00, //boost off efficiency 0.75
109 0xFFFFFFFF, 0xFFFFFFFF
110};
111
112/* This is only required for PG2.0*/
113static unsigned int p_tas2559_isense_threshold_data[] =
114{
115 TAS2559_ISENSE_THRESHOLD, 0x04, 0, 0, 0, 0, // Make Isense threshold zero
116 0xFFFFFFFF, 0xFFFFFFFF
117};
118
119static unsigned int p_tas2559_irq_config[] =
120{
121 //channel_both, TAS2559_GPIO4_PIN_REG, 0x07, // set GPIO4 as int1, default
122 DevA, TAS2559_INT_GEN1_REG, 0x11, // enable spk OC and OV
123 DevA, TAS2559_INT_GEN2_REG, 0x11, // enable clk err1 and die OT
124 DevA, TAS2559_INT_GEN3_REG, 0x11, // enable clk err2 and brownout
125 DevA, TAS2559_INT_GEN4_REG, 0x01, // disable SAR, enable clk halt
126 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
127};
128
129static unsigned int p_tas2559_startup_data[] = {
130 DevA, TAS2559_CLK_ERR_CTRL, 0x03, //enable clock error detection
131 DevB, TAS2560_MUTE_REG, 0x41,
132 DevA, TAS2559_POWER_CTRL2_REG, 0xA0, //Class-D, Boost power up
133 DevA, TAS2559_POWER_CTRL2_REG, 0xA3, //Class-D, Boost, IV sense power up
134 DevA, TAS2559_POWER_CTRL1_REG, 0xF8, //PLL, DSP, clock dividers power up
135 DevA, TAS2559_UDELAY, 2000, //delay
136 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
137};
138
139static unsigned int p_tas2559_unmute_data[] = {
140 DevA, TAS2559_MUTE_REG, 0x00, //unmute
141 DevB, TAS2560_MUTE_REG, 0x40,
142 DevA, TAS2559_SOFT_MUTE_REG, 0x00, //soft unmute
143 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
144};
145
146static unsigned int p_tas2559_shutdown_data[] = {
147 DevA, TAS2559_SOFT_MUTE_REG, 0x01, //soft mute
148 DevB, TAS2560_MUTE_REG, 0x41,
149 DevA, TAS2559_UDELAY, 10000, //delay 10ms
150 DevA, TAS2559_MUTE_REG, 0x03, //mute
151 DevA, TAS2559_POWER_CTRL1_REG, 0x60, //DSP power down
152 DevA, TAS2559_UDELAY, 2000, //delay 2ms
153 DevA, TAS2559_POWER_CTRL2_REG, 0x00, //Class-D, Boost power down
154 DevA, TAS2559_POWER_CTRL1_REG, 0x00, //all power down
155 DevB, TAS2560_MUTE_REG, 0x01,
156 DevA, TAS2559_UDELAY, 30000, //delay 30ms
157 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
158};
159
160static unsigned int p_tas2559_mute_DSP_down_data[] = {
161 DevA, TAS2559_MUTE_REG, 0x03, //mute
162 DevB, TAS2560_MUTE_REG, 0x41,
163 DevA, TAS2559_POWER_CTRL1_REG, 0x60, //DSP power down
164 DevB, TAS2560_MUTE_REG, 0x01,
165 DevA, TAS2559_UDELAY, 30000, //delay 30ms
166 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
167};
168
169static int tas2559_dev_load_data(struct tas2559_priv *pTAS2559,
170 unsigned int *pData)
171{
172 int ret = 0;
173 unsigned int n = 0;
174 enum channel chl;
175 unsigned int nRegister;
176 unsigned int nData;
177
178 do {
179 chl = pData[n * 3];
180 nRegister = pData[n * 3 + 1];
181 nData = pData[n * 3 + 2];
182 if (nRegister == TAS2559_UDELAY)
183 udelay(nData);
184 else if (nRegister != 0xFFFFFFFF){
185 ret = pTAS2559->write(pTAS2559, chl, nRegister, nData);
186 if(ret < 0) {
187 dev_err(pTAS2559->dev, "Reg Write err %d\n", ret);
188 break;
189 }
190 }
191 n++;
192 } while (nRegister != 0xFFFFFFFF);
193
194 return ret;
195}
196
197int tas2559_dev_load_blk_data(
198 struct tas2559_priv *pTAS2559,
199 enum channel chl,
200 unsigned int *pData)
201{
202 unsigned int nRegister;
203 unsigned int *nData;
204 unsigned char Buf[128];
205 unsigned int nLength = 0;
206 unsigned int i =0;
207 unsigned int nSize = 0;
208 int ret = 0;
209
210 do{
211 nRegister = pData[nLength];
212 nSize = pData[nLength + 1];
213 nData = &pData[nLength + 2];
214 if (nRegister == TAS2559_MDELAY){
215 mdelay(nData[0]);
216 }
217 else{
218 if (nRegister != 0xFFFFFFFF){
219 if(nSize > 128){
220 dev_err(pTAS2559->dev,
221 "%s, Line=%d, invalid size, maximum is 128 bytes!\n",
222 __FUNCTION__, __LINE__);
223 break;
224 }
225
226 if(nSize > 1){
227 for(i = 0; i < nSize; i++) Buf[i] = (unsigned char)nData[i];
228 ret = pTAS2559->bulk_write(pTAS2559, chl, nRegister, Buf, nSize);
229 }else if(nSize == 1){
230 ret = pTAS2559->write(pTAS2559,chl,nRegister, nData[0]);
231 }else{
232 dev_err(pTAS2559->dev,
233 "%s, Line=%d,invalid size, minimum is 1 bytes!\n",
234 __FUNCTION__, __LINE__);
235 }
236
237 if(ret < 0) break;
238 }
239 }
240 nLength = nLength + 2 + pData[nLength+1] ;
241 } while (nRegister != 0xFFFFFFFF);
242
243 return ret;
244}
245
246void tas2559_configIRQ(struct tas2559_priv *pTAS2559)
247{
248 tas2559_dev_load_data(pTAS2559, p_tas2559_irq_config);
249}
250
251int tas2559_DevA_setLoad(struct tas2559_priv *pTAS2559, int load)
252{
253 int ret = 0;
254
255 ret = pTAS2559->write(pTAS2559,
256 DevA,
257 TAS2559_SNS_CTRL_REG, (load&0x03)<<1);
258 if(ret<0)
259 goto err;
260
261 switch(load)
262 {
263 case LOAD_8OHM: //8Ohm
264 ret = tas2559_dev_load_blk_data(pTAS2559,
265 DevA,
266 p_tas2559_boost_8Ohm_data);
267 break;
268
269 case LOAD_6OHM: //6Ohm
270 ret = tas2559_dev_load_blk_data(pTAS2559,
271 DevA,
272 p_tas2559_boost_6Ohm_data);
273 break;
274
275 case LOAD_4OHM: //4Ohm
276 ret = tas2559_dev_load_blk_data(pTAS2559,
277 DevA,
278 p_tas2559_boost_4Ohm_data);
279 break;
280 }
281
282err:
283
284 return ret;
285}
286
287int tas2559_DevA_setChannel(struct tas2559_priv *pTAS2559, int channel)
288{
289 int ret = 0;
290 unsigned char val = 0;
291
292 switch(channel)
293 {
294 case CHANNEL_LEFT:
295 val = 0;
296 break;
297
298 case CHANNEL_RIGHT:
299 val = 1;
300 break;
301
302 default:
303 ret = -1;
304 break;
305 }
306
307 if(ret >= 0){
308 ret = pTAS2559->update_bits(pTAS2559, DevA, TAS2559_ASI_CTRL_REG, 0x06, val<<1);
309 }
310
311 if(ret < 0){
312 dev_err(pTAS2559->dev, "devA Channel err %d\n", channel);
313 }
314
315 return ret;
316}
317
318int tas2559_load_DevA_platdata(struct tas2559_priv *pTAS2559)
319{
320 int ret = 0;
321
322 ret = tas2559_DevA_setLoad(pTAS2559, pTAS2559->mnDevALoad);
323 ret = tas2559_DevA_setChannel(pTAS2559, pTAS2559->mnDevAChl);
324 ret = tas2559_set_bit_rate(pTAS2559, DevA, pTAS2559->mnBitRate);
325
326 return ret;
327}
328
329int tas2559_load_DevA_default(struct tas2559_priv *pTAS2559)
330{
331 int ret = 0;
332
333 ret = tas2559_dev_load_blk_data(pTAS2559,
334 DevA,
335 p_tas2559_dboost_data);
336 if(ret < 0) goto err;
337
338 /* This is not required for PG1.0 and 2.1, only PG2.0*/
339 if(pTAS2559->mnDevAPGID
340 == TAS2559_PG_VERSION_2P0)
341 ret = tas2559_dev_load_blk_data(pTAS2559,
342 DevA,
343 p_tas2559_isense_threshold_data);
344
345 if(pTAS2559->mnDevAPGID
346 == TAS2559_PG_VERSION_1P0){
347 tas2559_dev_load_blk_data(pTAS2559,
348 DevA,
349 p_tas2559_vpred_comp_data);
350 tas2559_dev_load_blk_data(pTAS2559,
351 DevA,
352 p_tas2559_thermal_foldback_data);
353 }
354
355 if(pTAS2559->mnDevAPGID
356 == TAS2559_PG_VERSION_2P0)
357 ret = tas2559_dev_load_blk_data(pTAS2559,
358 DevA,
359 p_tas2559_isense_threshold_data);
360
361 if(pTAS2559->mnDevAPGID
362 == TAS2559_PG_VERSION_1P0){
363 tas2559_dev_load_blk_data(pTAS2559,
364 DevA,
365 p_tas2559_vpred_comp_data);
366 tas2559_dev_load_blk_data(pTAS2559,
367 DevA,
368 p_tas2559_thermal_foldback_data);
369 }
370
371 tas2559_load_DevA_platdata(pTAS2559);
372
373err:
374
375 return ret;
376}
377
378void tas2559_enable(struct tas2559_priv *pTAS2559, bool bEnable)
379{
380 dev_dbg(pTAS2559->dev, "Enable: %d\n", bEnable);
381 if (bEnable) {
382 if (!pTAS2559->mbPowerUp) {
383 dev_dbg(pTAS2559->dev, "Enable: load startup sequence\n");
384 tas2559_dev_load_data(pTAS2559, p_tas2559_startup_data);
385 tas2559_load_DevB_Runtime(pTAS2559);
386 dev_dbg(pTAS2559->dev, "Enable: load unmute sequence\n");
387 tas2559_dev_load_data(pTAS2559, p_tas2559_unmute_data);
388 pTAS2559->enableIRQ(pTAS2559, 1);
389 pTAS2559->mbPowerUp = true;
390 }
391 } else {
392 if (pTAS2559->mbPowerUp) {
393 dev_dbg(pTAS2559->dev, "Enable: load shutdown sequence\n");
394 tas2559_dev_load_data(pTAS2559, p_tas2559_shutdown_data);
395 pTAS2559->enableIRQ(pTAS2559, 0);
396 //tas2559_dev_load_data(pTAS2559, p_tas2559_shutdown_clk_err);
397 pTAS2559->mbPowerUp = false;
398 }
399 }
400}
401
402int tas2559_set_bit_rate(struct tas2559_priv *pTAS2559,
403 enum channel chn, unsigned int nBitRate)
404{
405 int ret = 0, n = -1;
406
407 dev_dbg(pTAS2559->dev, "tas2559_set_bit_rate: nBitRate = %d \n",
408 nBitRate);
409 switch(nBitRate){
410 case 16:
411 n = 0;
412 break;
413 case 20:
414 n = 1;
415 break;
416 case 24:
417 n = 2;
418 break;
419 case 32:
420 n = 3;
421 break;
422 }
423
424 if(n >= 0){
425 if(chn & DevA){
426 ret = pTAS2559->update_bits(pTAS2559, DevA,
427 TAS2559_ASI1_DAC_FORMAT_REG, 0x18, n<<3);
428 }
429
430 if(chn & DevB){
431 ret = pTAS2559->update_bits(pTAS2559, DevB,
432 TAS2560_DAI_FMT, 0x03, n);
433 }
434 }
435
436 return ret;
437}
438
439int tas2559_get_bit_rate(struct tas2559_priv *pTAS2559,
440 enum channel chn, unsigned char *pBitRate)
441{
442 int ret = -1;
443 unsigned int nValue = 0;
444 unsigned char bitRate;
445
446 if(chn == DevA){
447 ret = pTAS2559->read(pTAS2559, DevA,
448 TAS2559_ASI1_DAC_FORMAT_REG, &nValue);
449 if(ret >=0){
450 bitRate = (nValue&0x18)>>3;
451 }
452 }else if(chn == DevB){
453 ret = pTAS2559->read(pTAS2559, DevB,
454 TAS2560_DAI_FMT, &nValue);
455 if(ret >=0){
456 bitRate = (nValue&0x03);
457 }
458 }
459
460 if(ret >=0){
461 if(bitRate == 0) bitRate = 16;
462 else if(bitRate == 1) bitRate = 20;
463 else if(bitRate == 2) bitRate = 24;
464 else if(bitRate == 3) bitRate = 32;
465
466 *pBitRate = bitRate;
467 }
468
469 return ret;
470}
471
472int tas2559_get_DAC_gain(struct tas2559_priv *pTAS2559, enum channel chl, unsigned char *pnGain)
473{
474 int ret = 0;
475 unsigned int nValue = 0;
476
477 if(chl == DevA){
478 ret = pTAS2559->read(pTAS2559, DevA, TAS2559_SPK_CTRL_REG, &nValue);
479 if(ret >=0){
480 *pnGain = ((nValue&TAS2559_DAC_GAIN_MASK)>>TAS2559_DAC_GAIN_SHIFT);
481 }
482 }else if(chl == DevB){
483 ret = tas2559_DevB_get_volume(pTAS2559, &nValue);
484 if(ret >=0){
485 *pnGain = (unsigned char)nValue;
486 }
487 }
488
489 return ret;
490}
491
492int tas2559_set_DAC_gain(struct tas2559_priv *pTAS2559, enum channel chl, unsigned int nGain)
493{
494 int ret = 0;
495
496 if(chl&DevA){
497 ret = pTAS2559->update_bits(pTAS2559, DevA,
498 TAS2559_SPK_CTRL_REG,
499 TAS2559_DAC_GAIN_MASK,
500 (nGain<<TAS2559_DAC_GAIN_SHIFT));
501 }
502
503 if(chl&DevB){
504 ret = tas2559_DevB_set_volume(pTAS2559, nGain&0x0f);
505 }
506
507 return ret;
508}
509
510int tas2559_set_sampling_rate(struct tas2559_priv *pTAS2559, unsigned int nSamplingRate)
511{
512 TConfiguration *pConfiguration;
513 unsigned int nConfiguration;
514
515 dev_dbg(pTAS2559->dev, "tas2559_setup_clocks: nSamplingRate = %d [Hz]\n",
516 nSamplingRate);
517
518 if ((!pTAS2559->mpFirmware->mpPrograms) ||
519 (!pTAS2559->mpFirmware->mpConfigurations)) {
520 dev_err(pTAS2559->dev, "Firmware not loaded\n");
521 return -EINVAL;
522 }
523
524 pConfiguration = &(pTAS2559->mpFirmware->mpConfigurations[pTAS2559->mnCurrentConfiguration]);
525 if (pConfiguration->mnSamplingRate == nSamplingRate) {
526 dev_info(pTAS2559->dev, "Sampling rate for current configuration matches: %d\n",
527 nSamplingRate);
528 return 0;
529 }
530
531 for (nConfiguration = 0;
532 nConfiguration < pTAS2559->mpFirmware->mnConfigurations;
533 nConfiguration++) {
534 pConfiguration =
535 &(pTAS2559->mpFirmware->mpConfigurations[nConfiguration]);
536 if ((pConfiguration->mnSamplingRate == nSamplingRate)
537 &&(pConfiguration->mnProgram == pTAS2559->mnCurrentProgram)){
538 dev_info(pTAS2559->dev,
539 "Found configuration: %s, with compatible sampling rate %d\n",
540 pConfiguration->mpName, nSamplingRate);
541 tas2559_load_configuration(pTAS2559, nConfiguration, false);
542 return 0;
543 }
544 }
545
546 dev_err(pTAS2559->dev, "Cannot find a configuration that supports sampling rate: %d\n",
547 nSamplingRate);
548
549 return -EINVAL;
550}
551
552static void fw_print_header(struct tas2559_priv *pTAS2559, TFirmware * pFirmware)
553{
554 dev_info(pTAS2559->dev, "FW Size = %d", pFirmware->mnFWSize);
555 dev_info(pTAS2559->dev, "Checksum = 0x%04X", pFirmware->mnChecksum);
556 dev_info(pTAS2559->dev, "PPC Version = 0x%04X", pFirmware->mnPPCVersion);
557 dev_info(pTAS2559->dev, "FW Version = 0x%04X", pFirmware->mnFWVersion);
558 dev_info(pTAS2559->dev, "Driver Version= 0x%04X", pFirmware->mnDriverVersion);
559 dev_info(pTAS2559->dev, "Timestamp = %d", pFirmware->mnTimeStamp);
560 dev_info(pTAS2559->dev, "DDC Name = %s", pFirmware->mpDDCName);
561 dev_info(pTAS2559->dev, "Description = %s", pFirmware->mpDescription);
562}
563
564inline unsigned int fw_convert_number(unsigned char *pData)
565{
566 return pData[3] + (pData[2] << 8) + (pData[1] << 16) + (pData[0] << 24);
567}
568
569static int fw_parse_header(struct tas2559_priv *pTAS2559,
570 TFirmware * pFirmware, unsigned char *pData,
571 unsigned int nSize)
572{
573 unsigned char *pDataStart = pData;
574 unsigned int n;
575 unsigned char pMagicNumber[] = { 0x35, 0x35, 0x35, 0x32 };
576 if (nSize < 104) {
577 dev_err(pTAS2559->dev, "Firmware: Header too short");
578 return -1;
579 }
580
581 if (memcmp(pData, pMagicNumber, 4)) {
582 dev_err(pTAS2559->dev, "Firmware: Magic number doesn't match");
583 return -1;
584 }
585
586 pData += 4;
587
588 pFirmware->mnFWSize = fw_convert_number(pData);
589 pData += 4;
590
591 pFirmware->mnChecksum = fw_convert_number(pData);
592 pData += 4;
593
594 pFirmware->mnPPCVersion = fw_convert_number(pData);
595 pData += 4;
596
597 pFirmware->mnFWVersion = fw_convert_number(pData);
598 pData += 4;
599
600 pFirmware->mnDriverVersion = fw_convert_number(pData);
601 pData += 4;
602
603 pFirmware->mnTimeStamp = fw_convert_number(pData);
604 pData += 4;
605
606 memcpy(pFirmware->mpDDCName, pData, 64);
607 pData += 64;
608
609 n = strlen(pData);
610 pFirmware->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
611 pData += n + 1;
612
613 if ((pData - pDataStart) >= nSize) {
614 dev_err(pTAS2559->dev, "Firmware: Header too short after DDC description");
615 return -1;
616 }
617
618 pFirmware->mnDeviceFamily = fw_convert_number(pData);
619 pData += 4;
620
621 if(pFirmware->mnDeviceFamily != 0){
622 dev_err(pTAS2559->dev,
623 "deviceFamily %d, not TAS device", pFirmware->mnDeviceFamily);
624 return -1;
625 }
626
627 pFirmware->mnDevice = fw_convert_number(pData);
628 pData += 4;
629
630 if(pFirmware->mnDevice != 3){
631 dev_err(pTAS2559->dev,
632 "device %d, not TAS2559", pFirmware->mnDevice);
633 return -1;
634 }
635
636 fw_print_header(pTAS2559, pFirmware);
637
638 return pData - pDataStart;
639}
640
641static int fw_parse_block_data(struct tas2559_priv *pTAS2559,
642 TBlock * pBlock, unsigned char *pData)
643{
644 unsigned char *pDataStart = pData;
645 unsigned int n;
646
647 pBlock->mnType = fw_convert_number(pData);
648 pData += 4;
649
650 dev_dbg(pTAS2559->dev, "TBlock type[%d]\n", pBlock->mnType);
651
652 pBlock->mnCommands = fw_convert_number(pData);
653 pData += 4;
654
655 n = pBlock->mnCommands * 4;
656 pBlock->mpData = kmemdup(pData, n, GFP_KERNEL);
657 pData += n;
658
659 return pData - pDataStart;
660}
661
662static int fw_parse_data(struct tas2559_priv *pTAS2559,
663 TData * pImageData, unsigned char *pData)
664{
665 unsigned char *pDataStart = pData;
666 unsigned int nBlock;
667 unsigned int n;
668
669 memcpy(pImageData->mpName, pData, 64);
670 pData += 64;
671
672 n = strlen(pData);
673 pImageData->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
674 pData += n + 1;
675
676 dev_dbg(pTAS2559->dev, "TData name=%s\n", pImageData->mpName);
677 dev_dbg(pTAS2559->dev, "TData Desc=%s\n", pImageData->mpDescription);
678
679 pImageData->mnBlocks = (pData[0] << 8) + pData[1];
680 pData += 2;
681
682 pImageData->mpBlocks =
683 kmalloc(sizeof(TBlock) * pImageData->mnBlocks, GFP_KERNEL);
684
685 for (nBlock = 0; nBlock < pImageData->mnBlocks; nBlock++) {
686 n = fw_parse_block_data(pTAS2559,
687 &(pImageData->mpBlocks[nBlock]), pData);
688 pData += n;
689 }
690
691 return pData - pDataStart;
692}
693
694static int fw_parse_pll_data(struct tas2559_priv *pTAS2559,
695 TFirmware * pFirmware, unsigned char *pData)
696{
697 unsigned char *pDataStart = pData;
698 unsigned int n;
699 unsigned int nPLL;
700 TPLL *pPLL;
701
702 pFirmware->mnPLLs = (pData[0] << 8) + pData[1];
703 pData += 2;
704
705 pFirmware->mpPLLs = kmalloc(sizeof(TPLL) * pFirmware->mnPLLs, GFP_KERNEL);
706 for (nPLL = 0; nPLL < pFirmware->mnPLLs; nPLL++) {
707 pPLL = &(pFirmware->mpPLLs[nPLL]);
708
709 memcpy(pPLL->mpName, pData, 64);
710 pData += 64;
711
712 n = strlen(pData);
713 pPLL->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
714 pData += n + 1;
715
716 dev_dbg(pTAS2559->dev, "PLL[%d] Name=%s\n", nPLL, pPLL->mpName);
717 dev_dbg(pTAS2559->dev, "PLL[%d] Desc=%s\n", nPLL, pPLL->mpDescription);
718 n = fw_parse_block_data(pTAS2559, &(pPLL->mBlock), pData);
719 pData += n;
720 }
721
722 return pData - pDataStart;
723}
724
725static int fw_parse_program_data(struct tas2559_priv *pTAS2559,
726 TFirmware * pFirmware, unsigned char *pData)
727{
728 unsigned char *pDataStart = pData;
729 unsigned int n;
730 unsigned int nProgram;
731 TProgram *pProgram;
732
733 pFirmware->mnPrograms = (pData[0] << 8) + pData[1];
734 pData += 2;
735
736 pFirmware->mpPrograms =
737 kmalloc(sizeof(TProgram) * pFirmware->mnPrograms, GFP_KERNEL);
738 for (nProgram = 0; nProgram < pFirmware->mnPrograms; nProgram++) {
739 pProgram = &(pFirmware->mpPrograms[nProgram]);
740 memcpy(pProgram->mpName, pData, 64);
741 pData += 64;
742
743 n = strlen(pData);
744 pProgram->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
745 pData += n + 1;
746
747 dev_dbg(pTAS2559->dev, "Program[%d] Name=%s\n", nProgram, pProgram->mpName);
748 dev_dbg(pTAS2559->dev, "Program[%d] Desc=%s\n", nProgram, pProgram->mpDescription);
749
750 pProgram->mnAppMode = pData[0];
751 pData++;
752
753 pProgram->mnBoost = (pData[0] << 8) + pData[1];
754 pData += 2;
755
756 n = fw_parse_data(pTAS2559, &(pProgram->mData), pData);
757 pData += n;
758 }
759
760 return pData - pDataStart;
761}
762
763static int fw_parse_configuration_data(struct tas2559_priv *pTAS2559,
764 TFirmware * pFirmware,
765 unsigned char *pData)
766{
767 unsigned char *pDataStart = pData;
768 unsigned int n;
769 unsigned int nConfiguration;
770 TConfiguration *pConfiguration;
771
772 pFirmware->mnConfigurations = (pData[0] << 8) + pData[1];
773 pData += 2;
774
775 pFirmware->mpConfigurations =
776 kmalloc(sizeof(TConfiguration) * pFirmware->mnConfigurations,
777 GFP_KERNEL);
778 for (nConfiguration = 0; nConfiguration < pFirmware->mnConfigurations;
779 nConfiguration++) {
780 pConfiguration = &(pFirmware->mpConfigurations[nConfiguration]);
781 memcpy(pConfiguration->mpName, pData, 64);
782 pData += 64;
783
784 n = strlen(pData);
785 pConfiguration->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
786 pData += n + 1;
787
788 pConfiguration->mnProgram = pData[0];
789 pData++;
790
791 dev_dbg(pTAS2559->dev, "Configuration[%d] Name=%s\n", nConfiguration, pConfiguration->mpName);
792 dev_dbg(pTAS2559->dev, "Configuration[%d] Desc=%s\n", nConfiguration, pConfiguration->mpDescription);
793
794 pConfiguration->mnPLL = pData[0];
795 pData++;
796
797 pConfiguration->mnSamplingRate = fw_convert_number(pData);
798 pData += 4;
799
800 n = fw_parse_data(pTAS2559, &(pConfiguration->mData), pData);
801 pData += n;
802 }
803
804 return pData - pDataStart;
805}
806
807int fw_parse_calibration_data(struct tas2559_priv *pTAS2559,
808 TFirmware * pFirmware, unsigned char *pData)
809{
810 unsigned char *pDataStart = pData;
811 unsigned int n;
812 unsigned int nCalibration;
813 TCalibration *pCalibration;
814
815 pFirmware->mnCalibrations = (pData[0] << 8) + pData[1];
816 pData += 2;
817
818 pFirmware->mpCalibrations =
819 kmalloc(sizeof(TCalibration) * pFirmware->mnCalibrations, GFP_KERNEL);
820 for (nCalibration = 0;
821 nCalibration < pFirmware->mnCalibrations;
822 nCalibration++) {
823 pCalibration = &(pFirmware->mpCalibrations[nCalibration]);
824 memcpy(pCalibration->mpName, pData, 64);
825 pData += 64;
826
827 n = strlen(pData);
828 pCalibration->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
829 pData += n + 1;
830
831 pCalibration->mnProgram = pData[0];
832 pData++;
833
834 pCalibration->mnConfiguration = pData[0];
835 pData++;
836
837 n = fw_parse_block_data(pTAS2559, &(pCalibration->mBlock), pData);
838 pData += n;
839 }
840
841 return pData - pDataStart;
842}
843
844static int fw_parse(struct tas2559_priv *pTAS2559,
845 TFirmware * pFirmware,
846 unsigned char *pData,
847 unsigned int nSize)
848{
849 int nPosition = 0;
850
851 nPosition = fw_parse_header(pTAS2559, pFirmware, pData, nSize);
852 if (nPosition < 0) {
853 dev_err(pTAS2559->dev, "Firmware: Wrong Header");
854 return FW_ERR_HEADER;
855 }
856
857 if (nPosition >= nSize) {
858 dev_err(pTAS2559->dev, "Firmware: Too short");
859 return FW_ERR_SIZE;
860 }
861
862 pData += nPosition;
863 nSize -= nPosition;
864 nPosition = 0;
865
866 nPosition = fw_parse_pll_data(pTAS2559, pFirmware, pData);
867
868 pData += nPosition;
869 nSize -= nPosition;
870 nPosition = 0;
871
872 nPosition = fw_parse_program_data(pTAS2559, pFirmware, pData);
873
874 pData += nPosition;
875 nSize -= nPosition;
876 nPosition = 0;
877
878 nPosition = fw_parse_configuration_data(pTAS2559, pFirmware, pData);
879
880 pData += nPosition;
881 nSize -= nPosition;
882 nPosition = 0;
883
884 if (nSize > 64)
885 nPosition = fw_parse_calibration_data(pTAS2559, pFirmware, pData);
886
887 return 0;
888}
889
890static void tas2559_load_block(struct tas2559_priv *pTAS2559, TBlock * pBlock)
891{
892 unsigned int nCommand = 0;
893 unsigned char nBook;
894 unsigned char nPage;
895 unsigned char nOffset;
896 unsigned char nData;
897 unsigned int nLength;
898 enum channel chl;
899 unsigned char *pData = pBlock->mpData;
900
901 dev_dbg(pTAS2559->dev, "TAS2559 load block: Type = %d, commands = %d\n",
902 pBlock->mnType, pBlock->mnCommands);
903
904 if(pBlock->mnType == TAS2559_BLOCK_PLL){
905 chl = DevA;
906 }else if((pBlock->mnType == TAS2559_BLOCK_PGM_DEV_A)
907 ||(pBlock->mnType == TAS2559_BLOCK_CFG_COEFF_DEV_A)
908 ||(pBlock->mnType == TAS2559_BLOCK_CFG_PRE_DEV_A)){
909 chl = DevA;
910 }else if((pBlock->mnType == TAS2559_BLOCK_PGM_DEV_B)
911 ||(pBlock->mnType == TAS2559_BLOCK_CFG_COEFF_DEV_B)
912 ||(pBlock->mnType == TAS2559_BLOCK_CFG_PRE_DEV_B)){
913 chl = DevB;
914 }else{
915 dev_err(pTAS2559->dev, "block type error %d\n", pBlock->mnType);
916 return;
917 }
918
919 while (nCommand < pBlock->mnCommands) {
920 pData = pBlock->mpData + nCommand * 4;
921
922 nBook = pData[0];
923 nPage = pData[1];
924 nOffset = pData[2];
925 nData = pData[3];
926
927 nCommand++;
928
929 if (nOffset <= 0x7F){
930 pTAS2559->write(pTAS2559,
931 chl,
932 TAS2559_REG(nBook, nPage, nOffset),
933 nData);
934 }else if (nOffset == 0x81) {
935 unsigned int nSleep = (nBook << 8) + nPage;
936 msleep(nSleep);
937 }else if (nOffset == 0x85) {
938 pData += 4;
939 nLength = (nBook << 8) + nPage;
940 nBook = pData[0];
941 nPage = pData[1];
942 nOffset = pData[2];
943 if (nLength > 1)
944 pTAS2559->bulk_write(pTAS2559,
945 chl,
946 TAS2559_REG(nBook, nPage, nOffset),
947 pData + 3,
948 nLength);
949 else
950 pTAS2559->write(pTAS2559,
951 chl,
952 TAS2559_REG(nBook, nPage, nOffset),
953 pData[3]);
954
955 nCommand++;
956 if (nLength >= 2)
957 nCommand += ((nLength - 2) / 4) + 1;
958 }
959 }
960}
961
962static void tas2559_load_data(struct tas2559_priv *pTAS2559, TData * pData,
963 unsigned int nType)
964{
965 unsigned int nBlock;
966 TBlock *pBlock;
967
968 dev_dbg(pTAS2559->dev,
969 "TAS2559 load data: %s, Blocks = %d, Block Type = %d\n", pData->mpName,
970 pData->mnBlocks, nType);
971
972 for (nBlock = 0; nBlock < pData->mnBlocks; nBlock++) {
973 pBlock = &(pData->mpBlocks[nBlock]);
974 if (pBlock->mnType == nType)
975 tas2559_load_block(pTAS2559, pBlock);
976 }
977}
978
979static void tas2559_load_configuration(struct tas2559_priv *pTAS2559,
980 unsigned int nConfiguration, bool bLoadSame)
981{
982 TConfiguration *pCurrentConfiguration;
983 TConfiguration *pNewConfiguration;
984 TPLL *pNewPLL;
985
986 dev_dbg(pTAS2559->dev, "tas2559_load_configuration: %d\n", nConfiguration);
987
988 if ((!pTAS2559->mpFirmware->mpPrograms) ||
989 (!pTAS2559->mpFirmware->mpConfigurations)) {
990 dev_err(pTAS2559->dev, "Firmware not loaded\n");
991 return;
992 }
993
994 if (nConfiguration >= pTAS2559->mpFirmware->mnConfigurations) {
995 dev_err(pTAS2559->dev, "Configuration %d doesn't exist\n",
996 nConfiguration);
997 return;
998 }
999
1000 if ((nConfiguration == pTAS2559->mnCurrentConfiguration) && (!bLoadSame)) {
1001 dev_info(pTAS2559->dev, "Configuration %d is already loaded\n",
1002 nConfiguration);
1003 return;
1004 }
1005
1006 pCurrentConfiguration =
1007 &(pTAS2559->mpFirmware->mpConfigurations[pTAS2559->mnCurrentConfiguration]);
1008 pNewConfiguration =
1009 &(pTAS2559->mpFirmware->mpConfigurations[nConfiguration]);
1010
1011 if (pNewConfiguration->mnProgram != pCurrentConfiguration->mnProgram) {
1012 dev_err(pTAS2559->dev,
1013 "Configuration %d, %s doesn't share the same program as current %d\n",
1014 nConfiguration, pNewConfiguration->mpName, pCurrentConfiguration->mnProgram);
1015 return;
1016 }
1017
1018 if (pNewConfiguration->mnPLL >= pTAS2559->mpFirmware->mnPLLs) {
1019 dev_err(pTAS2559->dev,
1020 "Configuration %d, %s doesn't have a valid PLL index %d\n",
1021 nConfiguration, pNewConfiguration->mpName, pNewConfiguration->mnPLL);
1022 return;
1023 }
1024
1025 pNewPLL = &(pTAS2559->mpFirmware->mpPLLs[pNewConfiguration->mnPLL]);
1026
1027 if (pTAS2559->mbPowerUp) {
1028 if (pNewConfiguration->mnPLL != pCurrentConfiguration->mnPLL) {
1029 dev_dbg(pTAS2559->dev,
1030 "TAS2559 is powered up, power down DSP before loading new configuration\n");
1031 tas2559_dev_load_data(pTAS2559, p_tas2559_shutdown_data);
1032 dev_dbg(pTAS2559->dev, "TAS2559: load new PLL: %s, block data\n",
1033 pNewPLL->mpName);
1034 pTAS2559->enableIRQ(pTAS2559, 0);
1035 tas2559_load_block(pTAS2559, &(pNewPLL->mBlock));
1036 pTAS2559->mnCurrentSampleRate = pNewConfiguration->mnSamplingRate;
1037 dev_dbg(pTAS2559->dev,
1038 "load new configuration: %s, pre block data\n",
1039 pNewConfiguration->mpName);
1040 tas2559_load_data(pTAS2559, &(pNewConfiguration->mData),
1041 TAS2559_BLOCK_CFG_PRE_DEV_A);
1042 tas2559_load_data(pTAS2559, &(pNewConfiguration->mData),
1043 TAS2559_BLOCK_CFG_PRE_DEV_B);
1044 dev_dbg(pTAS2559->dev,
1045 "TAS2559: load new configuration: %s, coeff block data\n",
1046 pNewConfiguration->mpName);
1047 tas2559_load_data(pTAS2559, &(pNewConfiguration->mData),
1048 TAS2559_BLOCK_CFG_COEFF_DEV_A);
1049 tas2559_load_data(pTAS2559, &(pNewConfiguration->mData),
1050 TAS2559_BLOCK_CFG_COEFF_DEV_B);
1051 dev_dbg(pTAS2559->dev, "TAS2559: power up TAS2559\n");
1052 tas2559_dev_load_data(pTAS2559, p_tas2559_startup_data);
1053 tas2559_load_DevB_Runtime(pTAS2559);
1054 dev_dbg(pTAS2559->dev, "TAS2559: unmute TAS2559\n");
1055 tas2559_dev_load_data(pTAS2559, p_tas2559_unmute_data);
1056 pTAS2559->enableIRQ(pTAS2559, 1);
1057 } else {
1058 dev_dbg(pTAS2559->dev,
1059 "TAS2559 is powered up, no change in PLL: load new configuration: %s, coeff block data\n",
1060 pNewConfiguration->mpName);
1061 tas2559_load_data(pTAS2559, &(pNewConfiguration->mData),
1062 TAS2559_BLOCK_CFG_COEFF_DEV_A);
1063 tas2559_load_data(pTAS2559, &(pNewConfiguration->mData),
1064 TAS2559_BLOCK_CFG_COEFF_DEV_B);
1065 }
1066
1067 pTAS2559->mbLoadConfigurationPostPowerUp = false;
1068 } else {
1069 dev_dbg(pTAS2559->dev,
1070 "TAS2559 was powered down\n");
1071 if (pNewConfiguration->mnPLL != pCurrentConfiguration->mnPLL) {
1072 dev_dbg(pTAS2559->dev, "TAS2559: load new PLL: %s, block data\n",
1073 pNewPLL->mpName);
1074 tas2559_load_block(pTAS2559, &(pNewPLL->mBlock));
1075 pTAS2559->mnCurrentSampleRate = pNewConfiguration->mnSamplingRate;
1076 dev_dbg(pTAS2559->dev,
1077 "load new configuration: %s, pre block data\n",
1078 pNewConfiguration->mpName);
1079 tas2559_load_data(pTAS2559, &(pNewConfiguration->mData),
1080 TAS2559_BLOCK_CFG_PRE_DEV_A);
1081 tas2559_load_data(pTAS2559, &(pNewConfiguration->mData),
1082 TAS2559_BLOCK_CFG_PRE_DEV_B);
1083 }
1084
1085 dev_dbg(pTAS2559->dev,
1086 "TAS2559: load new configuration: %s, coeff block data\n",
1087 pNewConfiguration->mpName);
1088 tas2559_load_data(pTAS2559, &(pNewConfiguration->mData),
1089 TAS2559_BLOCK_CFG_COEFF_DEV_A);
1090 tas2559_load_data(pTAS2559, &(pNewConfiguration->mData),
1091 TAS2559_BLOCK_CFG_COEFF_DEV_B);
1092 pTAS2559->mbLoadConfigurationPostPowerUp = true;
1093 }
1094
1095 pTAS2559->mnCurrentConfiguration = nConfiguration;
1096}
1097
1098int tas2559_set_config(struct tas2559_priv *pTAS2559, int config)
1099{
1100 TConfiguration *pConfiguration;
1101 TProgram *pProgram;
1102 unsigned int nProgram = pTAS2559->mnCurrentProgram;
1103 unsigned int nConfiguration = config;
1104
1105 if ((!pTAS2559->mpFirmware->mpPrograms) ||
1106 (!pTAS2559->mpFirmware->mpConfigurations)) {
1107 dev_err(pTAS2559->dev, "Firmware not loaded\n");
1108 return -1;
1109 }
1110
1111 if (nConfiguration >= pTAS2559->mpFirmware->mnConfigurations) {
1112 dev_err(pTAS2559->dev, "Configuration %d doesn't exist\n",
1113 nConfiguration);
1114 return -1;
1115 }
1116
1117 pConfiguration = &(pTAS2559->mpFirmware->mpConfigurations[nConfiguration]);
1118 pProgram = &(pTAS2559->mpFirmware->mpPrograms[nProgram]);
1119
1120 if (nProgram != pConfiguration->mnProgram) {
1121 dev_err(pTAS2559->dev,
1122 "Configuration %d, %s with Program %d isn't compatible with existing Program %d, %s\n",
1123 nConfiguration, pConfiguration->mpName, pConfiguration->mnProgram,
1124 nProgram, pProgram->mpName);
1125 return -1;
1126 }
1127
1128 tas2559_load_configuration(pTAS2559, nConfiguration, false);
1129
1130 return 0;
1131}
1132
1133void tas2559_clear_firmware(TFirmware *pFirmware)
1134{
1135 unsigned int n, nn;
1136 if (!pFirmware) return;
1137 if (pFirmware->mpDescription) kfree(pFirmware->mpDescription);
1138
1139 for (n = 0; n < pFirmware->mnPLLs; n++)
1140 {
1141 kfree(pFirmware->mpPLLs[n].mpDescription);
1142 kfree(pFirmware->mpPLLs[n].mBlock.mpData);
1143 }
1144 kfree(pFirmware->mpPLLs);
1145
1146 for (n = 0; n < pFirmware->mnPrograms; n++)
1147 {
1148 kfree(pFirmware->mpPrograms[n].mpDescription);
1149 kfree(pFirmware->mpPrograms[n].mData.mpDescription);
1150 for (nn = 0; nn < pFirmware->mpPrograms[n].mData.mnBlocks; nn++)
1151 kfree(pFirmware->mpPrograms[n].mData.mpBlocks[nn].mpData);
1152 kfree(pFirmware->mpPrograms[n].mData.mpBlocks);
1153 }
1154 kfree(pFirmware->mpPrograms);
1155
1156 for (n = 0; n < pFirmware->mnConfigurations; n++)
1157 {
1158 kfree(pFirmware->mpConfigurations[n].mpDescription);
1159 kfree(pFirmware->mpConfigurations[n].mData.mpDescription);
1160 for (nn = 0; nn < pFirmware->mpConfigurations[n].mData.mnBlocks; nn++)
1161 kfree(pFirmware->mpConfigurations[n].mData.mpBlocks[nn].mpData);
1162 kfree(pFirmware->mpConfigurations[n].mData.mpBlocks);
1163 }
1164 kfree(pFirmware->mpConfigurations);
1165
1166 for (n = 0; n < pFirmware->mnCalibrations; n++)
1167 {
1168 kfree(pFirmware->mpCalibrations[n].mpDescription);
1169 kfree(pFirmware->mpCalibrations[n].mBlock.mpData);
1170 }
1171 kfree(pFirmware->mpCalibrations);
1172
1173 memset(pFirmware, 0x00, sizeof(TFirmware));
1174}
1175
1176static void tas2559_load_calibration(struct tas2559_priv *pTAS2559, char *pFileName)
1177{
1178 int nResult;
1179 int nFile;
1180 mm_segment_t fs;
1181 unsigned char pBuffer[512];
1182 int nSize = 0;
1183
1184 dev_dbg(pTAS2559->dev, "%s:\n", __func__);
1185
1186 fs = get_fs();
1187 set_fs(KERNEL_DS);
1188 nFile = sys_open(pFileName, O_RDONLY, 0);
1189
1190 dev_info(pTAS2559->dev, "TAS2559 calibration file = %s, handle = %d\n",
1191 pFileName, nFile);
1192
1193 if (nFile >= 0) {
1194 nSize = sys_read(nFile, pBuffer, 512);
1195 sys_close(nFile);
1196 } else {
1197 dev_err(pTAS2559->dev, "TAS2559 cannot open calibration file: %s\n",
1198 pFileName);
1199 }
1200
1201 set_fs(fs);
1202
1203 if (!nSize)
1204 return;
1205
1206 tas2559_clear_firmware(pTAS2559->mpCalFirmware);
1207
1208 dev_info(pTAS2559->dev, "TAS2559 calibration file size = %d\n", nSize);
1209 nResult = fw_parse(pTAS2559, pTAS2559->mpCalFirmware, pBuffer, nSize);
1210
1211 if (nResult) {
1212 dev_err(pTAS2559->dev, "TAS2559 calibration file is corrupt\n");
1213 return;
1214 }
1215
1216 dev_info(pTAS2559->dev, "TAS2559 calibration: %d calibrations\n",
1217 pTAS2559->mpCalFirmware->mnCalibrations);
1218}
1219
1220void tas2559_fw_ready(const struct firmware *pFW, void *pContext)
1221{
1222 struct tas2559_priv *pTAS2559 = (struct tas2559_priv *) pContext;
1223 int nResult;
1224 unsigned int nProgram = 0;
1225 unsigned int nSampleRate = 0;
1226
1227 dev_info(pTAS2559->dev, "%s:\n", __func__);
1228
1229 if (unlikely(!pFW) || unlikely(!pFW->data)) {
1230 dev_err(pTAS2559->dev, "%s firmware is not loaded.\n",
1231 TAS2559_FW_NAME);
1232
1233 return;
1234 }
1235
1236 if (pTAS2559->mpFirmware->mpConfigurations){
1237 nProgram = pTAS2559->mnCurrentProgram;
1238 nSampleRate = pTAS2559->mnCurrentSampleRate;
1239 dev_dbg(pTAS2559->dev, "clear current firmware\n");
1240 tas2559_clear_firmware(pTAS2559->mpFirmware);
1241 }
1242
1243 nResult = fw_parse(pTAS2559, pTAS2559->mpFirmware,
1244 (unsigned char *) (pFW->data), pFW->size);
1245
1246 release_firmware(pFW);
1247
1248 if (nResult) {
1249 dev_err(pTAS2559->dev, "firmware is corrupt\n");
1250 return;
1251 }
1252
1253 if (!pTAS2559->mpFirmware->mnPrograms) {
1254 dev_err(pTAS2559->dev, "firmware contains no programs\n");
1255 return;
1256 }
1257
1258 if (!pTAS2559->mpFirmware->mnConfigurations) {
1259 dev_err(pTAS2559->dev,
1260 "firmware contains no configurations\n");
1261 return;
1262 }
1263
1264 if(nProgram >= pTAS2559->mpFirmware->mnPrograms){
1265 dev_info(pTAS2559->dev,
1266 "no previous program, set to default\n");
1267 nProgram = 0;
1268 }
1269
1270 pTAS2559->mnCurrentSampleRate = nSampleRate;
1271
1272 tas2559_set_program(pTAS2559, nProgram);
1273}
1274
1275int tas2559_set_program(struct tas2559_priv *pTAS2559,
1276 unsigned int nProgram)
1277{
1278 TPLL *pPLL;
1279 TConfiguration *pConfiguration;
1280 unsigned int nConfiguration = 0;
1281 unsigned int Value = 0;
1282 unsigned int nSampleRate = 0;
1283 bool bFound = false;
1284 int nResult = -1;
1285
1286 if ((!pTAS2559->mpFirmware->mpPrograms) ||
1287 (!pTAS2559->mpFirmware->mpConfigurations)) {
1288 dev_err(pTAS2559->dev, "Firmware not loaded\n");
1289 return -1;
1290 }
1291
1292 if (nProgram >= pTAS2559->mpFirmware->mnPrograms) {
1293 dev_err(pTAS2559->dev, "TAS2559: Program %d doesn't exist\n",
1294 nConfiguration);
1295 return -1;
1296 }
1297
1298 nConfiguration = 0;
1299 nSampleRate = pTAS2559->mnCurrentSampleRate;
1300
1301 while (!bFound
1302 && (nConfiguration < pTAS2559->mpFirmware->mnConfigurations)) {
1303 if (pTAS2559->mpFirmware->mpConfigurations[nConfiguration].mnProgram
1304 == nProgram){
1305 if(nSampleRate == 0){
1306 bFound = true;
1307 dev_info(pTAS2559->dev, "find default configuration %d\n", nConfiguration);
1308 }else if(nSampleRate
1309 == pTAS2559->mpFirmware->mpConfigurations[nConfiguration].mnSamplingRate){
1310 bFound = true;
1311 dev_info(pTAS2559->dev, "find matching configuration %d\n", nConfiguration);
1312 }else{
1313 nConfiguration++;
1314 }
1315 }else{
1316 nConfiguration++;
1317 }
1318 }
1319
1320 if (!bFound) {
1321 dev_err(pTAS2559->dev,
1322 "Program %d, no valid configuration found for sample rate %d, ignore\n",
1323 nProgram, nSampleRate);
1324 return -1;
1325 }
1326
1327 pTAS2559->mnCurrentProgram = nProgram;
1328 if(pTAS2559->mbPowerUp){
1329 nResult = tas2559_dev_load_data(pTAS2559, p_tas2559_mute_DSP_down_data);
1330 pTAS2559->enableIRQ(pTAS2559, 0);
1331 }
1332 pTAS2559->write(pTAS2559, DevBoth, TAS2559_SW_RESET_REG, 0x01);
1333 udelay(1000);
1334
1335 nResult = tas2559_load_DevA_default(pTAS2559);
1336 nResult = tas2559_load_DevB_default(pTAS2559);
1337
1338 dev_info(pTAS2559->dev, "load program %d\n", nProgram);
1339 tas2559_load_data(pTAS2559,
1340 &(pTAS2559->mpFirmware->mpPrograms[nProgram].mData),
1341 TAS2559_BLOCK_PGM_DEV_A);
1342 tas2559_load_data(pTAS2559,
1343 &(pTAS2559->mpFirmware->mpPrograms[nProgram].mData),
1344 TAS2559_BLOCK_PGM_DEV_B);
1345
1346 nResult = pTAS2559->read(pTAS2559, DevA, TAS2559_CRC_CHECKSUM_REG, &Value);
1347 dev_info(pTAS2559->dev, "DevA uCDSP Checksum: 0x%02x\n", Value);
1348
1349 pTAS2559->mnCurrentConfiguration = nConfiguration;
1350
1351 pConfiguration =
1352 &(pTAS2559->mpFirmware->mpConfigurations[nConfiguration]);
1353 pPLL = &(pTAS2559->mpFirmware->mpPLLs[pConfiguration->mnPLL]);
1354 dev_dbg(pTAS2559->dev,
1355 "TAS2559 load PLL: %s block for Configuration %s\n",
1356 pPLL->mpName, pConfiguration->mpName);
1357
1358 tas2559_load_block(pTAS2559, &(pPLL->mBlock));
1359 pTAS2559->mnCurrentSampleRate = pConfiguration->mnSamplingRate;
1360 dev_dbg(pTAS2559->dev,
1361 "load configuration %s conefficient pre block\n",
1362 pConfiguration->mpName);
1363 tas2559_load_data(pTAS2559, &(pConfiguration->mData), TAS2559_BLOCK_CFG_PRE_DEV_A);
1364 tas2559_load_data(pTAS2559, &(pConfiguration->mData), TAS2559_BLOCK_CFG_PRE_DEV_B);
1365
1366 tas2559_load_configuration(pTAS2559, nConfiguration, true);
1367 if (pTAS2559->mbPowerUp){
1368 dev_dbg(pTAS2559->dev, "device powered up, load startup\n");
1369 tas2559_dev_load_data(pTAS2559, p_tas2559_startup_data);
1370 tas2559_load_DevB_Runtime(pTAS2559);
1371 dev_dbg(pTAS2559->dev,
1372 "device powered up, load unmute\n");
1373 tas2559_dev_load_data(pTAS2559, p_tas2559_unmute_data);
1374 pTAS2559->enableIRQ(pTAS2559, 1);
1375 }
1376
1377 return 0;
1378}
1379
1380int tas2559_set_calibration(struct tas2559_priv *pTAS2559,
1381 int nCalibration)
1382{
1383 if ((!pTAS2559->mpFirmware->mpPrograms) || (!pTAS2559->mpFirmware->mpConfigurations))
1384 {
1385 dev_err(pTAS2559->dev, "Firmware not loaded\n\r");
1386 return -1;
1387 }
1388
1389 if (nCalibration == 0x00FF)
1390 {
1391 dev_info(pTAS2559->dev, "load new calibration file %s\n", TAS2559_CAL_NAME);
1392 tas2559_load_calibration(pTAS2559, TAS2559_CAL_NAME);
1393 nCalibration = 0;
1394 }
1395
1396 if (nCalibration >= pTAS2559->mpFirmware->mnCalibrations) {
1397 dev_err(pTAS2559->dev,
1398 "Calibration %d doesn't exist\n", nCalibration);
1399 return -1;
1400 }
1401
1402 pTAS2559->mnCurrentCalibration = nCalibration;
1403 if(pTAS2559->mbPowerUp){
1404 tas2559_load_block(pTAS2559,
1405 &(pTAS2559->mpCalFirmware->mpCalibrations[pTAS2559->mnCurrentCalibration].mBlock));
1406 pTAS2559->mbLoadCalibrationPostPowerUp = false;
1407 }else{
1408 pTAS2559->mbLoadCalibrationPostPowerUp = true;
1409 }
1410
1411 return 0;
1412}
1413
1414int tas2559_parse_dt(struct device *dev,
1415 struct tas2559_priv *pTAS2559)
1416{
1417 struct device_node *np = dev->of_node;
1418 int rc= 0, ret = 0;
1419 unsigned int value;
1420
1421 pTAS2559->mnResetGPIO = of_get_named_gpio(np, "ti,cdc-reset-gpio", 0);
1422 if (pTAS2559->mnResetGPIO < 0) {
1423 dev_err(pTAS2559->dev, "Looking up %s property in node %s failed %d\n",
1424 "ti,cdc-reset-gpio", np->full_name,
1425 pTAS2559->mnResetGPIO);
1426 ret = -1;
1427 }else{
1428 dev_dbg(pTAS2559->dev, "ti,cdc-reset-gpio=%d\n", pTAS2559->mnResetGPIO);
1429 }
1430
1431 if(ret >=0){
1432 pTAS2559->mnGpioINT = of_get_named_gpio(np, "ti,irq-gpio", 0);
1433 if (pTAS2559->mnGpioINT < 0) {
1434 dev_err(pTAS2559->dev, "Looking up %s property in node %s failed %d\n",
1435 "ti,irq-gpio", np->full_name,
1436 pTAS2559->mnGpioINT);
1437 ret = -2;
1438 }else{
1439 dev_dbg(pTAS2559->dev, "ti,irq-gpio=%d\n", pTAS2559->mnGpioINT);
1440 }
1441 }
1442
1443 if(ret >=0){
1444 rc = of_property_read_u32(np, "ti,bit-rate", &value);
1445 if (rc) {
1446 dev_err(pTAS2559->dev, "Looking up %s property in node %s failed %d\n",
1447 "ti,dev-a-addr", np->full_name, rc);
1448 ret = -3;
1449 }else{
1450 pTAS2559->mnBitRate = value;
1451 dev_dbg(pTAS2559->dev, "ti,bit-rate=%d\n", pTAS2559->mnBitRate);
1452 }
1453 }
1454
1455 if(ret >=0){
1456 rc = of_property_read_u32(np, "ti,dev-a-addr", &value);
1457 if (rc) {
1458 dev_err(pTAS2559->dev, "Looking up %s property in node %s failed %d\n",
1459 "ti,dev-a-addr", np->full_name, rc);
1460 ret = -3;
1461 }else{
1462 pTAS2559->mnDevAAddr = value;
1463 dev_dbg(pTAS2559->dev, "ti,dev-a-addr=0x%x\n", pTAS2559->mnDevAAddr);
1464 }
1465 }
1466
1467 if(ret >=0){
1468 rc = of_property_read_u32(np, "ti,dev-a-channel", &value);
1469 if (rc) {
1470 dev_err(pTAS2559->dev, "Looking up %s property in node %s failed %d\n",
1471 "ti,dev-a-channel", np->full_name, rc);
1472 ret = -4;
1473 }else{
1474 pTAS2559->mnDevAChl = value;
1475 dev_dbg(pTAS2559->dev, "ti,dev-a-channel=0x%x\n", pTAS2559->mnDevAChl);
1476 }
1477 }
1478
1479 if(ret >=0){
1480 rc = of_property_read_u32(np, "ti,dev-a-load", &value);
1481 if (rc) {
1482 dev_err(pTAS2559->dev, "Looking up %s property in node %s failed %d\n",
1483 "ti,dev-a-load", np->full_name, rc);
1484 ret = -5;
1485 }else{
1486 pTAS2559->mnDevALoad = value;
1487 dev_dbg(pTAS2559->dev, "ti,dev-a-load=%d", pTAS2559->mnDevALoad);
1488 }
1489 }
1490
1491 if(ret >=0){
1492 rc = of_property_read_u32(np, "ti,dev-b-addr", &value);
1493 if (rc) {
1494 dev_err(pTAS2559->dev, "Looking up %s property in node %s failed %d\n",
1495 "ti,dev-b-addr", np->full_name, rc);
1496 ret = -6;
1497 }else{
1498 pTAS2559->mnDevAAddr = value;
1499 dev_dbg(pTAS2559->dev, "ti,dev-b-addr=0x%x\n", pTAS2559->mnDevBAddr);
1500 }
1501 }
1502
1503 if(ret >=0){
1504 rc = of_property_read_u32(np, "ti,dev-b-channel", &value);
1505 if (rc) {
1506 dev_err(pTAS2559->dev, "Looking up %s property in node %s failed %d\n",
1507 "ti,dev-b-channel", np->full_name, rc);
1508 ret = -7;
1509 }else{
1510 pTAS2559->mnDevAChl = value;
1511 dev_dbg(pTAS2559->dev, "ti,dev-b-channel=0x%x\n", pTAS2559->mnDevBChl);
1512 }
1513 }
1514
1515 if(ret >=0){
1516 rc = of_property_read_u32(np, "ti,dev-b-load", &value);
1517 if (rc) {
1518 dev_err(pTAS2559->dev, "Looking up %s property in node %s failed %d\n",
1519 "ti,dev-b-load", np->full_name, rc);
1520 ret = -8;
1521 }else{
1522 pTAS2559->mnDevBLoad = value;
1523 dev_dbg(pTAS2559->dev, "ti,dev-b-load=%d", pTAS2559->mnDevBLoad);
1524 }
1525 }
1526
1527 return ret;
1528}
1529
1530MODULE_AUTHOR("Texas Instruments Inc.");
1531MODULE_DESCRIPTION("TAS2559 common functions for Android Linux");
1532MODULE_LICENSE("GPLv2"); \ No newline at end of file
diff --git a/tas2559-core.h b/tas2559-core.h
new file mode 100755
index 0000000..93d3d22
--- /dev/null
+++ b/tas2559-core.h
@@ -0,0 +1,54 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tas2559-core.h
19**
20** Description:
21** header file for tas2559-core.c
22**
23** =============================================================================
24*/
25
26#ifndef _TAS2559_CORE_H
27#define _TAS2559_CORE_H
28
29#include "tas2559.h"
30
31void tas2559_enable(struct tas2559_priv *pTAS2559, bool bEnable);
32int tas2559_set_sampling_rate(struct tas2559_priv *pTAS2559,
33 unsigned int nSamplingRate);
34int tas2559_set_bit_rate(struct tas2559_priv *pTAS2559,
35 enum channel chn, unsigned int nBitRate);
36int tas2559_get_bit_rate(struct tas2559_priv *pTAS2559,
37 enum channel chn, unsigned char *pBitRate);
38int tas2559_set_config(struct tas2559_priv *pTAS2559, int config);
39void tas2559_fw_ready(const struct firmware *pFW, void *pContext);
40int tas2559_set_program(struct tas2559_priv *pTAS2559,
41 unsigned int nProgram);
42int tas2559_set_calibration(struct tas2559_priv *pTAS2559,
43 int nCalibration);
44int tas2559_load_default(struct tas2559_priv *pTAS2559);
45int tas2559_parse_dt(struct device *dev, struct tas2559_priv *pTAS2559);
46int tas2559_get_DAC_gain(struct tas2559_priv *pTAS2559,
47 enum channel chl, unsigned char *pnGain);
48int tas2559_set_DAC_gain(struct tas2559_priv *pTAS2559,
49 enum channel chl, unsigned int nGain);
50void tas2559_configIRQ(struct tas2559_priv *pTAS2559);
51int tas2559_dev_load_blk_data(struct tas2559_priv *pTAS2559,
52 enum channel chl, unsigned int *pData);
53
54#endif /* _TAS2559_CORE_H */
diff --git a/tas2559-misc.c b/tas2559-misc.c
new file mode 100755
index 0000000..53bd21e
--- /dev/null
+++ b/tas2559-misc.c
@@ -0,0 +1,608 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tas2559-misc.c
19**
20** Description:
21** misc driver for Texas Instruments TAS2559 High Performance 4W Smart Amplifier
22**
23** =============================================================================
24*/
25
26#ifdef CONFIG_TAS2559_MISC
27
28#define DEBUG
29#include <linux/module.h>
30#include <linux/moduleparam.h>
31#include <linux/init.h>
32#include <linux/delay.h>
33#include <linux/pm.h>
34#include <linux/i2c.h>
35#include <linux/gpio.h>
36#include <linux/regulator/consumer.h>
37#include <linux/firmware.h>
38#include <linux/regmap.h>
39#include <linux/of.h>
40#include <linux/of_gpio.h>
41#include <linux/slab.h>
42#include <linux/syscalls.h>
43#include <linux/fcntl.h>
44#include <linux/miscdevice.h>
45#include <asm/uaccess.h>
46//#include <dt-bindings/sound/tas2559.h>
47
48#include "tas2559.h"
49#include "tas2559-core.h"
50#include "tas2559-misc.h"
51#include <linux/dma-mapping.h>
52
53static int g_logEnable = 1;
54static struct tas2559_priv *g_tas2559 = NULL;
55
56static int tas2559_file_open(struct inode *inode, struct file *file)
57{
58 struct tas2559_priv *pTAS2559 = g_tas2559;
59
60 if (!try_module_get(THIS_MODULE)) return -ENODEV;
61
62 file->private_data = (void*)pTAS2559;
63
64 if(g_logEnable) dev_info(pTAS2559->dev,
65 "%s\n", __FUNCTION__);
66 return 0;
67}
68
69static int tas2559_file_release(struct inode *inode, struct file *file)
70{
71 struct tas2559_priv *pTAS2559 = (struct tas2559_priv *)file->private_data;
72
73 if(g_logEnable) dev_info(pTAS2559->dev,
74 "%s\n", __FUNCTION__);
75
76 file->private_data = (void*)NULL;
77 module_put(THIS_MODULE);
78
79 return 0;
80}
81
82static ssize_t tas2559_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
83{
84 struct tas2559_priv *pTAS2559 = (struct tas2559_priv *)file->private_data;
85 int ret = 0;
86 unsigned int nValue = 0;
87 unsigned char value = 0;
88 unsigned char *p_kBuf = NULL;
89
90 mutex_lock(&pTAS2559->file_lock);
91
92 switch(pTAS2559->mnDBGCmd)
93 {
94 case TIAUDIO_CMD_REG_READ:
95 {
96 if(g_logEnable) dev_info(pTAS2559->dev,
97 "TIAUDIO_CMD_REG_READ: chn[%d], current_reg = 0x%x, count=%d\n",
98 pTAS2559->mnCurrentChannel,
99 pTAS2559->mnCurrentReg, (int)count);
100 if(count == 1){
101 ret = pTAS2559->read(pTAS2559,
102 pTAS2559->mnCurrentChannel,
103 pTAS2559->mnCurrentReg, &nValue);
104 if( 0 > ret) {
105 dev_err(pTAS2559->dev, "dev read fail %d\n", ret);
106 break;
107 }
108
109 value = (u8)nValue;
110 if(g_logEnable) dev_info(pTAS2559->dev,
111 "TIAUDIO_CMD_REG_READ: nValue=0x%x, value=0x%x\n",
112 nValue, value);
113 ret = copy_to_user(buf, &value, 1);
114 if (0 != ret) {
115 /* Failed to copy all the data, exit */
116 dev_err(pTAS2559->dev, "copy to user fail %d\n", ret);
117 }
118 }else if(count > 1){
119 p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
120 if(p_kBuf != NULL){
121 ret = pTAS2559->bulk_read(pTAS2559,
122 pTAS2559->mnCurrentChannel,
123 pTAS2559->mnCurrentReg, p_kBuf, count);
124 if( 0 > ret) {
125 dev_err(pTAS2559->dev, "dev bulk read fail %d\n", ret);
126 }else{
127 ret = copy_to_user(buf, p_kBuf, count);
128 if (0 != ret) {
129 /* Failed to copy all the data, exit */
130 dev_err(pTAS2559->dev, "copy to user fail %d\n", ret);
131 }
132 }
133
134 kfree(p_kBuf);
135 }else{
136 dev_err(pTAS2559->dev, "read no mem\n");
137 }
138 }
139 }
140 break;
141
142 case TIAUDIO_CMD_PROGRAM:
143 {
144 if(g_logEnable) dev_info(pTAS2559->dev,
145 "TIAUDIO_CMD_PROGRAM: count = %d\n",
146 (int)count);
147
148 if(count == PROGRAM_BUF_SIZE){
149 p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
150 if(p_kBuf != NULL){
151 TProgram * pProgram =
152 &(pTAS2559->mpFirmware->mpPrograms[pTAS2559->mnCurrentProgram]);
153
154 p_kBuf[0] = pTAS2559->mpFirmware->mnPrograms;
155 p_kBuf[1] = pTAS2559->mnCurrentProgram;
156 p_kBuf[2] = pProgram->mnAppMode;
157 p_kBuf[3] = (pProgram->mnBoost&0xff00)>>8;
158 p_kBuf[4] = (pProgram->mnBoost&0x00ff);
159 memcpy(&p_kBuf[5], pProgram->mpName, FW_NAME_SIZE);
160 strcpy(&p_kBuf[5+FW_NAME_SIZE], pProgram->mpDescription);
161
162 ret = copy_to_user(buf, p_kBuf, count);
163 if (0 != ret) {
164 /* Failed to copy all the data, exit */
165 dev_err(pTAS2559->dev, "copy to user fail %d\n", ret);
166 }
167
168 kfree(p_kBuf);
169 }else{
170 dev_err(pTAS2559->dev, "read no mem\n");
171 }
172 }else{
173 dev_err(pTAS2559->dev, "read buffer not sufficient\n");
174 }
175 }
176 break;
177
178 case TIAUDIO_CMD_CONFIGURATION:
179 {
180 if(g_logEnable) dev_info(pTAS2559->dev,
181 "TIAUDIO_CMD_CONFIGURATION: count = %d\n",
182 (int)count);
183
184 if(count == CONFIGURATION_BUF_SIZE){
185 p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
186 if(p_kBuf != NULL){
187 TConfiguration * pConfiguration =
188 &(pTAS2559->mpFirmware->mpConfigurations[pTAS2559->mnCurrentConfiguration]);
189
190 p_kBuf[0] = pTAS2559->mpFirmware->mnConfigurations;
191 p_kBuf[1] = pTAS2559->mnCurrentConfiguration;
192 memcpy(&p_kBuf[2], pConfiguration->mpName, FW_NAME_SIZE);
193 p_kBuf[2+FW_NAME_SIZE] = pConfiguration->mnProgram;
194 p_kBuf[3+FW_NAME_SIZE] = pConfiguration->mnPLL;
195 p_kBuf[4+FW_NAME_SIZE] = (pConfiguration->mnSamplingRate&0x000000ff);
196 p_kBuf[5+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0x0000ff00)>>8);
197 p_kBuf[6+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0x00ff0000)>>16);
198 p_kBuf[7+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0xff000000)>>24);
199 strcpy(&p_kBuf[8+FW_NAME_SIZE], pConfiguration->mpDescription);
200
201 ret = copy_to_user(buf, p_kBuf, count);
202 if (0 != ret) {
203 /* Failed to copy all the data, exit */
204 dev_err(pTAS2559->dev, "copy to user fail %d\n", ret);
205 }
206
207 kfree(p_kBuf);
208 }else{
209 dev_err(pTAS2559->dev, "read no mem\n");
210 }
211 }else{
212 dev_err(pTAS2559->dev, "read buffer not sufficient\n");
213 }
214 }
215 break;
216
217 case TIAUDIO_CMD_FW_TIMESTAMP:
218 {
219 if(g_logEnable) dev_info(pTAS2559->dev,
220 "TIAUDIO_CMD_FW_TIMESTAMP: count = %d\n",
221 (int)count);
222
223 if(count == 4){
224 p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
225 if(p_kBuf != NULL){
226 p_kBuf[0] = (pTAS2559->mpFirmware->mnTimeStamp&0x000000ff);
227 p_kBuf[1] = ((pTAS2559->mpFirmware->mnTimeStamp&0x0000ff00)>>8);
228 p_kBuf[2] = ((pTAS2559->mpFirmware->mnTimeStamp&0x00ff0000)>>16);
229 p_kBuf[3] = ((pTAS2559->mpFirmware->mnTimeStamp&0xff000000)>>24);
230
231 ret = copy_to_user(buf, p_kBuf, count);
232 if (0 != ret) {
233 /* Failed to copy all the data, exit */
234 dev_err(pTAS2559->dev, "copy to user fail %d\n", ret);
235 }
236
237 kfree(p_kBuf);
238 }else{
239 dev_err(pTAS2559->dev, "read no mem\n");
240 }
241 }
242 }
243 break;
244
245 case TIAUDIO_CMD_CALIBRATION:
246 {
247 if(g_logEnable) dev_info(pTAS2559->dev,
248 "TIAUDIO_CMD_CALIBRATION: count = %d\n",
249 (int)count);
250
251 if(count == 1){
252 unsigned char curCal = pTAS2559->mnCurrentCalibration;
253 ret = copy_to_user(buf, &curCal, 1);
254 if (0 != ret) {
255 /* Failed to copy all the data, exit */
256 dev_err(pTAS2559->dev, "copy to user fail %d\n", ret);
257 }
258 }
259 }
260 break;
261
262 case TIAUDIO_CMD_SAMPLERATE:
263 {
264 if(g_logEnable) dev_info(pTAS2559->dev,
265 "TIAUDIO_CMD_SAMPLERATE: count = %d\n",
266 (int)count);
267 if(count == 4){
268 p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
269 if(p_kBuf != NULL){
270 TConfiguration *pConfiguration =
271 &(pTAS2559->mpFirmware->mpConfigurations[pTAS2559->mnCurrentConfiguration]);
272
273 p_kBuf[0] = (pConfiguration->mnSamplingRate&0x000000ff);
274 p_kBuf[1] = ((pConfiguration->mnSamplingRate&0x0000ff00)>>8);
275 p_kBuf[2] = ((pConfiguration->mnSamplingRate&0x00ff0000)>>16);
276 p_kBuf[3] = ((pConfiguration->mnSamplingRate&0xff000000)>>24);
277
278 ret = copy_to_user(buf, p_kBuf, count);
279 if (0 != ret) {
280 /* Failed to copy all the data, exit */
281 dev_err(pTAS2559->dev, "copy to user fail %d\n", ret);
282 }
283
284 kfree(p_kBuf);
285 }else{
286 dev_err(pTAS2559->dev, "read no mem\n");
287 }
288 }
289 }
290 break;
291
292 case TIAUDIO_CMD_BITRATE:
293 {
294 if(g_logEnable) dev_info(pTAS2559->dev,
295 "TIAUDIO_CMD_BITRATE: count = %d\n",
296 (int)count);
297
298 if(count == 1){
299 unsigned char bitRate = 0;
300 tas2559_get_bit_rate(pTAS2559,
301 pTAS2559->mnCurrentChannel, &bitRate);
302 ret = copy_to_user(buf, &bitRate, 1);
303 if (0 != ret) {
304 /* Failed to copy all the data, exit */
305 dev_err(pTAS2559->dev, "copy to user fail %d\n", ret);
306 }
307 }
308 }
309 break;
310
311 case TIAUDIO_CMD_DACVOLUME:
312 {
313 if(g_logEnable) dev_info(pTAS2559->dev,
314 "TIAUDIO_CMD_DACVOLUME: count = %d\n",
315 (int)count);
316
317 if(count == 1){
318 unsigned char volume = 0;
319 ret = tas2559_get_DAC_gain(pTAS2559,
320 pTAS2559->mnCurrentChannel, &volume);
321 if(ret >=0){
322 ret = copy_to_user(buf, &volume, 1);
323 if (0 != ret) {
324 /* Failed to copy all the data, exit */
325 dev_err(pTAS2559->dev, "copy to user fail %d\n", ret);
326 }
327 }
328 }
329 }
330 break;
331 }
332 pTAS2559->mnDBGCmd = 0;
333
334 mutex_unlock(&pTAS2559->file_lock);
335 return count;
336}
337
338static ssize_t tas2559_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
339{
340 struct tas2559_priv *pTAS2559 = (struct tas2559_priv *)file->private_data;
341 int ret = 0;
342// unsigned int value = 0;
343 unsigned char *p_kBuf = NULL;
344 unsigned int reg = 0;
345 enum channel chl;
346 unsigned int len = 0;
347
348 mutex_lock(&pTAS2559->file_lock);
349
350 p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
351 if(p_kBuf == NULL) {
352 dev_err(pTAS2559->dev, "write no mem\n");
353 goto err;
354 }
355
356 ret = copy_from_user(p_kBuf, buf, count);
357 if (0 != ret) {
358 dev_err(pTAS2559->dev,"copy_from_user failed.\n");
359 goto err;
360 }
361
362 pTAS2559->mnDBGCmd = p_kBuf[0];
363 switch(pTAS2559->mnDBGCmd)
364 {
365 case TIAUDIO_CMD_REG_WITE:
366 if(count > 6){
367 chl = p_kBuf[1];
368 reg = ((unsigned int)p_kBuf[2] << 24) +
369 ((unsigned int)p_kBuf[3] << 16) +
370 ((unsigned int)p_kBuf[4] << 8) +
371 (unsigned int)p_kBuf[5];
372 len = count - 6;
373 if(len == 1){
374 ret = pTAS2559->write(pTAS2559,
375 chl, reg, p_kBuf[6]);
376 if(g_logEnable)
377 dev_info(pTAS2559->dev,
378 "TIAUDIO_CMD_REG_WITE,chn[%d], Reg=0x%x, Val=0x%x\n",
379 chl, reg, p_kBuf[6]);
380 }else{
381 ret = pTAS2559->bulk_write(pTAS2559,
382 chl, reg, &p_kBuf[6], len);
383 }
384 }else{
385 dev_err(pTAS2559->dev,"%s, write len fail, count=%d.\n",
386 __FUNCTION__, (int)count);
387 }
388 pTAS2559->mnDBGCmd = 0;
389 break;
390
391 case TIAUDIO_CMD_REG_READ:
392 if(count == 6){
393 pTAS2559->mnCurrentChannel = p_kBuf[1];
394 pTAS2559->mnCurrentReg = ((unsigned int)p_kBuf[2] << 24) +
395 ((unsigned int)p_kBuf[3] << 16) +
396 ((unsigned int)p_kBuf[4] << 8) +
397 (unsigned int)p_kBuf[5];
398 if(g_logEnable){
399 dev_info(pTAS2559->dev,
400 "TIAUDIO_CMD_REG_READ chl[%d], whole=0x%x\n",
401 pTAS2559->mnCurrentChannel,
402 pTAS2559->mnCurrentReg);
403 }
404 }else{
405 dev_err(pTAS2559->dev,"read len fail.\n");
406 }
407 break;
408
409 case TIAUDIO_CMD_DEBUG_ON:
410 {
411 if(count == 2){
412 g_logEnable = p_kBuf[1];
413 }
414 pTAS2559->mnDBGCmd = 0;
415 }
416 break;
417
418 case TIAUDIO_CMD_PROGRAM:
419 {
420 if(count == 2){
421 if(g_logEnable)
422 dev_info(pTAS2559->dev,
423 "TIAUDIO_CMD_PROGRAM, set to %d\n",
424 p_kBuf[1]);
425 tas2559_set_program(pTAS2559, p_kBuf[1]);
426 pTAS2559->mnDBGCmd = 0;
427 }
428 }
429 break;
430
431 case TIAUDIO_CMD_CONFIGURATION:
432 {
433 if(count == 2){
434 if(g_logEnable)
435 dev_info(pTAS2559->dev,
436 "TIAUDIO_CMD_CONFIGURATION, set to %d\n",
437 p_kBuf[1]);
438 tas2559_set_config(pTAS2559, p_kBuf[1]);
439 pTAS2559->mnDBGCmd = 0;
440 }
441 }
442 break;
443
444 case TIAUDIO_CMD_FW_TIMESTAMP:
445 /*let go*/
446 break;
447
448 case TIAUDIO_CMD_CALIBRATION:
449 {
450 if(count == 2){
451 if(g_logEnable)
452 dev_info(pTAS2559->dev,
453 "TIAUDIO_CMD_CALIBRATION, set to %d\n",
454 p_kBuf[1]);
455 tas2559_set_calibration(pTAS2559, p_kBuf[1]);
456 pTAS2559->mnDBGCmd = 0;
457 }
458 }
459 break;
460
461 case TIAUDIO_CMD_SAMPLERATE:
462 {
463 if(count == 5){
464 unsigned int nSampleRate = ((unsigned int)p_kBuf[1] << 24) +
465 ((unsigned int)p_kBuf[2] << 16) +
466 ((unsigned int)p_kBuf[3] << 8) +
467 (unsigned int)p_kBuf[4];
468 if(g_logEnable)
469 dev_info(pTAS2559->dev,
470 "TIAUDIO_CMD_SAMPLERATE, set to %d\n",
471 nSampleRate);
472
473 tas2559_set_sampling_rate(pTAS2559, nSampleRate);
474 }
475 }
476 break;
477
478 case TIAUDIO_CMD_BITRATE:
479 {
480 pTAS2559->mnCurrentChannel = p_kBuf[1];
481 if(count == 3){
482 if(g_logEnable)
483 dev_info(pTAS2559->dev,
484 "TIAUDIO_CMD_BITRATE, set to %d\n",
485 p_kBuf[1]);
486
487 tas2559_set_bit_rate(pTAS2559,
488 pTAS2559->mnCurrentChannel, p_kBuf[2]);
489 }
490 }
491 break;
492
493 case TIAUDIO_CMD_DACVOLUME:
494 {
495 pTAS2559->mnCurrentChannel = p_kBuf[1];
496 if(count == 3){
497 unsigned char volume;
498 volume = (p_kBuf[2] & 0x0f);
499 if(g_logEnable)
500 dev_info(pTAS2559->dev,
501 "TIAUDIO_CMD_DACVOLUME, set to %d\n",
502 volume);
503
504 tas2559_set_DAC_gain(pTAS2559,
505 pTAS2559->mnCurrentChannel, volume);
506 }
507 }
508 break;
509
510 case TIAUDIO_CMD_SPEAKER:
511 {
512 if(count == 2){
513 if(g_logEnable)
514 dev_info(pTAS2559->dev,
515 "TIAUDIO_CMD_SPEAKER, set to %d\n",
516 p_kBuf[1]);
517 tas2559_enable(pTAS2559, (p_kBuf[1]>0));
518 }
519 }
520 break;
521
522 case TIAUDIO_CMD_FW_RELOAD:
523 {
524 if(count == 1){
525 ret = request_firmware_nowait(THIS_MODULE, 1, TAS2559_FW_NAME,
526 pTAS2559->dev, GFP_KERNEL, pTAS2559, tas2559_fw_ready);
527
528 if(g_logEnable)
529 dev_info(pTAS2559->dev,
530 "TIAUDIO_CMD_FW_RELOAD: ret = %d\n",
531 ret);
532 }
533
534 }
535 break;
536
537 default:
538 pTAS2559->mnDBGCmd = 0;
539 break;
540 }
541
542err:
543 if(p_kBuf != NULL)
544 kfree(p_kBuf);
545
546 mutex_unlock(&pTAS2559->file_lock);
547
548 return count;
549}
550
551static long tas2559_file_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
552{
553 struct tas2559_priv *pTAS2559 = file->private_data;
554 int ret = 0;
555
556 dev_info(pTAS2559->dev, "%s, cmd=0x%x\n", __FUNCTION__, cmd);
557
558 mutex_lock(&pTAS2559->file_lock);
559
560
561 mutex_unlock(&pTAS2559->file_lock);
562 return ret;
563}
564
565static struct file_operations fops =
566{
567 .owner = THIS_MODULE,
568 .read = tas2559_file_read,
569 .write = tas2559_file_write,
570 .unlocked_ioctl = tas2559_file_unlocked_ioctl,
571 .open = tas2559_file_open,
572 .release = tas2559_file_release,
573};
574
575#define MODULE_NAME "tas2559s"
576static struct miscdevice tas2559_misc =
577{
578 .minor = MISC_DYNAMIC_MINOR,
579 .name = MODULE_NAME,
580 .fops = &fops,
581};
582
583int tas2559_register_misc(struct tas2559_priv * pTAS2559)
584{
585 int ret = 0;
586
587 g_tas2559 = pTAS2559;
588
589 ret = misc_register(&tas2559_misc);
590 if (ret) {
591 dev_err(pTAS2559->dev, "TAS2559 misc fail: %d\n", ret);
592 }
593
594 dev_info(pTAS2559->dev, "%s, leave\n", __FUNCTION__);
595
596 return ret;
597}
598
599int tas2559_deregister_misc(struct tas2559_priv * pTAS2559)
600{
601 misc_deregister(&tas2559_misc);
602 return 0;
603}
604
605MODULE_AUTHOR("Texas Instruments Inc.");
606MODULE_DESCRIPTION("TAS2559 Misc Smart Amplifier driver");
607MODULE_LICENSE("GPLv2");
608#endif
diff --git a/tas2559-misc.h b/tas2559-misc.h
new file mode 100755
index 0000000..f24c917
--- /dev/null
+++ b/tas2559-misc.h
@@ -0,0 +1,63 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tas2559-misc.h
19**
20** Description:
21** header file for tas2559-misc.c
22**
23** =============================================================================
24*/
25
26#ifndef _TAS2559_MISC_H
27#define _TAS2559_MISC_H
28
29#include "tas2559.h"
30
31#define FW_NAME_SIZE 64
32#define FW_DESCRIPTION_SIZE 256
33#define PROGRAM_BUF_SIZE (5 + FW_NAME_SIZE + FW_DESCRIPTION_SIZE)
34#define CONFIGURATION_BUF_SIZE (8 + FW_NAME_SIZE + FW_DESCRIPTION_SIZE)
35
36#define TIAUDIO_CMD_REG_WITE 1
37#define TIAUDIO_CMD_REG_READ 2
38#define TIAUDIO_CMD_DEBUG_ON 3
39#define TIAUDIO_CMD_PROGRAM 4
40#define TIAUDIO_CMD_CONFIGURATION 5
41#define TIAUDIO_CMD_FW_TIMESTAMP 6
42#define TIAUDIO_CMD_CALIBRATION 7
43#define TIAUDIO_CMD_SAMPLERATE 8
44#define TIAUDIO_CMD_BITRATE 9
45#define TIAUDIO_CMD_DACVOLUME 10
46#define TIAUDIO_CMD_SPEAKER 11
47#define TIAUDIO_CMD_FW_RELOAD 12
48
49#define TAS2559_MAGIC_NUMBER 0x32353537 /* '2559' */
50
51#define SMARTPA_SPK_DAC_VOLUME _IOWR(TAS2559_MAGIC_NUMBER, 1, unsigned long)
52#define SMARTPA_SPK_POWER_ON _IOWR(TAS2559_MAGIC_NUMBER, 2, unsigned long)
53#define SMARTPA_SPK_POWER_OFF _IOWR(TAS2559_MAGIC_NUMBER, 3, unsigned long)
54#define SMARTPA_SPK_SWITCH_PROGRAM _IOWR(TAS2559_MAGIC_NUMBER, 4, unsigned long)
55#define SMARTPA_SPK_SWITCH_CONFIGURATION _IOWR(TAS2559_MAGIC_NUMBER, 5, unsigned long)
56#define SMARTPA_SPK_SWITCH_CALIBRATION _IOWR(TAS2559_MAGIC_NUMBER, 6, unsigned long)
57#define SMARTPA_SPK_SET_SAMPLERATE _IOWR(TAS2559_MAGIC_NUMBER, 7, unsigned long)
58#define SMARTPA_SPK_SET_BITRATE _IOWR(TAS2559_MAGIC_NUMBER, 8, unsigned long)
59
60int tas2559_register_misc(struct tas2559_priv *pTAS2559);
61int tas2559_deregister_misc(struct tas2559_priv *pTAS2559);
62
63#endif /* _TAS2559_MISC_H */
diff --git a/tas2559-regmap.c b/tas2559-regmap.c
new file mode 100755
index 0000000..cd5e3c9
--- /dev/null
+++ b/tas2559-regmap.c
@@ -0,0 +1,766 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tas2559-regmap.c
19**
20** Description:
21** I2C driver with regmap for Texas Instruments TAS2559 High Performance 4W Smart Amplifier
22**
23** =============================================================================
24*/
25
26#define DEBUG
27#include <linux/module.h>
28#include <linux/moduleparam.h>
29#include <linux/init.h>
30#include <linux/delay.h>
31#include <linux/pm.h>
32#include <linux/i2c.h>
33#include <linux/gpio.h>
34#include <linux/regulator/consumer.h>
35#include <linux/firmware.h>
36#include <linux/regmap.h>
37#include <linux/of.h>
38#include <linux/of_gpio.h>
39#include <linux/slab.h>
40#include <linux/syscalls.h>
41#include <linux/fcntl.h>
42#include <asm/uaccess.h>
43#include "tas2559.h"
44#include "tas2559-core.h"
45#include "tas2560.h"
46
47#ifdef CONFIG_TAS2559_CODEC
48#include "tas2559-codec.h"
49#endif
50
51#ifdef CONFIG_TAS2559_MISC
52#include "tas2559-misc.h"
53#endif
54
55#define ENABLE_TILOAD //only enable this for in-system tuning or debug, not for production systems
56#ifdef ENABLE_TILOAD
57#include "tiload.h"
58#endif
59
60/*
61* tas2559_i2c_write_device : write single byte to device
62* platform dependent, need platform specific support
63*/
64static int tas2559_i2c_write_device(
65 struct tas2559_priv *pTAS2559,
66 unsigned char addr,
67 unsigned char reg,
68 unsigned char value)
69{
70 int ret = 0;
71
72 pTAS2559->client->addr = addr;
73 ret = regmap_write(pTAS2559->mpRegmap, reg, value);
74 if(ret < 0){
75 dev_err(pTAS2559->dev, "%s[0x%x] Error %d\n",
76 __FUNCTION__, addr, ret);
77 }else{
78 ret = 1;
79 }
80
81 return ret;
82}
83
84/*
85* tas2559_i2c_bulkwrite_device : write multiple bytes to device
86* platform dependent, need platform specific support
87*/
88static int tas2559_i2c_bulkwrite_device(
89 struct tas2559_priv *pTAS2559,
90 unsigned char addr,
91 unsigned char reg,
92 unsigned char *pBuf,
93 unsigned int len)
94{
95 int ret = 0;
96
97 pTAS2559->client->addr = addr;
98 ret = regmap_bulk_write(pTAS2559->mpRegmap, reg, pBuf, len);
99 if(ret < 0){
100 dev_err(pTAS2559->dev, "%s[0x%x] Error %d\n",
101 __FUNCTION__, addr, ret);
102 }else{
103 ret = len;
104 }
105 return ret;
106}
107
108/*
109* tas2559_i2c_read_device : read single byte from device
110* platform dependent, need platform specific support
111*/
112static int tas2559_i2c_read_device(
113 struct tas2559_priv *pTAS2559,
114 unsigned char addr,
115 unsigned char reg,
116 unsigned char *p_value)
117{
118 int ret = 0;
119 unsigned int val = 0;
120
121 pTAS2559->client->addr = addr;
122 ret = regmap_read(pTAS2559->mpRegmap, reg, &val);
123 if(ret < 0){
124 dev_err(pTAS2559->dev, "%s[0x%x] Error %d\n",
125 __FUNCTION__, addr, ret);
126 }else{
127 *p_value = (unsigned char)val;
128 ret = 1;
129 }
130
131 return ret;
132}
133
134/*
135* tas2559_i2c_bulkread_device : read multiple bytes from device
136* platform dependent, need platform specific support
137*/
138static int tas2559_i2c_bulkread_device(
139 struct tas2559_priv *pTAS2559,
140 unsigned char addr,
141 unsigned char reg,
142 unsigned char *p_value,
143 unsigned int len)
144{
145 int ret = 0;
146 pTAS2559->client->addr = addr;
147 ret = regmap_bulk_read(pTAS2559->mpRegmap, reg, p_value, len);
148
149 if(ret < 0){
150 dev_err(pTAS2559->dev, "%s[0x%x] Error %d\n",
151 __FUNCTION__, addr, ret);
152 }else{
153 ret = len;
154 }
155
156 return ret;
157}
158
159static int tas2559_i2c_update_bits(
160 struct tas2559_priv *pTAS2559,
161 unsigned char addr,
162 unsigned char reg,
163 unsigned char mask,
164 unsigned char value)
165{
166 int ret = 0;
167
168 pTAS2559->client->addr = addr;
169 ret = regmap_update_bits(pTAS2559->mpRegmap, reg, mask, value);
170
171 if(ret < 0){
172 dev_err(pTAS2559->dev, "%s[0x%x] Error %d\n",
173 __FUNCTION__, addr, ret);
174 }else{
175 ret = 1;
176 }
177
178 return ret;
179}
180
181/*
182* tas2559_change_book_page : switch to certain book and page
183* platform independent, don't change unless necessary
184*/
185static int tas2559_change_book_page(
186 struct tas2559_priv *pTAS2559,
187 enum channel chn,
188 int nBook,
189 int nPage)
190{
191 int nResult = 0;
192
193 if(chn&DevA){
194 if(pTAS2559->mnDevACurrentBook == nBook){
195 if(pTAS2559->mnDevACurrentPage != nPage){
196 nResult = tas2559_i2c_write_device(pTAS2559, pTAS2559->mnDevAAddr, TAS2559_BOOKCTL_PAGE, nPage);
197 if(nResult >=0 )
198 pTAS2559->mnDevACurrentPage = nPage;
199 }
200 }else{
201 nResult = tas2559_i2c_write_device(pTAS2559, pTAS2559->mnDevAAddr, TAS2559_BOOKCTL_PAGE, 0);
202 if(nResult >=0){
203 pTAS2559->mnDevACurrentPage = 0;
204 nResult = tas2559_i2c_write_device(pTAS2559, pTAS2559->mnDevAAddr, TAS2559_BOOKCTL_REG, nBook);
205 pTAS2559->mnDevACurrentBook = nBook;
206 if(nPage != 0){
207 tas2559_i2c_write_device(pTAS2559, pTAS2559->mnDevAAddr, TAS2559_BOOKCTL_PAGE, nPage);
208 pTAS2559->mnDevACurrentPage = nPage;
209 }
210 }
211 }
212 }
213
214 if(chn&DevB){
215 if(pTAS2559->mnDevBCurrentBook == nBook){
216 if(pTAS2559->mnDevBCurrentPage != nPage){
217 nResult = tas2559_i2c_write_device(pTAS2559, pTAS2559->mnDevBAddr, TAS2559_BOOKCTL_PAGE, nPage);
218 if(nResult >=0 )
219 pTAS2559->mnDevBCurrentPage = nPage;
220 }
221 }else{
222 nResult = tas2559_i2c_write_device(pTAS2559, pTAS2559->mnDevBAddr, TAS2559_BOOKCTL_PAGE, 0);
223 if(nResult >=0){
224 pTAS2559->mnDevBCurrentPage = 0;
225 nResult = tas2559_i2c_write_device(pTAS2559, pTAS2559->mnDevBAddr, TAS2559_BOOKCTL_REG, nBook);
226 pTAS2559->mnDevBCurrentBook = nBook;
227 if(nPage != 0){
228 tas2559_i2c_write_device(pTAS2559, pTAS2559->mnDevBAddr, TAS2559_BOOKCTL_PAGE, nPage);
229 pTAS2559->mnDevBCurrentPage = nPage;
230 }
231 }
232 }
233 }
234
235 return nResult;
236}
237
238/*
239* tas2559_dev_read :
240* platform independent, don't change unless necessary
241*/
242static int tas2559_dev_read(
243 struct tas2559_priv *pTAS2559,
244 enum channel chn,
245 unsigned int nRegister,
246 unsigned int *pValue)
247{
248 int nResult = 0;
249 unsigned char Value = 0;
250
251 mutex_lock(&pTAS2559->dev_lock);
252
253 if (pTAS2559->mbTILoadActive) {
254 if (!(nRegister & 0x80000000)){
255 mutex_unlock(&pTAS2559->dev_lock);
256 return 0; // let only reads from TILoad pass.
257 }
258 nRegister &= ~0x80000000;
259
260 dev_dbg(pTAS2559->dev, "TiLoad R CH[%d] REG B[%d]P[%d]R[%d]\n",
261 chn,
262 TAS2559_BOOK_ID(nRegister),
263 TAS2559_PAGE_ID(nRegister),
264 TAS2559_PAGE_REG(nRegister));
265 }
266
267 nResult = tas2559_change_book_page(pTAS2559,
268 chn,
269 TAS2559_BOOK_ID(nRegister),
270 TAS2559_PAGE_ID(nRegister));
271 if(nResult >=0){
272 if(chn == DevA){
273 nResult = tas2559_i2c_read_device(pTAS2559, pTAS2559->mnDevAAddr, TAS2559_PAGE_REG(nRegister), &Value);
274 }else if(chn == DevB){
275 nResult = tas2559_i2c_read_device(pTAS2559, pTAS2559->mnDevBAddr, TAS2559_PAGE_REG(nRegister), &Value);
276 }else{
277 dev_err(pTAS2559->dev, "read chn ERROR %d\n", chn);
278 nResult = -1;
279 }
280
281 if(nResult>=0) *pValue = Value;
282 }
283 mutex_unlock(&pTAS2559->dev_lock);
284 return nResult;
285}
286
287/*
288* tas2559_dev_write :
289* platform independent, don't change unless necessary
290*/
291static int tas2559_dev_write(
292 struct tas2559_priv *pTAS2559,
293 enum channel chn,
294 unsigned int nRegister,
295 unsigned int nValue)
296{
297 int nResult = 0;
298
299 mutex_lock(&pTAS2559->dev_lock);
300 if ((nRegister == 0xAFFEAFFE) && (nValue == 0xBABEBABE)) {
301 pTAS2559->mbTILoadActive = true;
302 mutex_unlock(&pTAS2559->dev_lock);
303
304 dev_dbg(pTAS2559->dev, "TiLoad Active\n");
305 return 0;
306 }
307
308 if ((nRegister == 0xBABEBABE) && (nValue == 0xAFFEAFFE)) {
309 pTAS2559->mbTILoadActive = false;
310 mutex_unlock(&pTAS2559->dev_lock);
311
312 dev_dbg(pTAS2559->dev, "TiLoad DeActive\n");
313 return 0;
314 }
315
316 if (pTAS2559->mbTILoadActive) {
317 if (!(nRegister & 0x80000000)){
318 mutex_unlock(&pTAS2559->dev_lock);
319 return 0; // let only writes from TILoad pass.
320 }
321 nRegister &= ~0x80000000;
322
323 dev_dbg(pTAS2559->dev, "TiLoad W CH[%d] REG B[%d]P[%d]R[%d] =0x%x\n",
324 chn,
325 TAS2559_BOOK_ID(nRegister),
326 TAS2559_PAGE_ID(nRegister),
327 TAS2559_PAGE_REG(nRegister),
328 nValue);
329 }
330
331 nResult = tas2559_change_book_page(pTAS2559,
332 chn,
333 TAS2559_BOOK_ID(nRegister),
334 TAS2559_PAGE_ID(nRegister));
335
336 if(nResult >= 0){
337 if(chn & DevA){
338 nResult = tas2559_i2c_write_device(pTAS2559, pTAS2559->mnDevAAddr, TAS2559_PAGE_REG(nRegister), nValue);
339 }
340
341 if(chn & DevB){
342 nResult = tas2559_i2c_write_device(pTAS2559, pTAS2559->mnDevBAddr, TAS2559_PAGE_REG(nRegister), nValue);
343 }
344 }
345
346 mutex_unlock(&pTAS2559->dev_lock);
347
348 return nResult;
349}
350
351/*
352* tas2559_dev_bulk_read :
353* platform independent, don't change unless necessary
354*/
355static int tas2559_dev_bulk_read(
356 struct tas2559_priv *pTAS2559,
357 enum channel chn,
358 unsigned int nRegister,
359 u8 * pData,
360 unsigned int nLength)
361{
362 int nResult = 0;
363 unsigned char reg = 0;
364 unsigned char Addr = 0;
365
366 mutex_lock(&pTAS2559->dev_lock);
367 if (pTAS2559->mbTILoadActive) {
368 if (!(nRegister & 0x80000000)){
369 mutex_unlock(&pTAS2559->dev_lock);
370 return 0; // let only writes from TILoad pass.
371 }
372
373 nRegister &= ~0x80000000;
374 dev_dbg(pTAS2559->dev, "TiLoad BR CH[%d] REG B[%d]P[%d]R[%d], count=%d\n",
375 chn,
376 TAS2559_BOOK_ID(nRegister),
377 TAS2559_PAGE_ID(nRegister),
378 TAS2559_PAGE_REG(nRegister),
379 nLength);
380 }
381
382 nResult = tas2559_change_book_page(pTAS2559,
383 chn,
384 TAS2559_BOOK_ID(nRegister),
385 TAS2559_PAGE_ID(nRegister));
386 if(nResult >= 0){
387 reg = TAS2559_PAGE_REG(nRegister);
388 if(chn == DevA){
389 Addr = pTAS2559->mnDevAAddr;
390 }else if(chn == DevB){
391 Addr = pTAS2559->mnDevBAddr;
392 }else{
393 dev_err(pTAS2559->dev, "bulk read chn ERROR %d\n", chn);
394 nResult = -1;
395 }
396
397 if(nResult >= 0){
398 nResult = tas2559_i2c_bulkread_device(
399 pTAS2559, Addr, reg, pData, nLength);
400 }
401 }
402
403 mutex_unlock(&pTAS2559->dev_lock);
404
405 return nResult;
406}
407
408/*
409* tas2559_dev_bulk_write :
410* platform independent, don't change unless necessary
411*/
412static int tas2559_dev_bulk_write(
413 struct tas2559_priv *pTAS2559,
414 enum channel chn,
415 unsigned int nRegister,
416 u8 * pData,
417 unsigned int nLength)
418{
419 int nResult = 0;
420 unsigned char reg = 0;
421
422 mutex_lock(&pTAS2559->dev_lock);
423 if (pTAS2559->mbTILoadActive) {
424 if (!(nRegister & 0x80000000)){
425 mutex_unlock(&pTAS2559->dev_lock);
426 return 0; // let only writes from TILoad pass.
427 }
428
429 nRegister &= ~0x80000000;
430
431 dev_dbg(pTAS2559->dev, "TiLoad BW CH[%d] REG B[%d]P[%d]R[%d], count=%d\n",
432 chn,
433 TAS2559_BOOK_ID(nRegister),
434 TAS2559_PAGE_ID(nRegister),
435 TAS2559_PAGE_REG(nRegister),
436 nLength);
437 }
438
439 nResult = tas2559_change_book_page(
440 pTAS2559,
441 chn,
442 TAS2559_BOOK_ID(nRegister),
443 TAS2559_PAGE_ID(nRegister));
444
445 if(nResult >=0){
446 reg = TAS2559_PAGE_REG(nRegister);
447 if(chn & DevA){
448 nResult = tas2559_i2c_bulkwrite_device(
449 pTAS2559,
450 pTAS2559->mnDevAAddr,
451 reg, pData, nLength);
452 if(nResult < 0){
453 dev_err(pTAS2559->dev, "bulk write error %d\n", nResult);
454 }
455 }
456
457 if(chn & DevB){
458 nResult = tas2559_i2c_bulkwrite_device(
459 pTAS2559,
460 pTAS2559->mnDevBAddr,
461 reg, pData, nLength);
462 if(nResult < 0){
463 dev_err(pTAS2559->dev, "bulk write error %d\n", nResult);
464 }
465 }
466 }
467 mutex_unlock(&pTAS2559->dev_lock);
468
469 return nResult;
470}
471
472/*
473* tas2559_dev_update_bits :
474* platform independent, don't change unless necessary
475*/
476static int tas2559_dev_update_bits(
477 struct tas2559_priv *pTAS2559,
478 enum channel chn,
479 unsigned int nRegister,
480 unsigned int nMask,
481 unsigned int nValue)
482{
483 int nResult = 0;
484
485 mutex_lock(&pTAS2559->dev_lock);
486
487 if (pTAS2559->mbTILoadActive) {
488 if (!(nRegister & 0x80000000)){
489 mutex_unlock(&pTAS2559->dev_lock);
490 return 0; // let only writes from TILoad pass.
491 }
492
493 nRegister &= ~0x80000000;
494
495 dev_dbg(pTAS2559->dev, "TiLoad SB CH[%d] REG B[%d]P[%d]R[%d], mask=0x%x, value=0x%x\n",
496 chn,
497 TAS2559_BOOK_ID(nRegister),
498 TAS2559_PAGE_ID(nRegister),
499 TAS2559_PAGE_REG(nRegister),
500 nMask, nValue);
501 }
502
503 nResult = tas2559_change_book_page(
504 pTAS2559,
505 chn,
506 TAS2559_BOOK_ID(nRegister),
507 TAS2559_PAGE_ID(nRegister));
508
509 if(nResult>=0){
510 if(chn&DevA){
511 tas2559_i2c_update_bits(pTAS2559, pTAS2559->mnDevAAddr, TAS2559_PAGE_REG(nRegister), nMask, nValue);
512 }
513
514 if(chn&DevB){
515 tas2559_i2c_update_bits(pTAS2559, pTAS2559->mnDevBAddr, TAS2559_PAGE_REG(nRegister), nMask, nValue);
516 }
517 }
518
519 mutex_unlock(&pTAS2559->dev_lock);
520 return nResult;
521}
522
523void tas2559_enableIRQ(struct tas2559_priv *pTAS2559, int enable)
524{
525 if(enable)
526 enable_irq(pTAS2559->mnIRQ);
527 else
528 disable_irq(pTAS2559->mnIRQ);
529}
530
531static void irq_work_routine(struct work_struct *work)
532{
533// int nResult = 0;
534// unsigned char nDev1IntStatus1, nDev1IntStatus2;
535// unsigned char nDev2IntStatus1, nDev2IntStatus2;
536 struct tas2559_priv *pTAS2559 =
537 container_of(work, struct tas2559_priv, irq_work);
538
539 mutex_lock(&pTAS2559->dev_lock);
540
541 //check IRQ status and take action accordingly
542
543 mutex_unlock(&pTAS2559->dev_lock);
544}
545
546static irqreturn_t tas2559_irq_handler(int irq, void *dev_id)
547{
548 struct tas2559_priv *pTAS2559 = (struct tas2559_priv *)dev_id;
549
550 tas2559_enableIRQ(pTAS2559, 0);
551 schedule_work(&pTAS2559->irq_work);
552 return IRQ_HANDLED;
553}
554
555static bool tas2559_volatile(struct device *pDev, unsigned int nRegister)
556{
557 return true;
558}
559
560static bool tas2559_writeable(struct device *pDev, unsigned int nRegister)
561{
562 return true;
563}
564
565static const struct regmap_config tas2559_i2c_regmap = {
566 .reg_bits = 8,
567 .val_bits = 8,
568 .writeable_reg = tas2559_writeable,
569 .volatile_reg = tas2559_volatile,
570 .cache_type = REGCACHE_NONE,
571 .max_register = 128,
572};
573/*
574* tas2559_i2c_probe :
575* platform dependent
576* should implement hardware reset functionality
577*/
578static int tas2559_i2c_probe(struct i2c_client *pClient,
579 const struct i2c_device_id *pID)
580{
581 struct tas2559_priv *pTAS2559;
582 int nResult;
583 unsigned int nValue = 0;
584
585 dev_info(&pClient->dev, "%s enter\n", __FUNCTION__);
586
587 pTAS2559 = devm_kzalloc(&pClient->dev, sizeof(struct tas2559_priv), GFP_KERNEL);
588 if (!pTAS2559){
589 dev_err(&pClient->dev, " -ENOMEM\n");
590 nResult = -ENOMEM;
591 goto err;
592 }
593
594 pTAS2559->client = pClient;
595 pTAS2559->dev = &pClient->dev;
596 i2c_set_clientdata(pClient, pTAS2559);
597 dev_set_drvdata(&pClient->dev, pTAS2559);
598
599 pTAS2559->mpRegmap = devm_regmap_init_i2c(pClient, &tas2559_i2c_regmap);
600 if (IS_ERR(pTAS2559->mpRegmap)) {
601 nResult = PTR_ERR(pTAS2559->mpRegmap);
602 dev_err(&pClient->dev, "Failed to allocate register map: %d\n",
603 nResult);
604 goto err;
605 }
606
607 if (pClient->dev.of_node){
608 tas2559_parse_dt(&pClient->dev, pTAS2559);
609 }
610
611 if (gpio_is_valid(pTAS2559->mnResetGPIO)) {
612#ifdef HW_RESET //mandatory
613 devm_gpio_request_one(&pClient->dev, pTAS2559->mnResetGPIO,
614 GPIOF_OUT_INIT_LOW, "TAS2559_RST");
615 mdelay(5);
616 gpio_set_value_cansleep(pTAS2559->mnResetGPIO, 1);
617 mdelay(1);
618#endif
619 }else{
620 pTAS2559->mnDevACurrentBook = -1;
621 pTAS2559->mnDevACurrentPage = -1;
622 pTAS2559->mnDevBCurrentBook = -1;
623 pTAS2559->mnDevBCurrentPage = -1;
624 }
625
626 pTAS2559->read = tas2559_dev_read;
627 pTAS2559->write = tas2559_dev_write;
628 pTAS2559->bulk_read = tas2559_dev_bulk_read;
629 pTAS2559->bulk_write = tas2559_dev_bulk_write;
630 pTAS2559->update_bits = tas2559_dev_update_bits;
631 pTAS2559->enableIRQ = tas2559_enableIRQ;
632 pTAS2559->set_config = tas2559_set_config;
633 pTAS2559->set_calibration = tas2559_set_calibration;
634
635 mutex_init(&pTAS2559->dev_lock);
636
637 /* Reset the chip */
638 nResult = tas2559_dev_write(pTAS2559, DevBoth, TAS2559_SW_RESET_REG, 1);
639 if(nResult < 0){
640 dev_err(&pClient->dev, "I2c fail, %d\n", nResult);
641 goto err;
642 }
643
644 mdelay(1);
645 tas2559_dev_read(pTAS2559, DevA, TAS2559_REV_PGID_REG, &nValue);
646 pTAS2559->mnDevAPGID = nValue;
647 dev_info(&pClient->dev, "DevA PGID=0x%x\n", nValue);
648 nResult = pTAS2559->read(pTAS2559, DevB, TAS2560_ID_REG, &nValue);
649 pTAS2559->mnDevBPGID = nValue;
650 dev_info(pTAS2559->dev, "DevB PGID=0x%02x\n", nValue);
651
652 if (gpio_is_valid(pTAS2559->mnGpioINT)){
653 nResult = gpio_request(pTAS2559->mnGpioINT, "TAS2559-IRQ");
654 if(nResult < 0){
655 dev_err(pTAS2559->dev,
656 "%s: GPIO %d request INT error\n",
657 __FUNCTION__, pTAS2559->mnGpioINT);
658 goto err;
659 }
660
661 tas2559_configIRQ(pTAS2559);
662 INIT_WORK(&pTAS2559->irq_work, irq_work_routine);
663
664 gpio_direction_input(pTAS2559->mnGpioINT);
665 pTAS2559->mnIRQ = gpio_to_irq(pTAS2559->mnGpioINT);
666 dev_dbg(pTAS2559->dev, "irq = %d \n", pTAS2559->mnIRQ);
667 nResult = request_threaded_irq(pTAS2559->mnIRQ, tas2559_irq_handler,
668 NULL, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
669 pClient->name, pTAS2559);
670 if (nResult < 0) {
671 dev_err(pTAS2559->dev,
672 "request_irq failed, %d\n", nResult);
673 goto err;
674 }
675
676 tas2559_enableIRQ(pTAS2559, 0);
677 }
678
679 pTAS2559->mpFirmware = devm_kzalloc(&pClient->dev, sizeof(TFirmware), GFP_KERNEL);
680 if (!pTAS2559->mpFirmware){
681 dev_err(&pClient->dev, "mpFirmware ENOMEM\n");
682 nResult = -ENOMEM;
683 goto err;
684 }
685
686 pTAS2559->mpCalFirmware = devm_kzalloc(&pClient->dev, sizeof(TFirmware), GFP_KERNEL);
687 if (!pTAS2559->mpCalFirmware){
688 dev_err(&pClient->dev, "mpCalFirmware ENOMEM\n");
689 nResult = -ENOMEM;
690 goto err;
691 }
692
693#ifdef CONFIG_TAS2559_CODEC
694 tas2559_register_codec(pTAS2559);
695#endif
696
697#ifdef CONFIG_TAS2559_MISC
698 mutex_init(&pTAS2559->file_lock);
699 tas2559_register_misc(pTAS2559);
700#endif
701
702#ifdef ENABLE_TILOAD
703 tiload_driver_init(pTAS2559);
704#endif
705
706 nResult = request_firmware_nowait(THIS_MODULE, 1, TAS2559_FW_NAME,
707 pTAS2559->dev, GFP_KERNEL, pTAS2559, tas2559_fw_ready);
708
709err:
710
711 return nResult;
712}
713
714static int tas2559_i2c_remove(struct i2c_client *pClient)
715{
716 struct tas2559_priv *pTAS2559 = i2c_get_clientdata(pClient);
717
718 dev_info(pTAS2559->dev, "%s\n", __FUNCTION__);
719
720#ifdef CONFIG_TAS2559_CODEC
721 tas2559_deregister_codec(pTAS2559);
722#endif
723
724#ifdef CONFIG_TAS2559_MISC
725 tas2559_deregister_misc(pTAS2559);
726 mutex_destroy(&pTAS2559->file_lock);
727#endif
728
729 mutex_destroy(&pTAS2559->dev_lock);
730 return 0;
731}
732
733static const struct i2c_device_id tas2559_i2c_id[] = {
734 {"tas2559", 0},
735 {}
736};
737
738MODULE_DEVICE_TABLE(i2c, tas2559_i2c_id);
739
740#if defined(CONFIG_OF)
741static const struct of_device_id tas2559_of_match[] = {
742 {.compatible = "ti,tas2559"},
743 {},
744};
745
746MODULE_DEVICE_TABLE(of, tas2559_of_match);
747#endif
748
749static struct i2c_driver tas2559_i2c_driver = {
750 .driver = {
751 .name = "tas2559",
752 .owner = THIS_MODULE,
753#if defined(CONFIG_OF)
754 .of_match_table = of_match_ptr(tas2559_of_match),
755#endif
756 },
757 .probe = tas2559_i2c_probe,
758 .remove = tas2559_i2c_remove,
759 .id_table = tas2559_i2c_id,
760};
761
762module_i2c_driver(tas2559_i2c_driver);
763
764MODULE_AUTHOR("Texas Instruments Inc.");
765MODULE_DESCRIPTION("TAS2559 Stereo I2C Smart Amplifier driver");
766MODULE_LICENSE("GPLv2");
diff --git a/tas2559.h b/tas2559.h
new file mode 100755
index 0000000..1a8be79
--- /dev/null
+++ b/tas2559.h
@@ -0,0 +1,453 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tas2559.h
19**
20** Description:
21** definitions and data structures for TAS2559 Android Linux driver
22**
23** =============================================================================
24*/
25
26#ifndef _TAS2559_H
27#define _TAS2559_H
28
29#include <linux/regmap.h>
30
31/* Page Control Register */
32#define TAS2559_PAGECTL_REG 0
33
34/* Book Control Register (available in page0 of each book) */
35#define TAS2559_BOOKCTL_PAGE 0
36#define TAS2559_BOOKCTL_REG 127
37
38#define TAS2559_REG(book, page, reg) (((book * 256 * 128) + \
39 (page * 128)) + reg)
40
41#define TAS2559_BOOK_ID(reg) (reg / (256 * 128))
42#define TAS2559_PAGE_ID(reg) ((reg % (256 * 128)) / 128)
43#define TAS2559_BOOK_REG(reg) (reg % (256 * 128))
44#define TAS2559_PAGE_REG(reg) ((reg % (256 * 128)) % 128)
45
46/* Book0, Page0 registers */
47#define TAS2559_SW_RESET_REG TAS2559_REG(0, 0, 1)
48
49#define TAS2559_REV_PGID_REG TAS2559_REG(0, 0, 3)
50#define TAS2559_PG_VERSION_1P0 0x00
51#define TAS2559_PG_VERSION_2P0 0x10
52#define TAS2559_PG_VERSION_2P1 0x20
53
54#define TAS2559_POWER_CTRL1_REG TAS2559_REG(0, 0, 4)
55#define TAS2559_POWER_CTRL2_REG TAS2559_REG(0, 0, 5)
56
57#define TAS2559_SPK_CTRL_REG TAS2559_REG(0, 0, 6)
58/* B0P0R6 - TAS2559_SPK_CTRL_REG */
59#define TAS2559_DAC_GAIN_MASK (0xf << 3)
60#define TAS2559_DAC_GAIN_SHIFT 0x03
61
62#define TAS2559_MUTE_REG TAS2559_REG(0, 0, 7)
63#define TAS2559_SNS_CTRL_REG TAS2559_REG(0, 0, 8)
64#define TAS2559_ADC_INPUT_SEL_REG TAS2559_REG(0, 0, 9)
65#define TAS2559_DBOOST_CTL_REG TAS2559_REG(0, 0, 10)
66#define TAS2559_NONAME11_REG TAS2559_REG(0, 0, 11)
67#define TAS2559_NONAME12_REG TAS2559_REG(0, 0, 12)
68#define TAS2559_NONAME13_REG TAS2559_REG(0, 0, 13)
69#define TAS2559_NONAME14_REG TAS2559_REG(0, 0, 14)
70#define TAS2559_NONAME15_REG TAS2559_REG(0, 0, 15)
71#define TAS2559_NONAME16_REG TAS2559_REG(0, 0, 16)
72#define TAS2559_NONAME17_REG TAS2559_REG(0, 0, 17)
73#define TAS2559_NONAME18_REG TAS2559_REG(0, 0, 18)
74#define TAS2559_SAR_SAMPLING_TIME_REG TAS2559_REG(0, 0, 19)
75#define TAS2559_SAR_ADC1_REG TAS2559_REG(0, 0, 20)
76#define TAS2559_SAR_ADC2_REG TAS2559_REG(0, 0, 21)
77#define TAS2559_CRC_CHECKSUM_REG TAS2559_REG(0, 0, 32)
78#define TAS2559_CRC_RESET_REG TAS2559_REG(0, 0, 33)
79#define TAS2559_DSP_MODE_SELECT_REG TAS2559_REG(0, 0, 34)
80#define TAS2559_ASI_CTRL_REG TAS2559_REG(0, 0, 42)
81#define TAS2559_CLK_ERR_CTRL TAS2559_REG(0, 0, 44)
82#define TAS2559_DBOOST_CFG_REG TAS2559_REG(0, 0, 52)
83#define TAS2559_POWER_UP_FLAG_REG TAS2559_REG(0, 0, 100)
84#define TAS2559_FLAGS_1 TAS2559_REG(0, 0, 104)
85#define TAS2559_FLAGS_2 TAS2559_REG(0, 0, 108)
86/* Book0, Page1 registers */
87#define TAS2559_ASI1_DAC_FORMAT_REG TAS2559_REG(0, 1, 1)
88#define TAS2559_ASI1_ADC_FORMAT_REG TAS2559_REG(0, 1, 2)
89#define TAS2559_ASI1_OFFSET1_REG TAS2559_REG(0, 1, 3)
90#define TAS2559_ASI1_ADC_PATH_REG TAS2559_REG(0, 1, 7)
91#define TAS2559_ASI1_DAC_BCLK_REG TAS2559_REG(0, 1, 8)
92#define TAS2559_ASI1_DAC_WCLK_REG TAS2559_REG(0, 1, 9)
93#define TAS2559_ASI1_ADC_BCLK_REG TAS2559_REG(0, 1, 10)
94#define TAS2559_ASI1_ADC_WCLK_REG TAS2559_REG(0, 1, 11)
95#define TAS2559_ASI1_DIN_DOUT_MUX_REG TAS2559_REG(0, 1, 12)
96#define TAS2559_ASI1_BDIV_CLK_SEL_REG TAS2559_REG(0, 1, 13)
97#define TAS2559_ASI1_BDIV_CLK_RATIO_REG TAS2559_REG(0, 1, 14)
98#define TAS2559_ASI1_WDIV_CLK_RATIO_REG TAS2559_REG(0, 1, 15)
99#define TAS2559_ASI1_DAC_CLKOUT_REG TAS2559_REG(0, 1, 16)
100#define TAS2559_ASI1_ADC_CLKOUT_REG TAS2559_REG(0, 1, 17)
101
102#define TAS2559_ASI2_DAC_FORMAT_REG TAS2559_REG(0, 1, 21)
103#define TAS2559_ASI2_ADC_FORMAT_REG TAS2559_REG(0, 1, 22)
104#define TAS2559_ASI2_OFFSET1_REG TAS2559_REG(0, 1, 23)
105#define TAS2559_ASI2_ADC_PATH_REG TAS2559_REG(0, 1, 27)
106#define TAS2559_ASI2_DAC_BCLK_REG TAS2559_REG(0, 1, 28)
107#define TAS2559_ASI2_DAC_WCLK_REG TAS2559_REG(0, 1, 29)
108#define TAS2559_ASI2_ADC_BCLK_REG TAS2559_REG(0, 1, 30)
109#define TAS2559_ASI2_ADC_WCLK_REG TAS2559_REG(0, 1, 31)
110#define TAS2559_ASI2_DIN_DOUT_MUX_REG TAS2559_REG(0, 1, 32)
111#define TAS2559_ASI2_BDIV_CLK_SEL_REG TAS2559_REG(0, 1, 33)
112#define TAS2559_ASI2_BDIV_CLK_RATIO_REG TAS2559_REG(0, 1, 34)
113#define TAS2559_ASI2_WDIV_CLK_RATIO_REG TAS2559_REG(0, 1, 35)
114#define TAS2559_ASI2_DAC_CLKOUT_REG TAS2559_REG(0, 1, 36)
115#define TAS2559_ASI2_ADC_CLKOUT_REG TAS2559_REG(0, 1, 37)
116
117#define TAS2559_GPIO1_PIN_REG TAS2559_REG(0, 1, 61)
118#define TAS2559_GPIO2_PIN_REG TAS2559_REG(0, 1, 62)
119#define TAS2559_GPIO3_PIN_REG TAS2559_REG(0, 1, 63)
120#define TAS2559_GPIO4_PIN_REG TAS2559_REG(0, 1, 64)
121#define TAS2559_GPIO5_PIN_REG TAS2559_REG(0, 1, 65)
122#define TAS2559_GPIO6_PIN_REG TAS2559_REG(0, 1, 66)
123#define TAS2559_GPIO7_PIN_REG TAS2559_REG(0, 1, 67)
124#define TAS2559_GPIO8_PIN_REG TAS2559_REG(0, 1, 68)
125#define TAS2559_GPIO9_PIN_REG TAS2559_REG(0, 1, 69)
126#define TAS2559_GPIO10_PIN_REG TAS2559_REG(0, 1, 70)
127
128#define TAS2559_GPI_PIN_REG TAS2559_REG(0, 1, 77)
129#define TAS2559_GPIO_HIZ_CTRL1_REG TAS2559_REG(0, 1, 79)
130#define TAS2559_GPIO_HIZ_CTRL2_REG TAS2559_REG(0, 1, 80)
131#define TAS2559_GPIO_HIZ_CTRL3_REG TAS2559_REG(0, 1, 81)
132#define TAS2559_GPIO_HIZ_CTRL4_REG TAS2559_REG(0, 1, 82)
133#define TAS2559_GPIO_HIZ_CTRL5_REG TAS2559_REG(0, 1, 83)
134
135#define TAS2559_BIT_BANG_CTRL_REG TAS2559_REG(0, 1, 87)
136#define TAS2559_BIT_BANG_OUT1_REG TAS2559_REG(0, 1, 88)
137#define TAS2559_BIT_BANG_OUT2_REG TAS2559_REG(0, 1, 89)
138#define TAS2559_BIT_BANG_IN1_REG TAS2559_REG(0, 1, 90)
139#define TAS2559_BIT_BANG_IN2_REG TAS2559_REG(0, 1, 91)
140#define TAS2559_BIT_BANG_IN3_REG TAS2559_REG(0, 1, 92)
141
142#define TAS2559_PDM_IN_CLK_REG TAS2559_REG(0, 1, 94)
143#define TAS2559_PDM_IN_PIN_REG TAS2559_REG(0, 1, 95)
144
145#define TAS2559_ASIM_IFACE1_REG TAS2559_REG(0, 1, 98)
146#define TAS2559_ASIM_FORMAT_REG TAS2559_REG(0, 1, 99)
147#define TAS2559_ASIM_IFACE3_REG TAS2559_REG(0, 1, 100)
148#define TAS2559_ASIM_IFACE4_REG TAS2559_REG(0, 1, 101)
149#define TAS2559_ASIM_IFACE5_REG TAS2559_REG(0, 1, 102)
150#define TAS2559_ASIM_IFACE6_REG TAS2559_REG(0, 1, 103)
151#define TAS2559_ASIM_IFACE7_REG TAS2559_REG(0, 1, 104)
152#define TAS2559_ASIM_IFACE8_REG TAS2559_REG(0, 1, 105)
153#define TAS2559_ASIM_IFACE9_REG TAS2559_REG(0, 1, 106)
154
155#define TAS2559_INT_GEN1_REG TAS2559_REG(0, 1, 108)
156#define TAS2559_INT_GEN2_REG TAS2559_REG(0, 1, 109)
157#define TAS2559_INT_GEN3_REG TAS2559_REG(0, 1, 110)
158#define TAS2559_INT_GEN4_REG TAS2559_REG(0, 1, 111)
159
160#define TAS2559_MAIN_CLKIN_REG TAS2559_REG(0, 1, 115)
161#define TAS2559_PLL_CLKIN_REG TAS2559_REG(0, 1, 116)
162#define TAS2559_CLKOUT_MUX_REG TAS2559_REG(0, 1, 117)
163#define TAS2559_CLKOUT_CDIV_REG TAS2559_REG(0, 1, 118)
164
165#define TAS2559_HACK_GP01_REG TAS2559_REG(0, 1, 122)
166
167#define TAS2559_HACK01_REG TAS2559_REG(0, 2, 10)
168
169#define TAS2559_ISENSE_THRESHOLD TAS2559_REG(0, 50, 104)
170#define TAS2559_BOOSTON_EFFICIENCY TAS2559_REG(0, 51, 16)
171#define TAS2559_BOOSTOFF_EFFICIENCY TAS2559_REG(0, 51, 20)
172#define TAS2559_BOOST_HEADROOM TAS2559_REG(0, 51, 24)
173#define TAS2559_THERMAL_FOLDBACK_REG TAS2559_REG(0, 51, 100)
174#define TAS2559_VPRED_COMP_REG TAS2559_REG(0, 53, 24)
175
176#define TAS2559_TEST_MODE_REG TAS2559_REG(0, 253, 13)
177#define TAS2559_BROADCAST_REG TAS2559_REG(0, 253, 54)
178#define TAS2559_CRYPTIC_REG TAS2559_REG(0, 253, 71)
179
180//#define TAS2559__REG TAS2559_REG(0, 1, )
181//#define TAS2559__REG TAS2559_REG(1, 0, )
182#define TAS2559_DAC_INTERPOL_REG TAS2559_REG(100, 0, 1)
183#define TAS2559_SOFT_MUTE_REG TAS2559_REG(100, 0, 7)
184#define TAS2559_PLL_P_VAL_REG TAS2559_REG(100, 0, 27)
185#define TAS2559_PLL_J_VAL_REG TAS2559_REG(100, 0, 28)
186#define TAS2559_PLL_D_VAL_MSB_REG TAS2559_REG(100, 0, 29)
187#define TAS2559_PLL_D_VAL_LSB_REG TAS2559_REG(100, 0, 30)
188#define TAS2559_CLK_MISC_REG TAS2559_REG(100, 0, 31)
189#define TAS2559_PLL_N_VAL_REG TAS2559_REG(100, 0, 32)
190#define TAS2559_DAC_MADC_VAL_REG TAS2559_REG(100, 0, 33)
191#define TAS2559_ISENSE_DIV_REG TAS2559_REG(100, 0, 42)
192#define TAS2559_RAMP_CLK_DIV_MSB_REG TAS2559_REG(100, 0, 43)
193#define TAS2559_RAMP_CLK_DIV_LSB_REG TAS2559_REG(100, 0, 44)
194/* Bits */
195/* B0P0R4 - TAS2559_POWER_CTRL1_REG */
196#define TAS2559_SW_SHUTDOWN (0x1 << 0)
197#define TAS2559_MADC_POWER_UP (0x1 << 3)
198#define TAS2559_MDAC_POWER_UP (0x1 << 4)
199#define TAS2559_NDIV_POWER_UP (0x1 << 5)
200#define TAS2559_PLL_POWER_UP (0x1 << 6)
201#define TAS2559_DSP_POWER_UP (0x1 << 7)
202
203/* B0P0R5 - TAS2559_POWER_CTRL2_REG */
204#define TAS2559_VSENSE_ENABLE (0x1 << 0)
205#define TAS2559_ISENSE_ENABLE (0x1 << 1)
206#define TAS2559_BOOST_ENABLE (0x1 << 5)
207#define TAS2559_CLASSD_ENABLE (0x1 << 7)
208
209/* B0P0R7 - TAS2559_MUTE_REG */
210#define TAS2559_CLASSD_MUTE (0x1 << 0)
211#define TAS2559_ISENSE_MUTE (0x1 << 1)
212
213/* B0P253R13 - TAS2559_TEST_MODE_REG */
214#define TAS2559_TEST_MODE_ENABLE (13)
215#define TAS2559_TEST_MODE_MASK (0xf << 0)
216
217/* B0P253R71 - TAS2559_CRYPTIC_REG */
218#define TAS2559_OSC_TRIM_CAP(x) ((x & 0x3f) << 0)
219#define TAS2559_DISABLE_ENCRYPTION (0x1 << 6)
220#define TAS2559_SL_COMP (0x1 << 7)
221
222/* B0P1R115/6 - TAS2559_MAIN/PLL_CLKIN_REG */
223#define TAS2559_XXX_CLKIN_GPIO1 (0)
224#define TAS2559_XXX_CLKIN_GPIO2 (1)
225#define TAS2559_XXX_CLKIN_GPIO3 (2)
226#define TAS2559_XXX_CLKIN_GPIO4 (3)
227#define TAS2559_XXX_CLKIN_GPIO5 (4)
228#define TAS2559_XXX_CLKIN_GPIO6 (5)
229#define TAS2559_XXX_CLKIN_GPIO7 (6)
230#define TAS2559_XXX_CLKIN_GPIO8 (7)
231#define TAS2559_XXX_CLKIN_GPIO9 (8)
232#define TAS2559_XXX_CLKIN_GPIO10 (9)
233#define TAS2559_XXX_CLKIN_GPI1 (12)
234#define TAS2559_XXX_CLKIN_GPI2 (13)
235#define TAS2559_XXX_CLKIN_GPI3 (14)
236#define TAS2559_NDIV_CLKIN_PLL (15)
237#define TAS2559_PLL_CLKIN_INT_OSC (15)
238
239#define TAS2559_MCLK_CLKIN_SRC_GPIO1 (0)
240#define TAS2559_MCLK_CLKIN_SRC_GPIO2 (1)
241#define TAS2559_MCLK_CLKIN_SRC_GPIO3 (2)
242#define TAS2559_MCLK_CLKIN_SRC_GPIO4 (3)
243#define TAS2559_MCLK_CLKIN_SRC_GPIO5 (4)
244#define TAS2559_MCLK_CLKIN_SRC_GPIO6 (5)
245#define TAS2559_MCLK_CLKIN_SRC_GPIO7 (6)
246#define TAS2559_MCLK_CLKIN_SRC_GPIO8 (7)
247#define TAS2559_MCLK_CLKIN_SRC_GPIO9 (8)
248#define TAS2559_MCLK_CLKIN_SRC_GPIO10 (9)
249#define TAS2559_MCLK_CLKIN_SRC_GPI1 (12)
250#define TAS2559_MCLK_CLKIN_SRC_GPI2 (13)
251#define TAS2559_MCLK_CLKIN_SRC_GPI3 (14)
252
253#define TAS2559_FORMAT_I2S (0x0 << 5)
254#define TAS2559_FORMAT_DSP (0x1 << 5)
255#define TAS2559_FORMAT_RIGHT_J (0x2 << 5)
256#define TAS2559_FORMAT_LEFT_J (0x3 << 5)
257#define TAS2559_FORMAT_MONO_PCM (0x4 << 5)
258#define TAS2559_FORMAT_MASK (0x7 << 5)
259
260#define TAS2559_WORDLENGTH_16BIT (0x0 << 3)
261#define TAS2559_WORDLENGTH_20BIT (0x1 << 3)
262#define TAS2559_WORDLENGTH_24BIT (0x2 << 3)
263#define TAS2559_WORDLENGTH_32BIT (0x3 << 3)
264#define TAS2559_WORDLENGTH_MASK TAS2559_WORDLENGTH_32BIT
265
266/* B100P0R7 - TAS2559_SOFT_MUTE_REG */
267#define TAS2559_PDM_SOFT_MUTE (0x1 << 0)
268#define TAS2559_VSENSE_SOFT_MUTE (0x1 << 1)
269#define TAS2559_ISENSE_SOFT_MUTE (0x1 << 2)
270#define TAS2559_CLASSD_SOFT_MUTE (0x1 << 3)
271
272/* B100P0R27 - TAS2559_PLL_P_VAL_REG */
273#define TAS2559_PLL_P_VAL_MASK (0x3f << 0)
274
275/* B100P0R28 - TAS2559_PLL_J_VAL_REG */
276#define TAS2559_PLL_J_VAL_MASK ((unsigned int ) (0x7f << 0))
277#define TAS2559_PLL_J_VAL_MASKX 0x00
278
279/* B100P0R29-30 - TAS2559_PLL_D_VAL_MSB/LSB_REG */
280#define TAS2559_PLL_D_MSB_VAL(x) ((x >> 8) & 0x3f)
281#define TAS2559_PLL_D_LSB_VAL(x) (x & 0xff)
282
283/* B100P0R31 - TAS2559_CLK_MISC_REG */
284#define TAS2559_DSP_CLK_FROM_PLL (0x1 << 5)
285
286#define TAS2559_FW_NAME "tas2559_uCDSP.bin"
287
288#define LOAD_8OHM (0)
289#define LOAD_6OHM (1)
290#define LOAD_4OHM (2)
291
292#define CHANNEL_LEFT (0)
293#define CHANNEL_RIGHT (1)
294
295typedef struct {
296 unsigned int mnType;
297 unsigned int mnCommands;
298 unsigned char *mpData;
299} TBlock;
300
301typedef struct {
302 char mpName[64];
303 char *mpDescription;
304 unsigned int mnBlocks;
305 TBlock *mpBlocks;
306} TData;
307
308typedef struct {
309 char mpName[64];
310 char *mpDescription;
311 unsigned char mnAppMode;
312 unsigned short mnBoost;
313 TData mData;
314} TProgram;
315
316typedef struct {
317 char mpName[64];
318 char *mpDescription;
319 TBlock mBlock;
320} TPLL;
321
322typedef struct {
323 char mpName[64];
324 char *mpDescription;
325 unsigned int mnProgram;
326 unsigned int mnPLL;
327 unsigned int mnSamplingRate;
328 TData mData;
329} TConfiguration;
330
331typedef struct
332{
333 char mpName[64];
334 char *mpDescription;
335 unsigned int mnProgram;
336 unsigned int mnConfiguration;
337 TBlock mBlock;
338} TCalibration;
339
340typedef struct {
341 unsigned int mnFWSize;
342 unsigned int mnChecksum;
343 unsigned int mnPPCVersion;
344 unsigned int mnFWVersion;
345 unsigned int mnDriverVersion;
346 unsigned int mnTimeStamp;
347 char mpDDCName[64];
348 char *mpDescription;
349 unsigned int mnDeviceFamily;
350 unsigned int mnDevice;
351 unsigned int mnPLLs;
352 TPLL *mpPLLs;
353 unsigned int mnPrograms;
354 TProgram *mpPrograms;
355 unsigned int mnConfigurations;
356 TConfiguration *mpConfigurations;
357 unsigned int mnCalibrations;
358 TCalibration *mpCalibrations;
359} TFirmware;
360
361struct tas2559_register {
362 int book;
363 int page;
364 int reg;
365};
366
367enum channel{
368 DevA = 0x01,
369 DevB = 0x02,
370 DevBoth = (DevA|DevB),
371} ;
372
373struct tas2559_priv {
374 struct device *dev;
375 struct regmap *mpRegmap;
376 struct i2c_client *client;
377 int mnResetGPIO;
378 struct mutex dev_lock;
379 TFirmware *mpFirmware;
380 TFirmware *mpCalFirmware;
381 unsigned int mnCurrentProgram;
382 unsigned int mnCurrentSampleRate;
383 unsigned int mnCurrentConfiguration;
384 unsigned int mnCurrentCalibration;
385 unsigned int mnBitRate;
386 bool mbTILoadActive;
387 bool mbPowerUp;
388 bool mbLoadConfigurationPostPowerUp;
389 bool mbLoadCalibrationPostPowerUp;
390 bool mbCalibrationLoaded;
391
392/* parameters for TAS2559 */
393 int mnDevAPGID;
394 unsigned char mnDevAAddr;
395 unsigned char mnDevAChl;
396 unsigned char mnDevALoad;
397 int mnDevACurrentBook;
398 int mnDevACurrentPage;
399
400/* parameters for TAS2560 */
401 int mnDevBPGID;
402 unsigned char mnDevBAddr;
403 unsigned char mnDevBChl;
404 unsigned char mnDevBLoad;
405 int mnDevBCurrentBook;
406 int mnDevBCurrentPage;
407
408 int (*read) (struct tas2559_priv * pTAS2559,
409 enum channel chn,
410 unsigned int reg,
411 unsigned int *pValue);
412 int (*write) (struct tas2559_priv * pTAS2559,
413 enum channel chn,
414 unsigned int reg,
415 unsigned int Value);
416 int (*bulk_read) (struct tas2559_priv * pTAS2559,
417 enum channel chn,
418 unsigned int reg,
419 unsigned char *pData,
420 unsigned int len);
421 int (*bulk_write) (struct tas2559_priv * pTAS2559,
422 enum channel chn,
423 unsigned int reg,
424 unsigned char *pData,
425 unsigned int len);
426 int (*update_bits) (struct tas2559_priv * pTAS2559,
427 enum channel chn,
428 unsigned int reg,
429 unsigned int mask,
430 unsigned int value);
431 int (*set_config) (struct tas2559_priv *pTAS2559,
432 int config);
433 int (*set_calibration) (struct tas2559_priv *pTAS2559,
434 int calibration);
435 void (*enableIRQ)(struct tas2559_priv *pTAS2559, int enable);
436
437 int mnGpioINT;
438 struct work_struct irq_work;
439 unsigned int mnIRQ;
440
441#ifdef CONFIG_TAS2559_MISC
442 int mnCurrentChannel;
443 int mnDBGCmd;
444 int mnCurrentReg;
445 struct mutex file_lock;
446#endif
447
448 //used for in-system tuning
449 void *chl_private_data;
450 void *chr_private_data;
451};
452
453#endif /* _TAS2559_H */
diff --git a/tas2560-core.c b/tas2560-core.c
new file mode 100755
index 0000000..131a176
--- /dev/null
+++ b/tas2560-core.c
@@ -0,0 +1,286 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tas2560-core.c
19**
20** Description:
21** TAS2560 common functions for Android Linux
22**
23** =============================================================================
24*/
25#define DEBUG
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/init.h>
29#include <linux/delay.h>
30#include <linux/pm.h>
31#include <linux/i2c.h>
32#include <linux/gpio.h>
33#include <linux/regulator/consumer.h>
34#include <linux/firmware.h>
35#include <linux/regmap.h>
36#include <linux/of.h>
37#include <linux/of_gpio.h>
38#include <linux/slab.h>
39
40#include "tas2560-core.h"
41#include "tas2559-core.h"
42
43#define TAS2560_MDELAY 0xFFFFFFFE
44
45static unsigned int p_tas2560_dboost_data[] = {
46 TAS2560_DR_BOOST_REG_1, 0x0c,
47 TAS2560_DR_BOOST_REG_2, 0x33,
48 0xFFFFFFFF, 0xFFFFFFFF
49};
50
51static unsigned int p_tas2560_boost_headroom_data[] =
52{
53 TAS2560_BOOST_HEAD, 0x04, 0x06, 0x66, 0x66, 0x00,
54
55 0xFFFFFFFF, 0xFFFFFFFF
56};
57
58static unsigned int p_tas2560_thermal_foldback[] =
59{
60 TAS2560_THERMAL_FOLDBACK, 0x04, 0x39, 0x80, 0x00, 0x00,
61
62 0xFFFFFFFF, 0xFFFFFFFF
63};
64
65static unsigned int p_tas2560_HPF_data[] =
66{
67 /* reg address size values */
68 /*Isense path HPF cut off -> 2Hz*/
69 TAS2560_ISENSE_PATH_CTL1, 0x04, 0x7F, 0xFB, 0xB5, 0x00,
70 TAS2560_ISENSE_PATH_CTL2, 0x04, 0x80, 0x04, 0x4C, 0x00,
71 TAS2560_ISENSE_PATH_CTL3, 0x04, 0x7F, 0xF7, 0x6A, 0x00,
72 /*all pass*/
73 TAS2560_HPF_CUTOFF_CTL1, 0x04, 0x7F, 0xFF, 0xFF, 0xFF,
74 TAS2560_HPF_CUTOFF_CTL2, 0x04, 0x00, 0x00, 0x00, 0x00,
75 TAS2560_HPF_CUTOFF_CTL3, 0x04, 0x00, 0x00, 0x00, 0x00,
76
77 0xFFFFFFFF, 0xFFFFFFFF
78};
79
80static unsigned int p_tas2560_Vsense_biquad_data[] =
81{
82 /* vsense delay in biquad = 3/8 sample @48KHz */
83 TAS2560_VSENSE_DEL_CTL1, 0x04, 0x3a, 0x46, 0x74, 0x00,
84 TAS2560_VSENSE_DEL_CTL2, 0x04, 0x22, 0xf3, 0x07, 0x00,
85 TAS2560_VSENSE_DEL_CTL3, 0x04, 0x80, 0x77, 0x61, 0x00,
86 TAS2560_VSENSE_DEL_CTL4, 0x04, 0x22, 0xa7, 0xcc, 0x00,
87 TAS2560_VSENSE_DEL_CTL5, 0x04, 0x3a, 0x0c, 0x93, 0x00,
88
89 0xFFFFFFFF, 0xFFFFFFFF
90};
91
92static unsigned int p_tas2560_4Ohm_data[] =
93{
94 /* reg address size values */
95 TAS2560_BOOST_ON, 0x04, 0x6f, 0x5c, 0x28, 0xf5,
96 TAS2560_BOOST_OFF, 0x04, 0x67, 0xae, 0x14, 0x7a,
97 TAS2560_BOOST_TABLE_CTRL1, 0x04, 0x1c, 0x00, 0x00, 0x00,
98 TAS2560_BOOST_TABLE_CTRL2, 0x04, 0x1f, 0x0a, 0x3d, 0x70,
99 TAS2560_BOOST_TABLE_CTRL3, 0x04, 0x22, 0x14, 0x7a, 0xe1,
100 TAS2560_BOOST_TABLE_CTRL4, 0x04, 0x25, 0x1e, 0xb8, 0x51,
101 TAS2560_BOOST_TABLE_CTRL5, 0x04, 0x28, 0x28, 0xf5, 0xc2,
102 TAS2560_BOOST_TABLE_CTRL6, 0x04, 0x2b, 0x33, 0x33, 0x33,
103 TAS2560_BOOST_TABLE_CTRL7, 0x04, 0x2e, 0x3d, 0x70, 0xa3,
104 TAS2560_BOOST_TABLE_CTRL8, 0x04, 0x31, 0x47, 0xae, 0x14,
105 0xFFFFFFFF, 0xFFFFFFFF
106};
107
108static unsigned int p_tas2560_6Ohm_data[] =
109{
110 /* reg address size values */
111 TAS2560_BOOST_ON, 0x04, 0x73, 0x33, 0x33, 0x33,
112 TAS2560_BOOST_OFF, 0x04, 0x6b, 0x85, 0x1e, 0xb8,
113 TAS2560_BOOST_TABLE_CTRL1, 0x04, 0x1d, 0x99, 0x99, 0x99,
114 TAS2560_BOOST_TABLE_CTRL2, 0x04, 0x20, 0xcc, 0xcc, 0xcc,
115 TAS2560_BOOST_TABLE_CTRL3, 0x04, 0x24, 0x00, 0x00, 0x00,
116 TAS2560_BOOST_TABLE_CTRL4, 0x04, 0x27, 0x33, 0x33, 0x33,
117 TAS2560_BOOST_TABLE_CTRL5, 0x04, 0x2a, 0x66, 0x66, 0x66,
118 TAS2560_BOOST_TABLE_CTRL6, 0x04, 0x2d, 0x99, 0x99, 0x99,
119 TAS2560_BOOST_TABLE_CTRL7, 0x04, 0x30, 0xcc, 0xcc, 0xcc,
120 TAS2560_BOOST_TABLE_CTRL8, 0x04, 0x34, 0x00, 0x00, 0x00,
121 0xFFFFFFFF, 0xFFFFFFFF
122};
123
124static unsigned int p_tas2560_8Ohm_data[] =
125{
126 /* reg address size values */
127 TAS2560_BOOST_ON, 0x04, 0x75, 0xC2, 0x8F, 0x00,
128 TAS2560_BOOST_OFF, 0x04, 0x6E, 0x14, 0x7A, 0x00,
129 TAS2560_BOOST_TABLE_CTRL1, 0x04, 0x1D, 0x99, 0x99, 0x00,
130 TAS2560_BOOST_TABLE_CTRL2, 0x04, 0x20, 0xcc, 0xcc, 0xcc,
131 TAS2560_BOOST_TABLE_CTRL3, 0x04, 0x24, 0x00, 0x00, 0x00,
132 TAS2560_BOOST_TABLE_CTRL4, 0x04, 0x27, 0x33, 0x33, 0x33,
133 TAS2560_BOOST_TABLE_CTRL5, 0x04, 0x2a, 0x66, 0x66, 0x66,
134 TAS2560_BOOST_TABLE_CTRL6, 0x04, 0x2d, 0x99, 0x99, 0x99,
135 TAS2560_BOOST_TABLE_CTRL7, 0x04, 0x30, 0xcc, 0xcc, 0xcc,
136 TAS2560_BOOST_TABLE_CTRL8, 0x04, 0x34, 0x00, 0x00, 0x00,
137 0xFFFFFFFF, 0xFFFFFFFF
138};
139
140int tas2559_DevB_SetLoad_Runtime(struct tas2559_priv *pTAS2559, int load)
141{
142 int ret = 0;
143
144 dev_dbg(pTAS2559->dev,"%s: %d\n",__func__, load);
145
146 switch(load){
147 case LOAD_8OHM:
148 tas2559_dev_load_blk_data(pTAS2559, DevB,p_tas2560_8Ohm_data);
149 break;
150 case LOAD_6OHM:
151 tas2559_dev_load_blk_data(pTAS2559, DevB,p_tas2560_6Ohm_data);
152 break;
153 case LOAD_4OHM:
154 tas2559_dev_load_blk_data(pTAS2559, DevB,p_tas2560_4Ohm_data);
155 break;
156 default:
157 break;
158 }
159
160 return ret;
161}
162
163int tas2559_DevB_get_volume(struct tas2559_priv *pTAS2559, unsigned int *pValue)
164{
165 int ret = -1;
166 int value = -1;
167
168 dev_dbg(pTAS2559->dev,"%s\n",__func__);
169 ret = pTAS2559->read(pTAS2559, DevB, TAS2560_SPK_CTRL_REG, &value);
170 if(ret >=0){
171 *pValue = (value&0x0f);
172 }
173
174 return ret;
175}
176
177int tas2559_DevB_set_volume(struct tas2559_priv *pTAS2559, unsigned int volume)
178{
179 int ret = -1;
180
181 dev_dbg(pTAS2559->dev,"%s\n",__func__);
182 ret = pTAS2559->update_bits(pTAS2559, DevB, TAS2560_SPK_CTRL_REG, 0x0f, volume&0x0f);
183
184 return ret;
185}
186
187int tas2559_load_DevB_Runtime(struct tas2559_priv *pTAS2559)
188{
189 int ret = 0;
190
191 ret = tas2559_dev_load_blk_data(pTAS2559, DevB, p_tas2560_HPF_data);
192
193 if (ret >= 0)
194 ret = tas2559_DevB_SetLoad_Runtime(pTAS2559, pTAS2559->mnDevBLoad);
195
196 if (ret >= 0)
197 ret = tas2559_dev_load_blk_data(pTAS2559, DevB, p_tas2560_boost_headroom_data);
198
199 if (ret >= 0)
200 ret = tas2559_dev_load_blk_data(pTAS2559, DevB, p_tas2560_thermal_foldback);
201
202 if (ret >= 0)
203 ret = tas2559_dev_load_blk_data(pTAS2559, DevB, p_tas2560_Vsense_biquad_data);
204
205 return ret;
206}
207
208int tas2559_DevB_setLoad(struct tas2559_priv *pTAS2559, int load)
209{
210 int ret = 0;
211
212 switch(load)
213 {
214 case LOAD_8OHM: //8Ohm
215 ret = pTAS2559->write(pTAS2559, DevB, TAS2560_LOAD, 0x83);
216 break;
217
218 case LOAD_6OHM: //6Ohm
219 ret = pTAS2559->write(pTAS2559, DevB, TAS2560_LOAD, 0x8b);
220 break;
221
222 case LOAD_4OHM: //4Ohm
223 ret = pTAS2559->write(pTAS2559, DevB, TAS2560_LOAD, 0x9b);
224 break;
225 }
226
227 return ret;
228}
229
230int tas2559_DevB_setChannel(struct tas2559_priv *pTAS2559, int channel)
231{
232 int ret = 0;
233 unsigned char val = 0;
234
235 switch(channel)
236 {
237 case CHANNEL_LEFT:
238 val = 0;
239 break;
240
241 case CHANNEL_RIGHT:
242 val = 1;
243 break;
244
245 default:
246 ret = -1;
247 break;
248 }
249
250 if(ret >= 0){
251 ret = pTAS2559->update_bits(pTAS2559, DevB, TAS2560_ASI_CTRL, 0x06, val);
252 }
253
254 if(ret < 0){
255 dev_err(pTAS2559->dev, "devA Channel err %d\n", channel);
256 }
257
258 return ret;
259}
260
261int tas2559_load_DevB_platdata(struct tas2559_priv *pTAS2559)
262{
263 int ret = 0;
264
265 ret = tas2559_DevB_setLoad(pTAS2559, pTAS2559->mnDevBLoad);
266 ret = tas2559_DevB_setChannel(pTAS2559, pTAS2559->mnDevBChl);
267 return ret;
268}
269
270int tas2559_load_DevB_default(struct tas2559_priv *pTAS2559)
271{
272 int ret = 0;
273
274 ret = tas2559_dev_load_blk_data(pTAS2559,
275 DevB,
276 p_tas2560_dboost_data);
277
278 if(ret >= 0)
279 ret = tas2559_load_DevB_platdata(pTAS2559);
280
281 return ret;
282}
283
284MODULE_AUTHOR("Texas Instruments Inc.");
285MODULE_DESCRIPTION("TAS2560 common functions for Android Linux");
286MODULE_LICENSE("GPLv2");
diff --git a/tas2560-core.h b/tas2560-core.h
new file mode 100755
index 0000000..415f073
--- /dev/null
+++ b/tas2560-core.h
@@ -0,0 +1,37 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tas2560-core.h
19**
20** Description:
21** header file for tas2560-core.c
22**
23** =============================================================================
24*/
25
26#ifndef _TAS2560_CORE_H
27#define _TAS2560_CORE_H
28
29#include "tas2560.h"
30#include "tas2559.h"
31
32int tas2559_load_DevB_default(struct tas2559_priv *pTAS2559);
33int tas2559_load_DevB_Runtime(struct tas2559_priv *pTAS2559);
34int tas2559_DevB_get_volume(struct tas2559_priv *pTAS2559, unsigned int *pValue);
35int tas2559_DevB_set_volume(struct tas2559_priv *pTAS2559, unsigned int volume);
36
37#endif /* _TAS2560_CORE_H */
diff --git a/tas2560.h b/tas2560.h
new file mode 100755
index 0000000..ef31741
--- /dev/null
+++ b/tas2560.h
@@ -0,0 +1,125 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tas2560.h
19**
20** Description:
21** definitions and data structures for TAS2560 Android Linux driver
22**
23** =============================================================================
24*/
25
26#ifndef _TAS2560_H
27#define _TAS2560_H
28
29/* Page Control Register */
30#define TAS2560_PAGECTL_REG 0
31
32/* Book Control Register (available in page0 of each book) */
33#define TAS2560_BOOKCTL_PAGE 0
34#define TAS2560_BOOKCTL_REG 127
35
36#define TAS2560_REG(book, page, reg) (((book * 256 * 128) + \
37 (page * 128)) + reg)
38
39#define TAS2560_BOOK_ID(reg) (reg / (256 * 128))
40#define TAS2560_PAGE_ID(reg) ((reg % (256 * 128)) / 128)
41#define TAS2560_BOOK_REG(reg) (reg % (256 * 128))
42#define TAS2560_PAGE_REG(reg) ((reg % (256 * 128)) % 128)
43
44/* Book0, Page0 registers */
45#define TAS2560_SW_RESET_REG TAS2560_REG(0, 0, 1)
46#define TAS2560_DEV_MODE_REG TAS2560_REG(0, 0, 2)
47#define TAS2560_SPK_CTRL_REG TAS2560_REG(0, 0, 4)
48#define TAS2560_MUTE_REG TAS2560_REG(0, 0, 7)
49#define TAS2560_PWR_REG TAS2560_REG(0, 0, 7)
50#define TAS2560_PWR_BIT_MASK (0x3 << 6)
51#define TAS2560_MUTE_MASK (0x7)
52
53#define TAS2560_SR_CTRL1 TAS2560_REG(0, 0, 8)
54#define TAS2560_LOAD TAS2560_REG(0, 0, 9)
55#define TAS2560_SR_CTRL2 TAS2560_REG(0, 0, 13)
56#define TAS2560_SR_CTRL3 TAS2560_REG(0, 0, 14)
57
58#define TAS2560_CLK_SEL TAS2560_REG(0, 0, 15)
59#define TAS2560_PLL_SRC_MASK (0xc0)
60#define TAS2560_PLL_CLKIN_BCLK (0)
61#define TAS2560_PLL_CLKIN_MCLK (1)
62#define TAS2560_PLL_CLKIN_PDMCLK (2)
63#define TAS2560_PLL_P_MASK (0x3f)
64
65#define TAS2560_SET_FREQ TAS2560_REG(0, 0, 16)
66#define TAS2560_PLL_J_MASK (0x7f)
67
68#define TAS2560_PLL_D_LSB TAS2560_REG(0, 0, 17)
69#define TAS2560_PLL_D_MSB TAS2560_REG(0, 0, 18)
70
71#define TAS2560_DAI_FMT TAS2560_REG(0, 0, 20)
72#define TAS2560_ASI_CTRL TAS2560_REG(0, 0, 21)
73#define TAS2560_ASI_OFFSET_1 TAS2560_REG(0, 0, 22)
74#define TAS2560_ASI_CFG_1 TAS2560_REG(0, 0, 24)
75#define TAS2560_DIRINV_MASK 0x3c
76#define TAS2560_BCLKINV (1 << 2)
77#define TAS2560_WCLKINV (1 << 3)
78#define TAS2560_BCLKDIR (1 << 4)
79#define TAS2560_WCLKDIR (1 << 5)
80
81#define TAS2560_DR_BOOST_REG_2 TAS2560_REG(0, 0, 60)
82#define TAS2560_DR_BOOST_REG_1 TAS2560_REG(0, 0, 73)
83#define TAS2560_ID_REG TAS2560_REG(0, 0, 125)
84
85/* Book0, Page50 registers */
86#define TAS2560_HPF_CUTOFF_CTL1 TAS2560_REG(0,50, 28)
87#define TAS2560_HPF_CUTOFF_CTL2 TAS2560_REG(0,50, 32)
88#define TAS2560_HPF_CUTOFF_CTL3 TAS2560_REG(0,50, 36)
89
90#define TAS2560_ISENSE_PATH_CTL1 TAS2560_REG(0,50, 40)
91#define TAS2560_ISENSE_PATH_CTL2 TAS2560_REG(0,50, 44)
92#define TAS2560_ISENSE_PATH_CTL3 TAS2560_REG(0,50, 48)
93
94#define TAS2560_VLIMIT_THRESHOLD TAS2560_REG(0,50, 60)
95
96/* Book0, Page51 registers */
97#define TAS2560_BOOST_HEAD TAS2560_REG(0,51, 24)
98#define TAS2560_BOOST_ON TAS2560_REG(0,51, 16)
99#define TAS2560_BOOST_OFF TAS2560_REG(0,51, 20)
100#define TAS2560_BOOST_TABLE_CTRL1 TAS2560_REG(0,51, 32)
101#define TAS2560_BOOST_TABLE_CTRL2 TAS2560_REG(0,51, 36)
102#define TAS2560_BOOST_TABLE_CTRL3 TAS2560_REG(0,51, 40)
103#define TAS2560_BOOST_TABLE_CTRL4 TAS2560_REG(0,51, 44)
104#define TAS2560_BOOST_TABLE_CTRL5 TAS2560_REG(0,51, 48)
105#define TAS2560_BOOST_TABLE_CTRL6 TAS2560_REG(0,51, 52)
106#define TAS2560_BOOST_TABLE_CTRL7 TAS2560_REG(0,51, 56)
107#define TAS2560_BOOST_TABLE_CTRL8 TAS2560_REG(0,51, 60)
108#define TAS2560_THERMAL_FOLDBACK TAS2560_REG(0,51, 100)
109
110/* Book0, Page52 registers */
111#define TAS2560_VSENSE_DEL_CTL1 TAS2560_REG(0,52, 52)
112#define TAS2560_VSENSE_DEL_CTL2 TAS2560_REG(0,52, 56)
113#define TAS2560_VSENSE_DEL_CTL3 TAS2560_REG(0,52, 60)
114#define TAS2560_VSENSE_DEL_CTL4 TAS2560_REG(0,52, 64)
115#define TAS2560_VSENSE_DEL_CTL5 TAS2560_REG(0,52, 68)
116
117#define TAS2560_DATAFORMAT_I2S (0x0 << 2)
118#define TAS2560_DATAFORMAT_DSP (0x1 << 2)
119#define TAS2560_DATAFORMAT_RIGHT_J (0x2 << 2)
120#define TAS2560_DATAFORMAT_LEFT_J (0x3 << 2)
121
122#define TAS2560_DAI_FMT_MASK (0x7 << 2)
123#define LOAD_MASK 0x18
124
125#endif
diff --git a/tiload.c b/tiload.c
new file mode 100755
index 0000000..7eadd98
--- /dev/null
+++ b/tiload.c
@@ -0,0 +1,360 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tiload.c
19**
20** Description:
21** utility for TAS2559 Android in-system tuning
22**
23** =============================================================================
24*/
25/* enable debug prints in the driver */
26#define DEBUG
27
28#include <linux/module.h>
29#include <linux/moduleparam.h>
30#include <linux/init.h>
31#include <linux/kernel.h>
32#include <linux/fs.h>
33#include <linux/types.h>
34#include <linux/kdev_t.h>
35#include <linux/cdev.h>
36#include <linux/device.h>
37#include <asm/io.h>
38#include <linux/slab.h>
39#include <linux/delay.h>
40#include <linux/i2c.h>
41#include <linux/platform_device.h>
42#include <asm/uaccess.h>
43
44#include "tiload.h"
45/* Function prototypes */
46
47/* externs */
48static struct cdev *tiload_cdev;
49static int tiload_major = 0; /* Dynamic allocation of Mjr No. */
50static int tiload_opened = 0; /* Dynamic allocation of Mjr No. */
51static struct tas2559_priv *g_TAS2559;
52struct class *tiload_class;
53static unsigned int magic_num = 0x00;
54//static char gDev = 0;
55static char gPage = 0;
56static char gBook = 0;
57/******************************** Debug section *****************************/
58
59/*
60 *----------------------------------------------------------------------------
61 * Function : tiload_open
62 *
63 * Purpose : open method for tiload programming interface
64 *----------------------------------------------------------------------------
65 */
66static int tiload_open(struct inode *in, struct file *filp)
67{
68 struct tas2559_priv *pTAS2559 = g_TAS2559;
69
70 dev_info(pTAS2559->dev, "%s\n", __FUNCTION__);
71
72 if (tiload_opened) {
73 printk("%s device is already opened\n", "tiload");
74 printk("%s: only one instance of driver is allowed\n", "tiload");
75 return -1;
76 }
77 tiload_opened++;
78 return 0;
79}
80
81/*
82 *----------------------------------------------------------------------------
83 * Function : tiload_release
84 *
85 * Purpose : close method for tiload programming interface
86 *----------------------------------------------------------------------------
87 */
88static int tiload_release(struct inode *in, struct file *filp)
89{
90 struct tas2559_priv *pTAS2559 = (struct tas2559_priv *)filp->private_data;
91
92 dev_info(pTAS2559->dev, "%s\n", __FUNCTION__);
93 tiload_opened--;
94 return 0;
95}
96
97/*
98 *----------------------------------------------------------------------------
99 * Function : tiload_read
100 *
101 * Purpose : read from codec
102 *----------------------------------------------------------------------------
103 */
104static ssize_t tiload_read(struct file *filp, char __user * buf,
105 size_t count, loff_t * offset)
106{
107 struct tas2559_priv *pTAS2559 = (struct tas2559_priv *)filp->private_data;
108 static char rd_data[MAX_LENGTH + 1];
109 unsigned int nCompositeRegister = 0, Value;
110 //unsigned int n;
111 char reg_addr;
112 size_t size;
113 int ret = 0;
114
115 dev_dbg(pTAS2559->dev, "%s\n", __FUNCTION__);
116
117 if (count > MAX_LENGTH) {
118 dev_err(pTAS2559->dev, "Max %d bytes can be read\n", MAX_LENGTH);
119 return -1;
120 }
121
122 /* copy register address from user space */
123 size = copy_from_user(&reg_addr, buf, 1);
124 if (size != 0) {
125 dev_err(pTAS2559->dev, "read: copy_from_user failure\n");
126 return -1;
127 }
128
129 size = count;
130
131 nCompositeRegister = BPR_REG(gBook, gPage, reg_addr);
132 if (count == 1) {
133 ret = pTAS2559->read(pTAS2559,
134 DevA,
135 0x80000000 | nCompositeRegister, &Value);
136 if (ret >= 0)
137 rd_data[0] = (char) Value;
138 } else if (count > 1) {
139 ret = pTAS2559->bulk_read(pTAS2559,
140 DevA,
141 0x80000000 | nCompositeRegister,
142 rd_data, size);
143 }
144 if (ret < 0)
145 dev_err(pTAS2559->dev,
146 "%s, %d, ret=%d, count=%zu error happen!\n",
147 __FUNCTION__, __LINE__, ret, count);
148
149#ifdef DEBUG
150 dev_dbg(pTAS2559->dev,
151 "read size = %d, reg_addr= 0x%x , count = %d\n",
152 (int) size, reg_addr, (int) count);
153#endif
154 if (size != count) {
155 dev_err(pTAS2559->dev,
156 "read %d registers from the codec\n", (int) size);
157 }
158
159 if (copy_to_user(buf, rd_data, size) != 0) {
160 dev_err(pTAS2559->dev, "copy_to_user failed\n");
161 return -1;
162 }
163
164 return size;
165}
166
167/*
168 *----------------------------------------------------------------------------
169 * Function : tiload_write
170 *
171 * Purpose : write to codec
172 *----------------------------------------------------------------------------
173 */
174static ssize_t tiload_write(struct file *filp, const char __user * buf,
175 size_t count, loff_t * offset)
176{
177 struct tas2559_priv *pTAS2559 = (struct tas2559_priv *)filp->private_data;
178 static char wr_data[MAX_LENGTH + 1];
179 char *pData = wr_data;
180 size_t size;
181 unsigned int nCompositeRegister = 0;
182 unsigned int nRegister;
183 int ret = 0;
184
185 dev_info(pTAS2559->dev, "%s\n", __FUNCTION__);
186
187
188 if (count > MAX_LENGTH) {
189 dev_err(pTAS2559->dev,"Max %d bytes can be read\n", MAX_LENGTH);
190 return -1;
191 }
192
193
194 /* copy buffer from user space */
195 size = copy_from_user(wr_data, buf, count);
196 if (size != 0) {
197 dev_err(pTAS2559->dev,
198 "copy_from_user failure %d\n", (int) size);
199 return -1;
200 }
201#ifdef DEBUG
202 dev_dbg(pTAS2559->dev, "write size = %zu\n", count);
203#endif
204 nRegister = wr_data[0];
205 size = count;
206 if ((nRegister == 127) && (gPage == 0)) {
207 gBook = wr_data[1];
208 return size;
209 }
210
211 if (nRegister == 0) {
212 gPage = wr_data[1];
213 pData++;
214 count--;
215 }
216#if 1
217 nCompositeRegister = BPR_REG(gBook, gPage, nRegister);
218 if (count == 2) {
219 ret =
220 pTAS2559->write(pTAS2559, DevA, 0x80000000 | nCompositeRegister,
221 pData[1]);
222 } else if (count > 2) {
223 ret =
224 pTAS2559->bulk_write(pTAS2559, DevA, 0x80000000 | nCompositeRegister,
225 &pData[1], count - 1);
226 }
227 if (ret < 0)
228 printk("%s, %d, ret=%d, count=%zu, ERROR Happen\n", __FUNCTION__,
229 __LINE__, ret, count);
230#else
231 for (n = 1; n < count; n++) {
232 nCompositeRegister = BPR_REG(gBook, gPage, nRegister + n - 1);
233 g_codec->driver->write(g_codec, 0x80000000 | nCompositeRegister,
234 pData[n]);
235 }
236#endif
237
238 return size;
239}
240
241static void tiload_route_IO(struct tas2559_priv *pTAS2559,
242 unsigned int bLock)
243{
244 if (bLock) {
245 pTAS2559->write(pTAS2559,
246 DevA,
247 0xAFFEAFFE, 0xBABEBABE);
248 } else {
249 pTAS2559->write(pTAS2559,
250 DevA,
251 0xBABEBABE, 0xAFFEAFFE);
252 }
253}
254
255static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
256{
257 long num = 0;
258 struct tas2559_priv *pTAS2559 = (struct tas2559_priv *)filp->private_data;
259 void __user *argp = (void __user *) arg;
260 int val;
261 BPR bpr;
262
263 dev_info(pTAS2559->dev, "%s, cmd=0x%x\n", __FUNCTION__, cmd);
264// if (_IOC_TYPE(cmd) != TILOAD_IOC_MAGIC)
265// return -ENOTTY;
266
267
268 switch (cmd) {
269 case TILOAD_IOMAGICNUM_GET:
270 num = copy_to_user(argp, &magic_num, sizeof(int));
271 break;
272 case TILOAD_IOMAGICNUM_SET:
273 num = copy_from_user(&magic_num, argp, sizeof(int));
274 tiload_route_IO(pTAS2559, magic_num);
275 break;
276 case TILOAD_BPR_READ:
277 break;
278 case TILOAD_BPR_WRITE:
279 num = copy_from_user(&bpr, argp, sizeof(BPR));
280 dev_dbg(pTAS2559->dev,
281 "TILOAD_BPR_WRITE: 0x%02X, 0x%02X, 0x%02X\n\r", bpr.nBook,
282 bpr.nPage, bpr.nRegister);
283 break;
284 case TILOAD_IOCTL_SET_CONFIG:
285 num = copy_from_user(&val, argp, sizeof(val));
286 pTAS2559->set_config(pTAS2559, val);
287 break;
288 case TILOAD_IOCTL_SET_CALIBRATION:
289 num = copy_from_user(&val, argp, sizeof(val));
290 pTAS2559->set_calibration(pTAS2559, val);
291 break;
292 default:
293 break;
294 }
295 return num;
296}
297
298/*********** File operations structure for tiload *************/
299static struct file_operations tiload_fops = {
300 .owner = THIS_MODULE,
301 .open = tiload_open,
302 .release = tiload_release,
303 .read = tiload_read,
304 .write = tiload_write,
305 .unlocked_ioctl = tiload_ioctl,
306};
307
308/*
309 *----------------------------------------------------------------------------
310 * Function : tiload_driver_init
311 *
312 * Purpose : Register a char driver for dynamic tiload programming
313 *----------------------------------------------------------------------------
314 */
315int tiload_driver_init(struct tas2559_priv *pTAS2559)
316{
317 int result;
318
319 dev_t dev = MKDEV(tiload_major, 0);
320 g_TAS2559 = pTAS2559;
321
322
323 result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
324 if (result < 0) {
325 dev_err(pTAS2559->dev,
326 "cannot allocate major number %d\n", tiload_major);
327 return result;
328 }
329 tiload_class = class_create(THIS_MODULE, DEVICE_NAME);
330 tiload_major = MAJOR(dev);
331 dev_info(pTAS2559->dev,
332 "allocated Major Number: %d\n", tiload_major);
333
334 tiload_cdev = cdev_alloc();
335 cdev_init(tiload_cdev, &tiload_fops);
336 tiload_cdev->owner = THIS_MODULE;
337 tiload_cdev->ops = &tiload_fops;
338
339 if (device_create(tiload_class, NULL, dev, NULL, "tiload_node") == NULL)
340 dev_err(pTAS2559->dev,
341 "Device creation failed\n");
342
343 if (cdev_add(tiload_cdev, dev, 1) < 0) {
344 dev_err(pTAS2559->dev,
345 "tiload_driver: cdev_add failed \n");
346 unregister_chrdev_region(dev, 1);
347 tiload_cdev = NULL;
348 return 1;
349 }
350
351 dev_info(pTAS2559->dev,
352 "Registered TiLoad driver, Major number: %d \n", tiload_major);
353
354 return 0;
355}
356
357MODULE_AUTHOR("Texas Instruments Inc.");
358MODULE_DESCRIPTION("Utility for TAS2559 Android in-system tuning");
359MODULE_LICENSE("GPLv2");
360//#endif
diff --git a/tiload.h b/tiload.h
new file mode 100755
index 0000000..82e7550
--- /dev/null
+++ b/tiload.h
@@ -0,0 +1,57 @@
1/*
2** =============================================================================
3** Copyright (c) 2016 Texas Instruments Inc.
4**
5** This program is free software; you can redistribute it and/or modify it under
6** the terms of the GNU General Public License as published by the Free Software
7** Foundation; version 2.
8**
9** This program is distributed in the hope that it will be useful, but WITHOUT
10** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12**
13** You should have received a copy of the GNU General Public License along with
14** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16**
17** File:
18** tiload.h
19**
20** Description:
21** header file for tiload.c
22**
23** =============================================================================
24*/
25
26#ifndef _TILOAD_H
27#define _TILOAD_H
28
29#include "tas2559.h"
30
31#define MAX_LENGTH 128
32
33#define BPR_REG(book, page, reg) (((book * 256 * 128) + \
34 (page * 128)) + reg)
35
36/* typedefs required for the included header files */
37typedef char *string;
38
39typedef struct {
40 unsigned char nBook;
41 unsigned char nPage;
42 unsigned char nRegister;
43} BPR;
44
45/* defines */
46#define DEVICE_NAME "tiload_node"
47#define TILOAD_IOC_MAGIC 0xE0
48#define TILOAD_IOMAGICNUM_GET _IOR(TILOAD_IOC_MAGIC, 1, int)
49#define TILOAD_IOMAGICNUM_SET _IOW(TILOAD_IOC_MAGIC, 2, int)
50#define TILOAD_BPR_READ _IOR(TILOAD_IOC_MAGIC, 3, BPR)
51#define TILOAD_BPR_WRITE _IOW(TILOAD_IOC_MAGIC, 4, BPR)
52#define TILOAD_IOCTL_SET_CONFIG _IOW(TILOAD_IOC_MAGIC, 5, int)
53#define TILOAD_IOCTL_SET_CALIBRATION _IOW(TILOAD_IOC_MAGIC, 6, int)
54
55int tiload_driver_init(struct tas2559_priv *pTAS2559);
56
57#endif