/* ** ============================================================================= ** Copyright (c) 2016 Texas Instruments Inc. ** ** This program is free software; you can redistribute it and/or modify it under ** the terms of the GNU General Public License as published by the Free Software ** Foundation; version 2. ** ** This program is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License along with ** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin ** Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** File: ** tas2555.c ** ** Description: ** functions for configurating TAS2555 Android device ** ** ============================================================================= */ #include "tas2557.h" #include "system.h" #include #include #include #include #include #include #include #include #include #define TILOAD_NODE "/dev/tiload_node" static int gTILoad = 0; static int gBinFile = 0; #define MAX_BIN_SIZE 2048 static char gpBin[MAX_BIN_SIZE]; static unsigned int gnBinIndex = 0; static unsigned int gnBinBlockIndex = 0; static char gpDevABlock[MAX_BIN_SIZE/2]; static unsigned int gnDevABlockIndex = 0; static char gpDevBBlock[MAX_BIN_SIZE/2]; static unsigned int gnDevBBlockIndex = 0; static unsigned char gnDevA; static unsigned char gnDevB; static unsigned char gnDev; static void tas2557_check_node(void); void tas2557_mixer_command(char *pCommand, int nData) { char *pMixer[] = {AUDIO_MIXER, pCommand, "0", NULL}; char *pEnv[] = {NULL}; char pData[16]; printf("TAS2555 mixer command %s = %d.\n\r", pCommand, nData); sprintf(pData, "%d", nData); pMixer[2] = pData; if (0 == (fork())) { if (execve(AUDIO_MIXER, pMixer, pEnv) == -1) { printf("factorytest: Can't find mixer. Please install %s. \n\r", AUDIO_MIXER); exit(-1); } } sys_delay(500); } void tas2557_load_configuration(int nConfiguration) { tas2557_check_node(); ioctl(gTILoad, TILOAD_IOCTL_SET_CONFIG, &nConfiguration); sys_delay(500); } void tas2557_load_calibration(int nCalibration) { tas2557_check_node(); ioctl(gTILoad, TILOAD_IOCTL_SET_CALIBRATION, &nCalibration); sys_delay(500); } static void tas2557_check_node(void) { if (gTILoad) return; gTILoad = open(TILOAD_NODE, O_RDWR); if (gTILoad < 0) { printf("factorytest: Can't find tiload. Please create %s. \n\r", TILOAD_NODE); exit(-1); } printf("factorytest: %s handle = %d\n\r", TILOAD_NODE, gTILoad); } uint8_t tas2557_get_PGID(void) { unsigned char pPageZero[] = {0x00, 0x00}; unsigned char pBook[] = {0x7F, 0x00}; unsigned char pPage[] = {0x00, 0x00}; unsigned char pData[] = {0x03, 0x00, 0x00, 0x00, 0x00}; tas2557_check_node(); write(gTILoad, pPageZero, 2); write(gTILoad, pBook, 2); write(gTILoad, pPage, 2); read(gTILoad, pData, 1); return pData[0]; } uint32_t tas2557_coeff_read(uint8_t book, uint8_t page, uint8_t reg) { unsigned char pPageZero[] = {0x00, 0x00}; unsigned char pBook[] = {0x7F, book}; unsigned char pPage[] = {0x00, page}; unsigned char pData[] = {reg, 0x00, 0x00, 0x00, 0x00}; tas2557_check_node(); write(gTILoad, pPageZero, 2); write(gTILoad, pBook, 2); write(gTILoad, pPage, 2); read(gTILoad, pData, 4); return ((pData[0] << 24) | (pData[1] << 16) | (pData[2] << 8) | (pData[3])); } uint32_t tas2557_switch_device(uint8_t i2cslave) { int addr = i2cslave; tas2557_check_node(); gnDev = i2cslave; ioctl(gTILoad, TILOAD_IOCTL_SET_CHL, &addr); return 0; } void tas2557_coeff_write(uint8_t book, uint8_t page, uint8_t reg, uint32_t data) { unsigned int nByte; if (gBinFile) // if the bin file is open, write the coefficients to the bin file { if(gnDev == gnDevA){ unsigned int index = gnDevABlockIndex*4; gpDevABlock[index] = 0; gpDevABlock[index + 1] = 4; gpDevABlock[index + 2] = 0x85; gpDevABlock[index + 4] = book; gpDevABlock[index + 5] = page; gpDevABlock[index + 6] = reg; for (nByte = 0; nByte < 4; nByte++) { gpDevABlock[index + 7 + nByte] = (data >> ((3 - nByte) * 8)) & 0xFF; } gnDevABlockIndex += 3; } else if(gnDev == gnDevB) { unsigned int index = gnDevBBlockIndex*4; gpDevBBlock[index] = 0; gpDevBBlock[index + 1] = 4; gpDevBBlock[index + 2] = 0x85; gpDevBBlock[index + 4] = book; gpDevBBlock[index + 5] = page; gpDevBBlock[index + 6] = reg; for (nByte = 0; nByte < 4; nByte++) { gpDevBBlock[index + 7 + nByte] = (data >> ((3 - nByte) * 8)) & 0xFF; } gnDevBBlockIndex += 3; } } else { unsigned char pPageZero[] = {0x00, 0x00}; unsigned char pBook[] = {0x7F, book}; unsigned char pPage[] = {0x00, page}; unsigned char pData[] = {reg, (data & 0xFF000000) >> 24, (data & 0x00FF0000) >> 16, (data & 0x0000FF00) >> 8, data & 0x000000FF}; tas2557_check_node(); write(gTILoad, pPageZero, 2); write(gTILoad, pBook, 2); write(gTILoad, pPage, 2); write(gTILoad, pData, 5); pBook[1] = 0x8C; pPage[1] = 0x19; pData[0] = 0x7C; pData[1] = 0x00; pData[2] = 0x00; pData[3] = 0x00; pData[4] = 0x01; write(gTILoad, pPageZero, 2); write(gTILoad, pBook, 2); write(gTILoad, pPage, 2); write(gTILoad, pData, 5); pBook[1] = 0x00; pPage[1] = 0x35; pData[0] = 0x2c; pData[1] = 0x00; pData[2] = 0x00; pData[3] = 0x00; pData[4] = 0x01; write(gTILoad, pPageZero, 2); write(gTILoad, pBook, 2); write(gTILoad, pPage, 2); write(gTILoad, pData, 5); } } void tas2557_save_cal(TFTCConfiguration *pFTCC, double dev_a_re, uint32_t dev_a_rms_pow, uint32_t dev_a_t_limit, double dev_b_re, uint32_t dev_b_rms_pow, uint32_t dev_b_t_limit, double t_cal, uint32_t nResult, char * pFileName) { printf("TAS2557 calibration values:\n\r"); printf(" DevA Re = %1.2f Ohm\n\r", dev_a_re); printf(" DevA rms_pow = 0x%08X\n\r", dev_a_rms_pow); printf(" DevA t_limit = 0x%08X\n\r", dev_a_t_limit); printf(" DevB Re = %1.2f Ohm\n\r", dev_b_re); printf(" DevB rms_pow = 0x%08X\n\r", dev_b_rms_pow); printf(" DevB t_limit = 0x%08X\n\r", dev_b_t_limit); if((nResult & RE1_CHK_MSK) == RESULT_PASS){ printf(" SPK A calibration success! \n\r"); }else { if(nResult & RE1_FAIL_HI) printf(" SPK A Calibration fail : Re is too high (limit: %1.2f).\n\r", pFTCC->nTSpkCharDevA.nReHi); else printf(" SPK A Calibration fail : Re is too low (limit: %1.2f).\n\r", pFTCC->nTSpkCharDevA.nReLo); } if((nResult & RE2_CHK_MSK) == RESULT_PASS){ printf(" SPK B calibration success! \n\r"); }else { if(nResult & RE2_FAIL_HI) printf(" SPK B Calibration fail : Re is too high (limit: %1.2f).\n\r", pFTCC->nTSpkCharDevB.nReHi); else printf(" SPK B Calibration fail : Re is too low (limit: %1.2f).\n\r", pFTCC->nTSpkCharDevB.nReLo); } FILE *pFile = fopen(pFileName, "w+"); fprintf(pFile, "DevA Re = %1.2f\n\r", dev_a_re); fprintf(pFile, "DevA rms_pow = 0x%08X\n\r", dev_a_rms_pow); fprintf(pFile, "DevA t_limit = 0x%08X\n\r", dev_a_t_limit); fprintf(pFile, "DevB Re = %1.2f\n\r", dev_b_re); fprintf(pFile, "DevB rms_pow = 0x%08X\n\r", dev_b_rms_pow); fprintf(pFile, "DevB t_limit = 0x%08X\n\r", dev_b_t_limit); fprintf(pFile, "Ambient temperature = %2.2f\n\r\n\r", t_cal); fprintf(pFile, "Result = 0x%x\n\r\n\r", nResult); fclose(pFile); } #define DDC_DESCRIPTION "Calibration Data File for TAS2557 Dual Mono" #define CALIBRATION_DESCRIPTION "Calibration snapshot for TAS2557 Dual Mono" #define DATA_DESCRIPTION "data blocks for TAS2557 Dual Mono FTCc" void tas2557_open_bin(char * pFileName, unsigned int nConfiguration, unsigned char dev_a, unsigned char dev_b) { time_t timestamp; gnDevA = dev_a; gnDevB = dev_b; gBinFile = open(pFileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH); gnBinIndex = 0; memset(gpBin, 0, MAX_BIN_SIZE); memset(gpDevABlock, 0, MAX_BIN_SIZE/2); gnDevABlockIndex = 0; memset(gpDevBBlock, 0, MAX_BIN_SIZE/2); gnDevBBlockIndex = 0; //magic number gpBin[gnBinIndex++] = '5'; gpBin[gnBinIndex++] = '5'; gpBin[gnBinIndex++] = '5'; gpBin[gnBinIndex++] = '2'; gnBinIndex += 4; //bypass size int gnBinIndex += 4; //bypass checksum int gnBinIndex += 4; //bypass PPC3 version int gnBinIndex += 4; //bypass DSP version int gpBin[gnBinIndex++] = 0; gpBin[gnBinIndex++] = 0; gpBin[gnBinIndex++] = 1; gpBin[gnBinIndex++] = 0; //driver version 0x00000100 time(×tamp); gpBin[gnBinIndex++] = (unsigned char)((timestamp&0xff000000)>>24); gpBin[gnBinIndex++] = (unsigned char)((timestamp&0x00ff0000)>>16);; gpBin[gnBinIndex++] = (unsigned char)((timestamp&0x0000ff00)>>8);; gpBin[gnBinIndex++] = (unsigned char)((timestamp&0x000000ff));; strcpy(&gpBin[gnBinIndex], "Calibration Data File"); //DDC name gnBinIndex += 64; strcpy(&gpBin[gnBinIndex], DDC_DESCRIPTION); gnBinIndex += strlen(DDC_DESCRIPTION) + 1; gnBinIndex += 4; //device family index gpBin[gnBinIndex++] = 0; //device index gpBin[gnBinIndex++] = 0; //device index gpBin[gnBinIndex++] = 0; //device index gpBin[gnBinIndex++] = 3; //device index, TAS2557 Dual Mono gnBinIndex += 2 + //num PLL index 0 + //array PLL index 2 + //num programs index 0 + //array programs index 2 + //num configurations index 0; //array configurations index gpBin[gnBinIndex++] = 0x00; gpBin[gnBinIndex++] = 0x01; // one calibration data block strcpy(&gpBin[gnBinIndex], "Calibration snapshot"); gnBinIndex += 64; strcpy(&gpBin[gnBinIndex], CALIBRATION_DESCRIPTION); gnBinIndex += strlen(CALIBRATION_DESCRIPTION) + 1; gpBin[gnBinIndex++] = 0x00; // compatible program = smart amp (index 0) gpBin[gnBinIndex++] = nConfiguration; // compatible configuration strcpy(&gpBin[gnBinIndex], "Calibration Data"); gnBinIndex += 64; strcpy(&gpBin[gnBinIndex], DATA_DESCRIPTION); gnBinIndex += strlen(DATA_DESCRIPTION) + 1; gpBin[gnBinIndex++] = 0x00; // gpBin[gnBinIndex++] = 2; // two blocks gpDevABlock[0] = 0; gpDevABlock[1] = 0; gpDevABlock[2] = 0; gpDevABlock[3] = 0x03; //o COEFF_DEVICE_A – 0x03 gnDevABlockIndex = 2; gpDevBBlock[0] = 0; gpDevBBlock[1] = 0; gpDevBBlock[2] = 0; gpDevBBlock[3] = 0x0a; //o COEFF_DEVICE_B – 0x0a gnDevBBlockIndex = 2; } void tas2557_close_bin(void) { unsigned int nCommands; unsigned char pCommit[] = { 0x00, 0x04, 0x85, 0x00, 0x8C, 0x19, 0x7C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x85, 0x00, 0x00, 0x35, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00 }; // write the commit sequence memcpy(&gpDevABlock[gnDevABlockIndex*4], pCommit, 24); gnDevABlockIndex += 6; memcpy(&gpDevBBlock[gnDevBBlockIndex*4], pCommit, 24); gnDevBBlockIndex += 6; // write number of commands for calibration block gpDevABlock[4] = ((gnDevABlockIndex-2) & 0xFF000000) >> 24; gpDevABlock[5] = ((gnDevABlockIndex-2) & 0x00FF0000) >> 16; gpDevABlock[6] = ((gnDevABlockIndex-2) & 0x0000FF00) >> 8; gpDevABlock[7] = ((gnDevABlockIndex-2) & 0x000000FF); gpDevBBlock[4] = ((gnDevBBlockIndex-2) & 0xFF000000) >> 24; gpDevBBlock[5] = ((gnDevBBlockIndex-2) & 0x00FF0000) >> 16; gpDevBBlock[6] = ((gnDevBBlockIndex-2) & 0x0000FF00) >> 8; gpDevBBlock[7] = ((gnDevBBlockIndex-2) & 0x000000FF); memcpy(&gpBin[gnBinIndex], gpDevABlock, gnDevABlockIndex*4); gnBinIndex += (gnDevABlockIndex*4); memcpy(&gpBin[gnBinIndex], gpDevBBlock, gnDevBBlockIndex*4); gnBinIndex += (gnDevBBlockIndex*4); // write bin file size gpBin[4] = (gnBinIndex & 0xFF000000) >> 24; gpBin[5] = (gnBinIndex & 0x00FF0000) >> 16; gpBin[6] = (gnBinIndex & 0x0000FF00) >> 8; gpBin[7] = (gnBinIndex & 0x000000FF); write(gBinFile, gpBin, gnBinIndex); close(gBinFile); gBinFile = 0; } // ----------------------------------------------------------------------------- // check_spk_bounds // ----------------------------------------------------------------------------- // Description: // Checks if speaker paramters are within bounds. // ----------------------------------------------------------------------------- uint32_t check_spk_bounds(TFTCConfiguration *pFTCC, double re1, double re2) { uint32_t result = RESULT_PASS; if(re1>pFTCC->nTSpkCharDevA.nReHi) result |= RE1_FAIL_HI; if(re1nTSpkCharDevA.nReLo) result |= RE1_FAIL_LO; if(re2>pFTCC->nTSpkCharDevB.nReHi) result |= RE2_FAIL_HI; if(re2nTSpkCharDevB.nReLo) result |= RE2_FAIL_LO; return result; }