update to version v1.0.0.2 : add "restore original state after FTC"
[tas2557sw-android/tas2557dm-ftc.git] / tas2557.c
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 **     tas2555.c
19 **
20 ** Description:
21 **     functions for configurating TAS2555 Android device
22 **
23 ** =============================================================================
24 */
26 #include "tas2557.h"
27 #include "system.h"
29 #include <sys/types.h>
30 #include <stdio.h>
31 #include <time.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <sys/ioctl.h>
37 #include <string.h>
39 #define TILOAD_NODE "/dev/tiload_node"
41 static int gTILoad = 0;
42 static int gBinFile = 0;
44 #define MAX_BIN_SIZE 2048
45 static char gpBin[MAX_BIN_SIZE];
46 static unsigned int gnBinIndex = 0;
47 static unsigned int gnBinBlockIndex = 0;
48 static char gpDevABlock[MAX_BIN_SIZE/2];
49 static unsigned int gnDevABlockIndex = 0;
50 static char gpDevBBlock[MAX_BIN_SIZE/2];
51 static unsigned int gnDevBBlockIndex = 0;
52 static unsigned char gnDevA;
53 static unsigned char gnDevB;
54 static unsigned char gnDev;
56 static void tas2557_check_node(void);
58 void tas2557_mixer_command(char *pCommand, int nData)
59 {
60         char *pMixer[] = {AUDIO_MIXER, pCommand, "0", NULL};
61         char *pEnv[] = {NULL};
63         char pData[16];
65         printf("TAS2557 mixer command %s = %d.\n\r", pCommand, nData);
67         sprintf(pData, "%d", nData);
68         pMixer[2] = pData;
69         
70         if (0 == (fork()))
71         {
72                 if (execve(AUDIO_MIXER, pMixer, pEnv) == -1)
73                 {
74                         printf("factorytest: Can't find mixer. Please install %s. \n\r", AUDIO_MIXER);
75                         exit(-1);
76                 }
77         }
79         sys_delay(500);
80 }
82 void tas2557_load_calibration(int nCalibration)
83 {
84         tas2557_check_node();
85         
86         ioctl(gTILoad, TILOAD_IOCTL_SET_CALIBRATION, &nCalibration);
87         sys_delay(500);
88 }
90 static void tas2557_check_node(void)
91 {
92         if (gTILoad) return;
94         gTILoad = open(TILOAD_NODE, O_RDWR);
96         if (gTILoad < 0)
97         {
98                 printf("factorytest: Can't find tiload. Please create %s. \n\r", TILOAD_NODE);
99                 exit(-1);
100         }
102         printf("factorytest: %s handle = %d\n\r", TILOAD_NODE, gTILoad);
105 uint8_t tas2557_get_PGID(void)
107         unsigned char pPageZero[] = {0x00, 0x00};
108         unsigned char pBook[] = {0x7F, 0x00};
109         unsigned char pPage[] = {0x00, 0x00};
110         unsigned char pData[] = {0x03, 0x00, 0x00, 0x00, 0x00};
112         tas2557_check_node();
114         write(gTILoad, pPageZero, 2);
115         write(gTILoad, pBook, 2);
116         write(gTILoad, pPage, 2);
117         read(gTILoad, pData, 1);
119         return pData[0];
122 uint32_t tas2557_coeff_read(uint32_t reg)
124         uint8_t nbook = TAS2557_BOOK_ID(reg);
125         uint8_t npage = TAS2557_PAGE_ID(reg);
126         uint8_t nreg = TAS2557_PAGE_REG(reg);
127         unsigned char pPageZero[] = {0x00, 0x00};
128         unsigned char pBook[] = {0x7F, nbook};
129         unsigned char pPage[] = {0x00, npage};
130         unsigned char pData[] = {nreg, 0x00, 0x00, 0x00, 0x00};
132         tas2557_check_node();
134         write(gTILoad, pPageZero, 2);
135         write(gTILoad, pBook, 2);
136         write(gTILoad, pPage, 2);
137         read(gTILoad, pData, 4);
139         return ((pData[0] << 24) | (pData[1] << 16) | (pData[2] << 8) | (pData[3]));
142 uint32_t tas2557_switch_device(uint8_t i2cslave)
144         int addr = i2cslave;
145         
146         tas2557_check_node();
148         gnDev = i2cslave;
149         
150         ioctl(gTILoad, TILOAD_IOCTL_SET_CHL, &addr);
151         
152         return 0;
155 #define TAS2557_mCDSP_SWAP_REG  TAS2557_REG(0x8c, 0x19, 0x7c)
156 #define TAS2557_uCDSP_SWAP_REG  TAS2557_REG(0x00, 0x35, 0x2c)
158 void tas2557_coeff_write(uint32_t reg, uint32_t data)
160         unsigned int nByte;
161         uint8_t nbook, npage, nreg;
163         nbook = TAS2557_BOOK_ID(reg);
164         npage = TAS2557_PAGE_ID(reg);
165         nreg = TAS2557_PAGE_REG(reg);
167         // if the bin file is open, write the coefficients to the bin file
168         if (gBinFile) {
169                 if (gnDev == gnDevA) {
170                         unsigned int index = gnDevABlockIndex*4;
172                         gpDevABlock[index] = 0;
173                         gpDevABlock[index + 1] = 4;
174                         gpDevABlock[index + 2] = 0x85;
175                         gpDevABlock[index + 4] = nbook;
176                         gpDevABlock[index + 5] = npage;
177                         gpDevABlock[index + 6] = nreg;
179                         for (nByte = 0; nByte < 4; nByte++)
180                                 gpDevABlock[index + 7 + nByte] = (data >> ((3 - nByte) * 8)) & 0xFF;
182                         gnDevABlockIndex += 3;
183                 } else if (gnDev == gnDevB) {
184                         unsigned int index = gnDevBBlockIndex*4;
186                         gpDevBBlock[index] = 0;
187                         gpDevBBlock[index + 1] = 4;
188                         gpDevBBlock[index + 2] = 0x85;
189                         gpDevBBlock[index + 4] = nbook;
190                         gpDevBBlock[index + 5] = npage;
191                         gpDevBBlock[index + 6] = nreg;
193                         for (nByte = 0; nByte < 4; nByte++)
194                                 gpDevBBlock[index + 7 + nByte] = (data >> ((3 - nByte) * 8)) & 0xFF;
196                         gnDevBBlockIndex += 3;
197                 }
198         } else {
199                 unsigned char pPageZero[] = {0x00, 0x00};
200                 unsigned char pBook[] = {0x7F, nbook};
201                 unsigned char pPage[] = {0x00, npage};
202                 unsigned char pData[] = {nreg, (data & 0xFF000000) >> 24, (data & 0x00FF0000) >> 16, (data & 0x0000FF00) >> 8, data & 0x000000FF};
204                 tas2557_check_node();
206                 write(gTILoad, pPageZero, 2);
207                 write(gTILoad, pBook, 2);
208                 write(gTILoad, pPage, 2);
209                 write(gTILoad, pData, 5);
211                 pBook[1] = TAS2557_BOOK_ID(TAS2557_mCDSP_SWAP_REG);
212                 pPage[1] = TAS2557_PAGE_ID(TAS2557_mCDSP_SWAP_REG);
214                 pData[0] = TAS2557_PAGE_REG(TAS2557_mCDSP_SWAP_REG);
215                 pData[1] = 0x00;
216                 pData[2] = 0x00;
217                 pData[3] = 0x00;
218                 pData[4] = 0x01;
220                 write(gTILoad, pPageZero, 2);
221                 write(gTILoad, pBook, 2);
222                 write(gTILoad, pPage, 2);
223                 write(gTILoad, pData, 5);
225                 pBook[1] = TAS2557_BOOK_ID(TAS2557_uCDSP_SWAP_REG);;
226                 pPage[1] = TAS2557_PAGE_ID(TAS2557_uCDSP_SWAP_REG);
228                 pData[0] = TAS2557_PAGE_REG(TAS2557_uCDSP_SWAP_REG);
229                 pData[1] = 0x00;
230                 pData[2] = 0x00;
231                 pData[3] = 0x00;
232                 pData[4] = 0x01;
234                 write(gTILoad, pPageZero, 2);
235                 write(gTILoad, pBook, 2);
236                 write(gTILoad, pPage, 2);
237                 write(gTILoad, pData, 5);
238         }
241 void tas2557_save_cal(struct TFTCConfiguration *pFTCC, 
242         double dev_a_re, uint32_t dev_a_rms_pow, uint32_t dev_a_t_limit, 
243         double dev_b_re, uint32_t dev_b_rms_pow, uint32_t dev_b_t_limit, 
244         double t_cal,  uint32_t nResult, char * pFileName)
246         printf("TAS2557 calibration values:\n\r");
247         printf("    DevA Re = %1.2f Ohm\n\r", dev_a_re);
248         printf("    DevA rms_pow       = 0x%08X\n\r", dev_a_rms_pow);
249         printf("    DevA t_limit       = 0x%08X\n\r", dev_a_t_limit);
250         printf("    DevB Re = %1.2f Ohm\n\r", dev_b_re);
251         printf("    DevB rms_pow       = 0x%08X\n\r", dev_b_rms_pow);
252         printf("    DevB t_limit       = 0x%08X\n\r", dev_b_t_limit);
254         if((nResult & RE1_CHK_MSK) == RESULT_PASS)
255                 printf(" SPK A calibration success! \n\r");
256         else {
257                 if(nResult & RE1_FAIL_HI)
258                         printf(" SPK A Calibration fail : Re is too high (limit: %1.2f).\n\r", pFTCC->nTSpkCharDevA.nReHi);
259                 else
260                         printf(" SPK A Calibration fail : Re is too low (limit: %1.2f).\n\r", pFTCC->nTSpkCharDevA.nReLo);
261         }
262         
263         if((nResult & RE2_CHK_MSK) == RESULT_PASS){
264                 printf(" SPK B calibration success! \n\r");
265         }else {
266                 if(nResult & RE2_FAIL_HI)
267                         printf(" SPK B Calibration fail : Re is too high (limit: %1.2f).\n\r", pFTCC->nTSpkCharDevB.nReHi);
268                 else
269                         printf(" SPK B Calibration fail : Re is too low (limit: %1.2f).\n\r", pFTCC->nTSpkCharDevB.nReLo);
270         }
271         
272         FILE *pFile = fopen(pFileName, "w+");
273         
274         fprintf(pFile, "DevA Re = %1.2f\n\r", dev_a_re);
275         fprintf(pFile, "DevA rms_pow       = 0x%08X\n\r", dev_a_rms_pow);
276         fprintf(pFile, "DevA t_limit       = 0x%08X\n\r", dev_a_t_limit);
277         fprintf(pFile, "DevB Re = %1.2f\n\r", dev_b_re);
278         fprintf(pFile, "DevB rms_pow       = 0x%08X\n\r", dev_b_rms_pow);
279         fprintf(pFile, "DevB t_limit       = 0x%08X\n\r", dev_b_t_limit);       
280         fprintf(pFile, "Ambient temperature = %2.2f\n\r\n\r", t_cal);
281         fprintf(pFile, "Result = 0x%x\n\r\n\r", nResult);
283         fclose(pFile);
286 #define DDC_DESCRIPTION "Calibration Data File for TAS2557 Dual Mono"
287 #define CALIBRATION_DESCRIPTION "Calibration snapshot for TAS2557 Dual Mono"
288 #define DATA_DESCRIPTION "data blocks for TAS2557 Dual Mono FTCc"
290 void tas2557_open_bin(char * pFileName, unsigned char dev_a, unsigned char dev_b)
292         time_t timestamp; 
293         
294         gnDevA = dev_a;
295         gnDevB = dev_b;
296         
297         gBinFile = open(pFileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH);
299         gnBinIndex = 0;
300         memset(gpBin, 0, MAX_BIN_SIZE);
301         memset(gpDevABlock, 0, MAX_BIN_SIZE/2);
302         gnDevABlockIndex = 0;
303         memset(gpDevBBlock, 0, MAX_BIN_SIZE/2);
304         gnDevBBlockIndex = 0;
306         //magic number
307         gpBin[gnBinIndex++] = '5';
308         gpBin[gnBinIndex++] = '5';
309         gpBin[gnBinIndex++] = '5';
310         gpBin[gnBinIndex++] = '2';
312         gnBinIndex += 4;        /* bypass size int */
313         gnBinIndex += 4;        /* bypass checksum int */
314         gnBinIndex += 4;        /* bypass PPC3 version int */
315         gnBinIndex += 4;        /* bypass DSP version int */
317         gpBin[gnBinIndex++] = 0;
318         gpBin[gnBinIndex++] = 0;
319         gpBin[gnBinIndex++] = 1;
320         gpBin[gnBinIndex++] = 0; /* driver version 0x00000100 */
322         time(&timestamp);
323         gpBin[gnBinIndex++] = (unsigned char)((timestamp&0xff000000)>>24);
324         gpBin[gnBinIndex++] = (unsigned char)((timestamp&0x00ff0000)>>16);;
325         gpBin[gnBinIndex++] = (unsigned char)((timestamp&0x0000ff00)>>8);;
326         gpBin[gnBinIndex++] = (unsigned char)((timestamp&0x000000ff));;
328         strcpy(&gpBin[gnBinIndex], "Calibration Data File");    /* DDC name */
329         gnBinIndex += 64;
331         strcpy(&gpBin[gnBinIndex], DDC_DESCRIPTION);
332         gnBinIndex += strlen(DDC_DESCRIPTION) + 1;
334         gnBinIndex += 4; /* device family index */
336         gpBin[gnBinIndex++] = 0; /* device index */
337         gpBin[gnBinIndex++] = 0; /* device index */
338         gpBin[gnBinIndex++] = 0; /* device index */
339         gpBin[gnBinIndex++] = 3; //device index, TAS2557 Dual Mono
341         gnBinIndex +=
342                 2 +     /* num PLL index */
343                 0 +     /* array PLL index */
344                 2 +     /* num programs index */
345                 0 +     /* array programs index */
346                 2 +     /* num configurations index */
347                 0;      /* array configurations index */
349         gpBin[gnBinIndex++] = 0x00;
350         gpBin[gnBinIndex++] = 0x01; /* one calibration data block */
352         strcpy(&gpBin[gnBinIndex], "Calibration snapshot");
353         gnBinIndex += 64;
354         strcpy(&gpBin[gnBinIndex], CALIBRATION_DESCRIPTION);
355         gnBinIndex += strlen(CALIBRATION_DESCRIPTION) + 1;
357         gpBin[gnBinIndex++] = 0x00; /* compatible program = smart amp (index 0) */
358         gpBin[gnBinIndex++] = 0x00; /* compatible configuration */
360         strcpy(&gpBin[gnBinIndex], "Calibration Data");
361         gnBinIndex += 64;
362         strcpy(&gpBin[gnBinIndex], DATA_DESCRIPTION);
363         gnBinIndex += strlen(DATA_DESCRIPTION) + 1;
365         gpBin[gnBinIndex++] = 0x00; 
366         gpBin[gnBinIndex++] = 2;        // two blocks
368         gpDevABlock[0] = 0;
369         gpDevABlock[1] = 0;
370         gpDevABlock[2] = 0;
371         gpDevABlock[3] = 0x03;  /* COEFF_DEVICE_A – 0x03 */
372         gnDevABlockIndex = 2;
373         
374         gpDevBBlock[0] = 0;
375         gpDevBBlock[1] = 0;
376         gpDevBBlock[2] = 0;
377         gpDevBBlock[3] = 0x0a;  //o     COEFF_DEVICE_B – 0x0a
378         gnDevBBlockIndex = 2;
381 void tas2557_close_bin(void)
383         unsigned int nCommands;
384         unsigned char pCommit[] = {
385                 0x00, 0x04, 0x85, 0x00,
386                 TAS2557_BOOK_ID(TAS2557_mCDSP_SWAP_REG), TAS2557_PAGE_ID(TAS2557_mCDSP_SWAP_REG), TAS2557_PAGE_REG(TAS2557_mCDSP_SWAP_REG), 0x00,
387                 0x00, 0x00, 0x01, 0x00,
388                 0x00, 0x04, 0x85, 0x00,
389                 TAS2557_BOOK_ID(TAS2557_uCDSP_SWAP_REG), TAS2557_PAGE_ID(TAS2557_uCDSP_SWAP_REG), TAS2557_PAGE_REG(TAS2557_uCDSP_SWAP_REG), 0x00,
390                 0x00, 0x00, 0x01, 0x00
391         };
393         /* write the commit sequence */
394         memcpy(&gpDevABlock[gnDevABlockIndex*4], pCommit, 24);
395         gnDevABlockIndex += 6;
396         
397         memcpy(&gpDevBBlock[gnDevBBlockIndex*4], pCommit, 24);
398         gnDevBBlockIndex += 6;
399         
400         /* write number of commands for calibration block */
401         gpDevABlock[4] = ((gnDevABlockIndex-2) & 0xFF000000) >> 24;
402         gpDevABlock[5] = ((gnDevABlockIndex-2) & 0x00FF0000) >> 16;
403         gpDevABlock[6] = ((gnDevABlockIndex-2) & 0x0000FF00) >> 8;
404         gpDevABlock[7] = ((gnDevABlockIndex-2) & 0x000000FF);
405                 
406         gpDevBBlock[4] = ((gnDevBBlockIndex-2) & 0xFF000000) >> 24;
407         gpDevBBlock[5] = ((gnDevBBlockIndex-2) & 0x00FF0000) >> 16;
408         gpDevBBlock[6] = ((gnDevBBlockIndex-2) & 0x0000FF00) >> 8;
409         gpDevBBlock[7] = ((gnDevBBlockIndex-2) & 0x000000FF);
410         
411         memcpy(&gpBin[gnBinIndex], gpDevABlock, gnDevABlockIndex*4);
412         gnBinIndex += (gnDevABlockIndex*4);
413         
414         memcpy(&gpBin[gnBinIndex], gpDevBBlock, gnDevBBlockIndex*4);
415         gnBinIndex += (gnDevBBlockIndex*4);
416         
417         /* write bin file size */
418         gpBin[4] = (gnBinIndex & 0xFF000000) >> 24;
419         gpBin[5] = (gnBinIndex & 0x00FF0000) >> 16;
420         gpBin[6] = (gnBinIndex & 0x0000FF00) >> 8;
421         gpBin[7] = (gnBinIndex & 0x000000FF);
423         write(gBinFile, gpBin, gnBinIndex);
424         close(gBinFile);
426         gBinFile = 0;
429 // ----------------------------------------------------------------------------- 
430 // check_spk_bounds 
431 // ----------------------------------------------------------------------------- 
432 // Description: 
433 //      Checks if speaker paramters are within bounds. 
434 // ----------------------------------------------------------------------------- 
435 uint32_t check_spk_bounds(struct TFTCConfiguration *pFTCC, double re1, double re2) 
436
437         uint32_t result = RESULT_PASS; 
439         if(re1>pFTCC->nTSpkCharDevA.nReHi) 
440                 result |= RE1_FAIL_HI; 
441         if(re1<pFTCC->nTSpkCharDevA.nReLo) 
442                 result |= RE1_FAIL_LO; 
443    
444     if(re2>pFTCC->nTSpkCharDevB.nReHi) 
445         result |= RE2_FAIL_HI; 
446     if(re2<pFTCC->nTSpkCharDevB.nReLo) 
447         result |= RE2_FAIL_LO; 
449         return result; 
450
452 void tas2557_ftc_release(void)
454         if (gTILoad > 0) {
455                 close(gTILoad);
456                 gTILoad = 0;
457         }