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