1 /*
2  * Copyright  2019 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 /*
9  * fsl_tfa9xxx.c
10  *
11  *   General platform specific integration of tfa2_core code.
12  */
13 
14 #include "fsl_tfa9xxx.h"
15 
16 /*******************************************************************************
17  * Definitions
18  ******************************************************************************/
19 #define TFA9XXX_ROUND_DOWN(a, n)    (((a) / (n)) * (n))
20 #define TFA9XXX_I2C_MAX_DATA_LENGTH 256
21 
22 /*******************************************************************************
23  * Prototypes
24  ******************************************************************************/
25 
26 status_t TFA9XXX_CreatePlatform(tfa9xxx_handle_t *handle, void *tfa_container_bin);
27 status_t TFA9XXX_PreStartConfigure(tfa9xxx_handle_t *handle);
28 void *TFA9XXX_GetI2CClient(nxpTfaContainer_t *cnt, uint8_t slaveAddress);
29 int TFA9XXX_DspExecuteCommand(
30     struct tfa2_device *tfa, const char *cmd_buf, size_t cmd_len, char *res_buf, size_t res_len);
31 /*******************************************************************************
32  * Variables
33  ******************************************************************************/
34 
35 /* tfa9xxx_device_t list */
36 static tfa9xxx_device_t s_devs[TFA9XXX_DEV_NUM];
37 
38 /* profile index in container header file for the TFA to start */
39 static uint8_t s_TFA9XXX_start_profile = 0;
40 
41 /*******************************************************************************
42  * Code
43  ******************************************************************************/
44 
45 /*!
46  * @brief Initialize the TFA, put the TFA to operating state, allocate memory side.
47  *
48  * @param handle TFA9XXX handle structure.
49  * @param tfa9xxxConfig TFA9XXX configuration structure.
50  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
51  */
TFA9XXX_Init(tfa9xxx_handle_t * handle,tfa9xxx_config_t * tfa9xxxConfig)52 status_t TFA9XXX_Init(tfa9xxx_handle_t *handle, tfa9xxx_config_t *tfa9xxxConfig)
53 {
54     status_t rc;
55     tfa9xxx_config_t *config = tfa9xxxConfig;
56     handle->config           = config;
57 
58     TFA9XXX_Printf("==========================================================\n", __FUNCTION__);
59     TFA9XXX_Printf("%s: TFA initialization starting...\n", __FUNCTION__);
60 
61     /* i2c bus initialization */
62     if (CODEC_I2C_Init(&(handle->i2cHandle), config->i2cConfig.codecI2CInstance, TFA9XXX_I2C_BAUDRATE,
63                        config->i2cConfig.codecI2CSourceClock) != kStatus_HAL_I2cSuccess)
64     {
65         return kStatus_Fail;
66     }
67 
68     /*
69      * instantiate and probe the device(s)
70      */
71     rc = TFA9XXX_CreatePlatform(handle, config->tfaContainer);
72     if (rc != kStatus_Success)
73     {
74         TFA9XXX_Printf("%s: TFA create platform failed:\n", __FUNCTION__);
75         return rc;
76     }
77 
78     /* Reset TFA */
79     rc = TFA9XXX_Reset(handle);
80     if (rc != kStatus_Success)
81     {
82         TFA9XXX_Printf("%s: TFA reset failed:\n", __FUNCTION__);
83         return rc;
84     }
85 
86     /* Set calibration value */
87     rc = TFA9XXX_PreStartConfigure(handle);
88     if (rc != kStatus_Success)
89     {
90         TFA9XXX_Printf("%s: TFA pre-start configure failed:\n", __FUNCTION__);
91         return rc;
92     }
93 
94     /* Reset TFA */
95     rc = TFA9XXX_Reset(handle);
96     if (rc != kStatus_Success)
97     {
98         TFA9XXX_Printf("%s: TFA reset failed:\n", __FUNCTION__);
99         return rc;
100     }
101 
102     rc = TFA9XXX_Start(handle);
103     if (rc != kStatus_Success)
104     {
105         TFA9XXX_Printf("%s: TFA start failed:\n", __FUNCTION__);
106         return rc;
107     }
108 
109     rc = TFA9XXX_SetMute(handle, false);
110     if (rc != kStatus_Success)
111     {
112         TFA9XXX_Printf("%s: TFA set mute failed:\n", __FUNCTION__);
113         return rc;
114     }
115 
116     TFA9XXX_Printf("%s: TFA initialized successfully.\n", __FUNCTION__);
117     TFA9XXX_Printf("==========================================================\n", __FUNCTION__);
118     return rc;
119 }
120 
121 /*!
122  * @brief Deinitialize the TFA, put the TFA to powerdown state.
123  *
124  * @param handle The TFA codec handle.
125  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
126  */
TFA9XXX_Deinit(tfa9xxx_handle_t * handle)127 status_t TFA9XXX_Deinit(tfa9xxx_handle_t *handle)
128 {
129     status_t rc;
130     if (!handle)
131     {
132         TFA9XXX_Printf("%s: TFA codec handle is NULL\n", __FUNCTION__);
133         return kStatus_InvalidArgument;
134     }
135 
136     rc = TFA9XXX_Reset(handle);
137     if (rc != kStatus_Success)
138         TFA9XXX_Printf("%s: TFA reset failed:\n", __FUNCTION__);
139 
140     return rc;
141 }
142 
143 /*!
144  * @brief Start the TFA.
145  *
146  * Start device will initialize if the device is in cold state
147  * if already warm then only clocks will be started.
148  *
149  * This function has dependency on internal structure, it has to be called after TFA9XXX_CreatePlatform();
150  *
151  * @param handle The TFA codec handle.
152  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
153  */
TFA9XXX_Start(tfa9xxx_handle_t * handle)154 status_t TFA9XXX_Start(tfa9xxx_handle_t *handle)
155 {
156     status_t rc;
157     if (!handle)
158     {
159         TFA9XXX_Printf("%s: TFA codec handle is NULL\n", __FUNCTION__);
160         return kStatus_InvalidArgument;
161     }
162 
163     rc = tfa2_dev_start(&s_devs[handle->config->deviceIndex], s_TFA9XXX_start_profile, 0);
164 
165     return TFA9XXX_ConvertErrorCode(rc);
166 }
167 
168 /*!
169  * @brief Stop the TFA
170  *
171  * stop will put the TFA in powerdown/standby mode, the next time TFA start will be a warm start.
172  *
173  * This function has dependency on internal structure, it has to be called after TFA9XXX_CreatePlatform();
174  *
175  * @param handle The TFA codec handle.
176  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
177  */
TFA9XXX_Stop(tfa9xxx_handle_t * handle)178 status_t TFA9XXX_Stop(tfa9xxx_handle_t *handle)
179 {
180     status_t rc;
181     if (!handle)
182     {
183         TFA9XXX_Printf("%s: TFA codec handle is NULL\n", __FUNCTION__);
184         return kStatus_InvalidArgument;
185     }
186 
187     rc = tfa2_dev_stop(&s_devs[handle->config->deviceIndex]);
188 
189     return TFA9XXX_ConvertErrorCode(rc);
190 }
191 
192 /*!
193  * @brief Reset the TFA
194  *
195  * Reset will put the in powerdown/standby mode, the next time TFA start will be a cold start.
196  *
197  * This function has dependency on internal structure, it has to be called after TFA9XXX_CreatePlatform();
198  *
199  * @param handle The TFA codec handle.
200  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
201  */
TFA9XXX_Reset(tfa9xxx_handle_t * handle)202 status_t TFA9XXX_Reset(tfa9xxx_handle_t *handle)
203 {
204     status_t rc;
205     if (!handle)
206     {
207         TFA9XXX_Printf("%s: TFA codec handle is NULL\n", __FUNCTION__);
208         return kStatus_InvalidArgument;
209     }
210 
211     rc = tfa2_dev_set_state(&s_devs[handle->config->deviceIndex], TFA_STATE_RESET);
212 
213     return TFA9XXX_ConvertErrorCode(rc);
214 }
215 
216 /*!
217  * @brief Mute/Unmute the TFA
218  *
219  * This function has dependency on internal structure, it has to be called after TFA9XXX_CreatePlatform();
220  *
221  * @param handle TFA9XXX handle structure.
222  * @param isMute true is mute, false is unmute..
223  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
224  */
TFA9XXX_SetMute(tfa9xxx_handle_t * handle,bool isMute)225 status_t TFA9XXX_SetMute(tfa9xxx_handle_t *handle, bool isMute)
226 {
227     status_t rc;
228     if (!handle)
229     {
230         TFA9XXX_Printf("%s: TFA codec handle is NULL\n", __FUNCTION__);
231         return kStatus_InvalidArgument;
232     }
233 
234     rc = tfa2_dev_mute(&s_devs[handle->config->deviceIndex], isMute);
235 
236     return TFA9XXX_ConvertErrorCode(rc);
237 }
238 
239 /******************************device object creation ***********************/
240 
241 /*!
242  * @brief Create the platform that TFA relies on.
243  *
244  * this needs to be called once after powerup.
245  * audio clocking is not required here, but may be running.
246  *
247  * @param handle The TFA codec handle.
248  * @param tfa_container_bin The container bin contains the settings and binary files that are needed by TFA.
249  *
250  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
251  */
TFA9XXX_CreatePlatform(tfa9xxx_handle_t * handle,void * tfa_container_bin)252 status_t TFA9XXX_CreatePlatform(tfa9xxx_handle_t *handle, void *tfa_container_bin)
253 {
254     status_t rc;
255     nxpTfaHeaderType_t type;
256     struct nxpTfaContainer *cnt;
257 
258     tfa9xxx_device_t *tfa = &s_devs[handle->config->deviceIndex];
259 
260     /* verify if container file is valid */
261     cnt  = (struct nxpTfaContainer *)tfa_container_bin;
262     type = (nxpTfaHeaderType_t)HDR(cnt->id[0], cnt->id[1]);
263     if (type != paramsHdr)
264     { /* Load container file */
265         TFA9XXX_Printf("%s: the container file is invalid\n", __FUNCTION__);
266         return kStatus_InvalidArgument;
267     }
268     tfa->cnt = cnt;
269 
270     /* verify if slave address is valid */
271     tfa->dev_idx = 0;
272     tfa->i2c     = (struct i2c_client *)TFA9XXX_GetI2CClient(cnt, handle->config->slaveAddress);
273     if (!tfa->i2c)
274     {
275         TFA9XXX_Printf("%s: Invalid slave address\n", __FUNCTION__);
276         return kStatus_InvalidArgument;
277     }
278     tfa->i2c->hal = &(handle->i2cHandle);
279 
280     rc = tfa2_dev_probe(tfa);
281     if (rc < 0)
282     {
283         TFA9XXX_Printf("%s: error probing device\n", __FUNCTION__);
284         return TFA9XXX_ConvertErrorCode(rc);
285     }
286     if ((tfa->rev == 0x2a94) || (tfa->rev == 0x3a94))
287     {
288         /* bf_manstate overloads for TFA9894N2A0 and TFA9894N2A1*/
289         tfa->bf_manstate = 0x1333;
290     }
291     tfa->dsp_execute = TFA9XXX_DspExecuteCommand;
292     tfa->verbose     = 1U;
293 
294     return kStatus_Success;
295 }
296 
297 /*!
298  * @brief Configurate the TFA before starting by setting hardcoded calibration value for a new chip.
299  *
300  * This function has dependency on internal structure, it has to be called after TFA9XXX_CreatePlatform();
301  *
302  * @param handle The TFA codec handle.
303  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
304  */
TFA9XXX_PreStartConfigure(tfa9xxx_handle_t * handle)305 status_t TFA9XXX_PreStartConfigure(tfa9xxx_handle_t *handle)
306 {
307     status_t rc;
308     bool isTFACalibrated;
309     tfa9xxx_device_t *tfa = &s_devs[handle->config->deviceIndex];
310 
311     rc = tfa2_i2c_write_bf(tfa->i2c, TFA9XXX_BF_PWDN, 0);
312     if (rc < 0)
313     {
314         TFA9XXX_Printf("%s: Setting PWDN failed!\n", __FUNCTION__);
315         return TFA9XXX_ConvertErrorCode(rc);
316     }
317 
318     rc = tfa2_dev_clock_stable_wait(tfa);
319     if (rc != kStatus_Success)
320     {
321         TFA9XXX_Printf("%s: TFA failed to power up.\n", __FUNCTION__);
322         return rc;
323     }
324 
325     rc = TFA9XXX_CheckCalibrationStatus(handle, &isTFACalibrated);
326     if (rc != kStatus_Success)
327     {
328         TFA9XXX_Printf("%s: TFA check calibration status failed:\n", __FUNCTION__);
329         return rc;
330     }
331 
332     if (!isTFACalibrated)
333     {
334         TFA9XXX_Printf("%s: TFA is not calibrated, setting Calibration value...\n", __FUNCTION__);
335         rc = TFA9XXX_HardcodeCalibrationValue(handle);
336         if (rc != kStatus_Success)
337         {
338             TFA9XXX_Printf("%s: Setting Calibration value failed:\n", __FUNCTION__);
339             return rc;
340         }
341     }
342     else
343     {
344         TFA9XXX_Printf("%s: TFA is already calibrated, continue to start...\n", __FUNCTION__);
345     }
346 
347     return rc;
348 }
349 
350 /*!
351  * @brief check if TFA is calibrated.
352  *
353  * This function has dependency on internal structure, it has to be called after TFA9XXX_CreatePlatform();
354  *
355  * @param handle The TFA codec handle.
356  * @param isTFACalibrated This value stores if TFA is calibrated.
357  * @return status_t Returns kStatus_Success if operation is successfully, otherwise returns error code..
358  */
TFA9XXX_CheckCalibrationStatus(tfa9xxx_handle_t * handle,bool * isTFACalibrated)359 status_t TFA9XXX_CheckCalibrationStatus(tfa9xxx_handle_t *handle, bool *isTFACalibrated)
360 {
361     status_t rc;
362 
363     if (!handle)
364     {
365         TFA9XXX_Printf("%s: TFA codec handle is NULL\n", __FUNCTION__);
366         return kStatus_InvalidArgument;
367     }
368 
369     tfa9xxx_device_t *tfa = &s_devs[handle->config->deviceIndex];
370 
371     /* open key2 */
372     rc = tfa2_i2c_hap_key2(tfa->i2c, 0);
373     if (rc < 0)
374     {
375         TFA9XXX_Printf("%s: open key2 failed!\n", __FUNCTION__);
376         goto exit;
377     }
378     /* check MTPEX, trigger CMTPI inside */
379     rc = tfa2_dev_mtp_get(tfa, TFA_MTP_EX);
380     if (rc < 0)
381     {
382         TFA9XXX_Printf("%s: check tfa calibration failed, cannot read MTPEX!\n", __FUNCTION__);
383         goto exit;
384     }
385     else
386     {
387         *isTFACalibrated = rc;
388         rc               = kStatus_Success;
389     }
390 
391 exit:
392     /* close key2 */
393     rc = tfa2_i2c_hap_key2(tfa->i2c, 1);
394     if (rc < 0)
395     {
396         TFA9XXX_Printf("%s: close key2 failed!\n", __FUNCTION__);
397     }
398 
399     return TFA9XXX_ConvertErrorCode(rc);
400 }
401 
402 /*!
403  * @brief Start Speakerboost Calibration.
404  *
405  * The calibration will measure speaker impedance, and calculate the speaker impedance at 25 degree.
406  * This value will be used to estimate the real-time temperature.
407  *
408  * This function has dependency on internal structure, it has to be called after TFA9XXX_CreatePlatform();
409  *
410  * @param handle The TFA codec handle.
411  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
412  */
TFA9XXX_CalibrateSpeakerBoost(tfa9xxx_handle_t * handle)413 status_t TFA9XXX_CalibrateSpeakerBoost(tfa9xxx_handle_t *handle)
414 {
415     status_t rc;
416 
417     if (!handle)
418     {
419         TFA9XXX_Printf("%s: TFA codec handle is NULL\n", __FUNCTION__);
420         return kStatus_InvalidArgument;
421     }
422 
423     tfa9xxx_device_t *tfa = &s_devs[handle->config->deviceIndex];
424 
425     rc = tfa2_dev_mtp_set(tfa, TFA_MTP_OTC, 1);
426     if (rc < 0)
427     {
428         TFA9XXX_Printf("%s: writing of MTPOTC failed!\n", __FUNCTION__);
429         return TFA9XXX_ConvertErrorCode(rc);
430     }
431 
432     rc = tfa2_dev_mtp_set(tfa, TFA_MTP_EX, 0);
433     if (rc < 0)
434     {
435         TFA9XXX_Printf("%s: MTP set failed!\n", __FUNCTION__);
436         return TFA9XXX_ConvertErrorCode(rc);
437     }
438 
439     rc = tfa2_sb_calibrate(tfa);
440     if (rc < 0)
441     {
442         TFA9XXX_Printf("%s: SpeakerBoost Calibration failed!\n", __FUNCTION__);
443     }
444 
445     return TFA9XXX_ConvertErrorCode(rc);
446 }
447 
448 /*!
449  * @brief Hardcode calibration value for DSP usage instead of triggering calibration.
450  *
451  * This function has dependency on internal structure, it has to be called after TFA9XXX_CreatePlatform();
452  *
453  * @param handle TFA9XXX handle structure.
454  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
455  */
TFA9XXX_HardcodeCalibrationValue(tfa9xxx_handle_t * handle)456 status_t TFA9XXX_HardcodeCalibrationValue(tfa9xxx_handle_t *handle)
457 {
458     status_t rc;
459     uint16_t mtp_data_pre[16];
460     uint8_t i;
461 
462     if (!handle)
463     {
464         TFA9XXX_Printf("%s: TFA codec handle is NULL\n", __FUNCTION__);
465         return kStatus_InvalidArgument;
466     }
467 
468     tfa9xxx_device_t *tfa = &s_devs[handle->config->deviceIndex];
469 
470     /* open key2 */
471     tfa2_i2c_hap_key2(tfa->i2c, 0);
472 
473     /* open mtp */
474     rc = tfa2_dev_mtp_set(tfa, TFA_MTP_OPEN, 1);
475     if (rc < 0)
476     {
477         TFA9XXX_Printf("%s: writing of OPENMTP failed!\n", __FUNCTION__);
478         goto exit;
479     }
480 
481     // store original MTP data from  0xf0 ~ 0xff:
482     rc = tfa2_i2c_write_bf(tfa->i2c, TFA9XXX_BF_CMTPI, 1);
483     if (rc < 0)
484     {
485         TFA9XXX_Printf("%s: writing CMTPI failed!\n", __FUNCTION__);
486         goto exit;
487     }
488 
489     for (i = 0; i < 16U; i++)
490     {
491         rc = tfa2_i2c_read_reg(tfa->i2c, 0xF0U + i);
492         if (rc < 0)
493             goto exit;
494         mtp_data_pre[i] = rc;
495     }
496 
497     /* open MTP already called inside */
498     rc = tfa2_dev_mtp_set(tfa, TFA_MTP_EX, 1);
499     if (rc < 0)
500     {
501         TFA9XXX_Printf("%s: writing of MTPEX failed!\n", __FUNCTION__);
502         goto exit;
503     }
504     rc = tfa2_dev_mtp_set(tfa, TFA_MTP_OTC, 1);
505     if (rc < 0)
506     {
507         TFA9XXX_Printf("%s: writing of MTPOTC failed!\n", __FUNCTION__);
508         goto exit;
509     }
510     /* hardcode 8 ohm (8*1024 = 8192 = 0x2000) */
511     rc = tfa2_dev_mtp_set(tfa, TFA_MTP_R25C, 0x2000U);
512     if (rc < 0)
513     {
514         TFA9XXX_Printf("%s: writing of R25C failed!\n", __FUNCTION__);
515         goto exit;
516     }
517 
518     for (i = 0; i < 16U; i++)
519     {
520         rc = tfa2_i2c_read_reg(tfa->i2c, 0xF0U + i);
521         if (rc < 0)
522             goto exit;
523         if (i == 0)
524         {
525             if (rc != (mtp_data_pre[i] | 0x3U))
526             {
527                 TFA9XXX_Printf("%s: !Unexpected MTP data change!\n", __FUNCTION__);
528                 goto exit;
529             }
530         }
531         else if (i == 5U)
532         {
533             if (rc != 0x2000U)
534             {
535                 TFA9XXX_Printf("%s: !Unexpected MTP data change!\n", __FUNCTION__);
536                 goto exit;
537             }
538         }
539         else
540         {
541             if (rc != mtp_data_pre[i])
542             {
543                 TFA9XXX_Printf("%s: !Unexpected MTP data change!\n", __FUNCTION__);
544                 goto exit;
545             }
546         }
547     }
548 
549 exit:
550     /* close key2 */
551     tfa2_i2c_hap_key2(tfa->i2c, 1);
552 
553     /* close mtp */
554     rc = tfa2_dev_mtp_set(tfa, TFA_MTP_OPEN, 0);
555     if (rc < 0)
556     {
557         TFA9XXX_Printf("%s: writing of OPENMTP failed!\n", __FUNCTION__);
558     }
559 
560     return TFA9XXX_ConvertErrorCode(rc);
561 }
562 
563 /*!
564  * @brief Configure the TFA based on I2S format.
565  * Assuming TFA_Init() is already called by calling CODEC_Init(), the TFA will be in operating state. So before calling
566  * TFA_SetFormat(), the TFA needs to be in powerdown state by calling TFA_Stop().
567  *
568  * @param handle TFA codec handle.
569  * @param mclk TFA by default uses BCK as external reference clock, mclk settings will be ignored here.
570  * @param sampleRate The sample rates supported are 48000Hz, 44100Hz, 32000Hz and 16000Hz. By default, 48000Hz is used.
571  * @param bitWidth The bit width.
572  * @return Returns @ref kStatus_TFA98XX_Ok if success, otherwise returns error code.
573  */
TFA9XXX_ConfigDataFormat(tfa9xxx_handle_t * handle,uint32_t mclk,uint32_t sampleRate,uint32_t bitWidth)574 status_t TFA9XXX_ConfigDataFormat(tfa9xxx_handle_t *handle, uint32_t mclk, uint32_t sampleRate, uint32_t bitWidth)
575 {
576     if (!handle)
577     {
578         TFA9XXX_Printf("%s: TFA codec handle is NULL\n", __FUNCTION__);
579         return kStatus_InvalidArgument;
580     }
581 
582     TFA9XXX_Printf("Function %s not supported yet\n", __FUNCTION__);
583     return kStatus_Success;
584 }
585 
586 /*!
587  * @brief Set the volume level.
588  *
589  * This function has dependency on internal structure, it has to be called after TFA9XXX_CreatePlatform();
590  *
591  * @param handle TFA codec handle.
592  * @param volume volume value, support 0 ~ 100, 0 is mute, 100 is the maximum volume value.
593  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
594  */
TFA9XXX_SetVolume(tfa9xxx_handle_t * handle,uint32_t volume)595 status_t TFA9XXX_SetVolume(tfa9xxx_handle_t *handle, uint32_t volume)
596 {
597     status_t rc;
598     static const uint16_t VolumeTable[15] = {0, 1, 2, 4, 6, 10, 16, 24, 30, 40, 50, 60, 80, 100, 255};
599     uint8_t index                         = 14 - volume / (100 / 14);
600 
601     //    uint8_t tfaVolume;
602 
603     if (!handle)
604     {
605         TFA9XXX_Printf("%s: TFA codec handle is NULL\n", __FUNCTION__);
606         return kStatus_InvalidArgument;
607     }
608 
609     if (volume > 100)
610     {
611         TFA9XXX_Printf("%s: volume out of range, should be 0 ~ 100\n", __FUNCTION__);
612         return kStatus_InvalidArgument;
613     }
614 
615     //    tfaVolume = (100 - volume) * 0xff / 100;
616 
617     rc = tfa2_i2c_write_bf_volatile(s_devs[handle->config->deviceIndex].i2c, TFA9XXX_BF_VOL, VolumeTable[index]);
618     if (rc < 0)
619     {
620         TFA9XXX_Printf("%s: Setting volume failed!\n", __FUNCTION__);
621     }
622 
623     return TFA9XXX_ConvertErrorCode(rc);
624 }
625 
626 /*!
627  * @brief Set the audio channel for a speaker.
628  * By default, I2S channel is configured by the `.tfaContainer` in `tfa9xxx_config_t`. So you don't need to call this
629  * function. However, if required, calling this function allows overwriting I2S channel selection. This can be useful
630  * when the tuning is done, and you simply want to change the I2S channel.
631  *
632  * This function has dependency on internal structure, it has to be called after TFA9XXX_CreatePlatform();
633  *
634  * @param handle TFA9XXX handle structure.
635  * @param _codec_play_channel play channel, available values are kCODEC_PlayChannelLeft0, kCODEC_PlayChannelRight0,
636  * kCODEC_PlayChannelLeft0 | kCODEC_PlayChannelRight0.
637  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
638  */
TFA9XXX_SetPlayChannel(tfa9xxx_handle_t * handle,uint32_t playChannel)639 status_t TFA9XXX_SetPlayChannel(tfa9xxx_handle_t *handle, uint32_t playChannel)
640 {
641     status_t rc;
642     uint8_t channelCode = 0x01U;
643 
644     tfa9xxx_device_t *tfa = &s_devs[handle->config->deviceIndex];
645 
646     rc = tfa2_i2c_read_bf(tfa->i2c, tfa->bf_manstate);
647     if (rc < 0)
648     {
649         TFA9XXX_Printf("%s: reading TFA status failed!\n", __FUNCTION__);
650         return kStatus_Success;
651     }
652     else if (rc < 6)
653     {
654         TFA9XXX_Printf("%s: TFA not ready for setting channel, skip!\n", __FUNCTION__);
655         return kStatus_Success;
656     }
657 
658     if (playChannel == kTFA9XXX_PlayChannelLeft0)
659     {
660         channelCode = 0x0fU;
661     }
662     else if (playChannel == kTFA9XXX_PlayChannelRight0)
663     {
664         channelCode = 0xf1U;
665     }
666     else if (playChannel == (kTFA9XXX_PlayChannelLeft0 | kTFA9XXX_PlayChannelRight0))
667     {
668         channelCode = 0x01U;
669     }
670     else
671     {
672         TFA9XXX_Printf("%s: play channel unsupported!\n", __FUNCTION__);
673         return kStatus_InvalidArgument;
674     }
675 
676     char SetInputSelector_msg[]      = {0x00U, 0x80U, 0x06U, 0xffU, 0xffU, channelCode,
677                                    0xffU, 0xffU, 0x32U, 0x00U, 0x0fU, 0xffU};
678     uint8_t SetInputSelector_msg_len = 12U;
679 
680     rc = tfa2_cnt_write_msg(tfa, SetInputSelector_msg_len, SetInputSelector_msg);
681     if (rc < 0)
682     {
683         TFA9XXX_Printf("%s: Writing Input Selector message failed!\n", __FUNCTION__);
684     }
685 
686     return TFA9XXX_ConvertErrorCode(rc);
687 }
688 
689 /*!
690  * @brief Get the status of a running TFA.
691  *
692  * This function has dependency on internal structure, it has to be called after TFA9XXX_CreatePlatform();
693  *
694  * @param handle TFA codec handle.
695  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
696  */
TFA9XXX_GetStatus(tfa9xxx_handle_t * handle)697 status_t TFA9XXX_GetStatus(tfa9xxx_handle_t *handle)
698 {
699     status_t rc;
700     if (!handle)
701     {
702         TFA9XXX_Printf("%s: TFA codec handle is NULL\n", __FUNCTION__);
703         return kStatus_InvalidArgument;
704     }
705 
706     rc = tfa2_dev_status(&s_devs[handle->config->deviceIndex]);
707 
708     return TFA9XXX_ConvertErrorCode(rc);
709 }
710 
711 /*!
712  * @brief Send command by i2c to TFA DSP to execute.
713  *
714  * Some long commands have to be chopped into little chunks to satisfy I2C limitation.
715  *
716  * @param tfa tfa device structure.
717  * @param cmd_buf command buffer.
718  * @param cmd_len command length.
719  * @param res_buf result buffer.
720  * @param res_len result length.
721  * @return status_t Returns kStatus_Success if success, otherwise returns error code.
722  */
TFA9XXX_DspExecuteCommand(struct tfa2_device * tfa,const char * cmd_buf,size_t cmd_len,char * res_buf,size_t res_len)723 int TFA9XXX_DspExecuteCommand(
724     struct tfa2_device *tfa, const char *cmd_buf, size_t cmd_len, char *res_buf, size_t res_len)
725 {
726     int rc = 0;
727     uint32_t read_len;
728 
729     /* check write options */
730     if (!cmd_len)
731         return -EINVAL;
732 
733     if (res_len)
734     {
735         /* check read options */
736         if (!res_buf)
737             return -EINVAL;
738         /* not 24bits aligned */
739         if (res_len % 3)
740             return -EFAULT;
741     }
742 
743     /* if read is too big, do it afterwards in chunks */
744     read_len = (res_len > TFA9XXX_I2C_MAX_DATA_LENGTH) ? 0 : res_len;
745 
746     /* if long message then send the payload in max sized chunks, fixup cmd_len */
747     if (cmd_len > TFA9XXX_I2C_MAX_DATA_LENGTH)
748     {
749         /* handle write large messages */
750         uint32_t chunk_size =
751             TFA9XXX_ROUND_DOWN(TFA9XXX_I2C_MAX_DATA_LENGTH - 5 /*TODO dev->tfa->buffer_size*/, 3); /* XMEM word size */
752         uint32_t xmem_offset = 2, remaining_bytes = cmd_len - 3; /* write all except the opcode/cmd_id */
753 
754         /* write in chunks */
755         while ((rc == 0) && (remaining_bytes > 0))
756         {
757             if (remaining_bytes < chunk_size)
758                 chunk_size = remaining_bytes;
759             /* else chunk_size remains at initialize value above */
760             rc = tfa2_i2c_write_cf_mem24(tfa->i2c, xmem_offset, (uint8_t *)cmd_buf + xmem_offset * 3 - 3, chunk_size,
761                                          TFA2_CF_MEM_XMEM);
762             remaining_bytes -= chunk_size;
763             xmem_offset += chunk_size / 3;
764         }
765         if (rc < 0)
766             return rc;
767 
768         /* fake a 1 word cmd, the RPC payload is already there, only need the opcode now */
769         cmd_len = 3;
770     }
771     /* and execute */
772     rc = tfa2_i2c_dsp_execute(tfa, cmd_buf, cmd_len, res_buf, read_len);
773     if (rc < 0)
774         return rc;
775 
776     if (res_len > TFA9XXX_I2C_MAX_DATA_LENGTH)
777     {
778         /* handle write read messages */
779         uint32_t chunk_size =
780             TFA9XXX_ROUND_DOWN(TFA9XXX_I2C_MAX_DATA_LENGTH - 5 /*TODO dev->tfa->buffer_size*/, 3); /* XMEM word size */
781         uint32_t xmem_offset = 0, remaining_bytes = res_len; /* write all except the opcode/cmd_id */
782 
783         /* write in chunks */
784         while ((rc == 0) && (remaining_bytes > 0))
785         {
786             if (remaining_bytes < chunk_size)
787                 chunk_size = remaining_bytes;
788             /* else chunk_size remains at initialize value above */
789             rc = tfa2_i2c_read_cf_mem24(tfa->i2c, xmem_offset, (uint8_t *)res_buf + xmem_offset * 3, chunk_size,
790                                         TFA2_CF_MEM_XMEM);
791             remaining_bytes -= chunk_size;
792             xmem_offset += chunk_size / 3;
793         }
794         if (rc < 0)
795             return rc;
796     }
797 
798     return rc;
799 }
800