1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "audio_hw_cirrus_playback" 18 /*#define LOG_NDEBUG 0*/ 19 20 #include <errno.h> 21 #include <math.h> 22 #include <log/log.h> 23 #include <fcntl.h> 24 #include "../audio_hw.h" 25 #include "platform.h" 26 #include "platform_api.h" 27 #include <sys/stat.h> 28 #include <linux/types.h> 29 #include <linux/ioctl.h> 30 #include <stdlib.h> 31 #include <stdio.h> 32 #include <dlfcn.h> 33 #include <math.h> 34 #include <pthread.h> 35 #include <time.h> 36 #include <unistd.h> 37 #include <cutils/properties.h> 38 #include "audio_extn.h" 39 40 struct cirrus_playback_session { 41 void *adev_handle; 42 pthread_mutex_t fb_prot_mutex; 43 pthread_t calibration_thread; 44 #ifdef ENABLE_CIRRUS_DETECTION 45 pthread_t failure_detect_thread; 46 #endif 47 struct pcm *pcm_rx; 48 struct pcm *pcm_tx; 49 volatile int32_t state; 50 }; 51 52 enum cirrus_playback_state { 53 INIT = 0, 54 CALIBRATING = 1, 55 IDLE = 2, 56 PLAYBACK = 3 57 }; 58 59 struct crus_sp_ioctl_header { 60 uint32_t size; 61 uint32_t module_id; 62 uint32_t param_id; 63 uint32_t data_length; 64 void *data; 65 }; 66 67 /* Payload struct for getting calibration result from DSP module */ 68 struct cirrus_cal_result_t { 69 int32_t status_l; 70 int32_t checksum_l; 71 int32_t z_l; 72 int32_t status_r; 73 int32_t checksum_r; 74 int32_t z_r; 75 }; 76 77 /* Payload struct for setting the RX and TX use cases */ 78 struct crus_rx_run_case_ctrl_t { 79 int32_t value; 80 int32_t status_l; 81 int32_t checksum_l; 82 int32_t z_l; 83 int32_t status_r; 84 int32_t checksum_r; 85 int32_t z_r; 86 }; 87 88 #define CRUS_SP_FILE "/dev/msm_cirrus_playback" 89 #define CRUS_CAL_FILE "/persist/audio/audio.cal" 90 #define CRUS_TX_CONF_FILE "vendor/firmware/crus_sp_config_%s_tx.bin" 91 #define CRUS_RX_CONF_FILE "vendor/firmware/crus_sp_config_%s_rx.bin" 92 #define CONFIG_FILE_SIZE 128 93 94 #define CRUS_SP_USECASE_MIXER "Cirrus SP Usecase" 95 #define CRUS_SP_LOAD_CONF_MIXER "Cirrus SP Load Config" 96 #define CRUS_SP_FAIL_DET_MIXER "Cirrus SP Failure Detection" 97 98 #define CIRRUS_SP 0x10027053 99 100 #define CRUS_MODULE_ID_TX 0x00000002 101 #define CRUS_MODULE_ID_RX 0x00000001 102 103 #define CRUS_PARAM_RX_SET_USECASE 0x00A1AF02 104 #define CRUS_PARAM_TX_SET_USECASE 0x00A1BF0A 105 106 #define CRUS_PARAM_RX_SET_CALIB 0x00A1AF03 107 #define CRUS_PARAM_TX_SET_CALIB 0x00A1BF03 108 109 #define CRUS_PARAM_RX_SET_EXT_CONFIG 0x00A1AF05 110 #define CRUS_PARAM_TX_SET_EXT_CONFIG 0x00A1BF08 111 112 #define CRUS_PARAM_RX_GET_TEMP 0x00A1AF07 113 #define CRUS_PARAM_TX_GET_TEMP_CAL 0x00A1BF06 114 // variables based on CSPL tuning file, max parameter length is 96 integers (384 bytes) 115 #define CRUS_PARAM_TEMP_MAX_LENGTH 384 116 117 #define CRUS_AFE_PARAM_ID_ENABLE 0x00010203 118 119 #define FAIL_DETECT_INIT_WAIT_US 500000 120 #define FAIL_DETECT_LOOP_WAIT_US 300000 121 122 #define CRUS_DEFAULT_CAL_L 0x2A11 123 #define CRUS_DEFAULT_CAL_R 0x29CB 124 125 #define CRUS_SP_IOCTL_MAGIC 'a' 126 127 #define CRUS_SP_IOCTL_GET _IOWR(CRUS_SP_IOCTL_MAGIC, 219, void *) 128 #define CRUS_SP_IOCTL_SET _IOWR(CRUS_SP_IOCTL_MAGIC, 220, void *) 129 #define CRUS_SP_IOCTL_GET_CALIB _IOWR(CRUS_SP_IOCTL_MAGIC, 221, void *) 130 #define CRUS_SP_IOCTL_SET_CALIB _IOWR(CRUS_SP_IOCTL_MAGIC, 222, void *) 131 132 133 134 static struct pcm_config pcm_config_cirrus_tx = { 135 .channels = 2, 136 .rate = 48000, 137 .period_size = 320, 138 .period_count = 4, 139 .format = PCM_FORMAT_S16_LE, 140 .start_threshold = 0, 141 .stop_threshold = INT_MAX, 142 .avail_min = 0, 143 }; 144 145 static struct pcm_config pcm_config_cirrus_rx = { 146 .channels = 8, 147 .rate = 48000, 148 .period_size = 320, 149 .period_count = 4, 150 .format = PCM_FORMAT_S32_LE, 151 .start_threshold = 0, 152 .stop_threshold = INT_MAX, 153 .avail_min = 0, 154 }; 155 156 static struct cirrus_playback_session handle; 157 158 #ifdef CIRRUS_FACTORY_CALIBRATION 159 static void *audio_extn_cirrus_calibration_thread(); 160 #else 161 static void *audio_extn_cirrus_config_thread(); 162 #endif 163 164 #ifdef ENABLE_CIRRUS_DETECTION 165 static void *audio_extn_cirrus_failure_detect_thread(); 166 #endif 167 168 void audio_extn_spkr_prot_init(void *adev) { 169 ALOGI("%s: Initialize Cirrus Logic Playback module", __func__); 170 171 memset(&handle, 0, sizeof(handle)); 172 if (!adev) { 173 ALOGE("%s: Invalid params", __func__); 174 return; 175 } 176 177 handle.adev_handle = adev; 178 handle.state = INIT; 179 180 pthread_mutex_init(&handle.fb_prot_mutex, NULL); 181 182 #ifdef CIRRUS_FACTORY_CALIBRATION 183 (void)pthread_create(&handle.calibration_thread, 184 (const pthread_attr_t *) NULL, 185 audio_extn_cirrus_calibration_thread, &handle); 186 #else 187 (void)pthread_create(&handle.calibration_thread, 188 (const pthread_attr_t *) NULL, 189 audio_extn_cirrus_config_thread, &handle); 190 #endif 191 } 192 193 void audio_extn_spkr_prot_deinit(void *adev __unused) { 194 ALOGV("%s: Entry", __func__); 195 196 #ifdef ENABLE_CIRRUS_DETECTION 197 pthread_join(handle.failure_detect_thread, NULL); 198 #endif 199 pthread_join(handle.calibration_thread, NULL); 200 pthread_mutex_destroy(&handle.fb_prot_mutex); 201 202 ALOGV("%s: Exit", __func__); 203 } 204 205 #ifdef CIRRUS_FACTORY_CALIBRATION 206 static int audio_extn_cirrus_run_calibration() { 207 struct audio_device *adev = handle.adev_handle; 208 struct crus_sp_ioctl_header header; 209 struct cirrus_cal_result_t result; 210 struct mixer_ctl *ctl = NULL; 211 FILE *cal_file = NULL; 212 int ret = 0, dev_file = -1; 213 char *buffer = NULL; 214 uint32_t option = 1; 215 216 ALOGI("%s: Running speaker calibration", __func__); 217 218 dev_file = open(CRUS_SP_FILE, O_RDWR | O_NONBLOCK); 219 if (dev_file < 0) { 220 ALOGE("%s: Failed to open Cirrus Playback IOCTL (%d)", 221 __func__, dev_file); 222 ret = -EINVAL; 223 goto exit; 224 } 225 226 buffer = calloc(1, CRUS_PARAM_TEMP_MAX_LENGTH); 227 if (!buffer) { 228 ALOGE("%s: allocate memory failed", __func__); 229 ret = -ENOMEM; 230 goto exit; 231 } 232 233 cal_file = fopen(CRUS_CAL_FILE, "r"); 234 if (cal_file) { 235 ret = fread(&result, sizeof(result), 1, cal_file); 236 if (ret != 1) { 237 ALOGE("%s: Cirrus SP calibration file cannot be read , read size: %lu file error: %d", 238 __func__, (unsigned long)ret * sizeof(result), ferror(cal_file)); 239 ret = -EINVAL; 240 fclose(cal_file); 241 goto exit; 242 } 243 244 fclose(cal_file); 245 } else { 246 247 ALOGV("%s: Calibrating...", __func__); 248 249 header.size = sizeof(header); 250 header.module_id = CRUS_MODULE_ID_RX; 251 header.param_id = CRUS_PARAM_RX_SET_CALIB; 252 header.data_length = sizeof(option); 253 header.data = &option; 254 255 ret = ioctl(dev_file, CRUS_SP_IOCTL_SET, &header); 256 if (ret < 0) { 257 ALOGE("%s: Cirrus SP calibration IOCTL failure (%d)", 258 __func__, ret); 259 ret = -EINVAL; 260 goto exit; 261 } 262 263 header.size = sizeof(header); 264 header.module_id = CRUS_MODULE_ID_TX; 265 header.param_id = CRUS_PARAM_TX_SET_CALIB; 266 header.data_length = sizeof(option); 267 header.data = &option; 268 269 ret = ioctl(dev_file, CRUS_SP_IOCTL_SET, &header); 270 if (ret < 0) { 271 ALOGE("%s: Cirrus SP calibration IOCTL failure (%d)", 272 __func__, ret); 273 ret = -EINVAL; 274 goto exit; 275 } 276 277 sleep(2); 278 279 header.size = sizeof(header); 280 header.module_id = CRUS_MODULE_ID_TX; 281 header.param_id = CRUS_PARAM_TX_GET_TEMP_CAL; 282 header.data_length = sizeof(result); 283 header.data = &result; 284 285 ret = ioctl(dev_file, CRUS_SP_IOCTL_GET, &header); 286 if (ret < 0) { 287 ALOGE("%s: Cirrus SP calibration IOCTL failure (%d)", 288 __func__, ret); 289 ret = -EINVAL; 290 goto exit; 291 } 292 293 if (result.status_l != 1) { 294 ALOGE("%s: Left calibration failure. Please check speakers", 295 __func__); 296 ret = -EINVAL; 297 } 298 299 if (result.status_r != 1) { 300 ALOGE("%s: Right calibration failure. Please check speakers", 301 __func__); 302 ret = -EINVAL; 303 } 304 305 if (ret < 0) 306 goto exit; 307 308 cal_file = fopen(CRUS_CAL_FILE, "wb"); 309 if (cal_file == NULL) { 310 ALOGE("%s: Cannot create Cirrus SP calibration file (%s)", 311 __func__, strerror(errno)); 312 ret = -EINVAL; 313 goto exit; 314 } 315 316 ret = fwrite(&result, sizeof(result), 1, cal_file); 317 318 if (ret != 1) { 319 ALOGE("%s: Unable to save Cirrus SP calibration data, write size %lu, file error %d", 320 __func__, (unsigned long)ret * sizeof(result), ferror(cal_file)); 321 fclose(cal_file); 322 ret = -EINVAL; 323 goto exit; 324 } 325 326 fclose(cal_file); 327 328 ALOGI("%s: Cirrus calibration file successfully written", 329 __func__); 330 } 331 332 header.size = sizeof(header); 333 header.module_id = CRUS_MODULE_ID_TX; 334 header.param_id = 0; 335 header.data_length = sizeof(result); 336 header.data = &result; 337 338 ret = ioctl(dev_file, CRUS_SP_IOCTL_SET_CALIB, &header); 339 340 if (ret < 0) { 341 ALOGE("%s: Cirrus SP calibration IOCTL failure (%d)", __func__, ret); 342 ret = -EINVAL; 343 goto exit; 344 } 345 346 ctl = mixer_get_ctl_by_name(adev->mixer, 347 CRUS_SP_USECASE_MIXER); 348 if (!ctl) { 349 ALOGE("%s: Could not get ctl for mixer cmd - %s", 350 __func__, CRUS_SP_USECASE_MIXER); 351 ret = -EINVAL; 352 goto exit; 353 } 354 355 ret = mixer_ctl_set_value(ctl, 0, 0); // Set RX external firmware config 356 if (ret < 0) { 357 ALOGE("%s: set default usecase failed", __func__); 358 goto exit; 359 } 360 361 sleep(1); 362 363 header.size = sizeof(header); 364 header.module_id = CRUS_MODULE_ID_RX; 365 header.param_id = CRUS_PARAM_RX_GET_TEMP; 366 header.data_length = CRUS_PARAM_TEMP_MAX_LENGTH; 367 header.data = buffer; 368 369 ret = ioctl(dev_file, CRUS_SP_IOCTL_GET, &header); 370 if (ret < 0) { 371 ALOGE("%s: Cirrus SP temperature IOCTL failure (%d)", __func__, ret); 372 ret = -EINVAL; 373 goto exit; 374 } 375 376 ALOGI("%s: Cirrus SP successfully calibrated", __func__); 377 378 exit: 379 if (dev_file >= 0) 380 close(dev_file); 381 free(buffer); 382 ALOGV("%s: Exit", __func__); 383 384 return ret; 385 } 386 387 static int audio_extn_cirrus_load_usecase_configs(void) { 388 struct audio_device *adev = handle.adev_handle; 389 struct mixer_ctl *ctl_uc = NULL, *ctl_config = NULL; 390 char *filename = NULL; 391 int ret = 0, default_uc = 0; 392 struct snd_card_split *snd_split_handle = NULL; 393 snd_split_handle = audio_extn_get_snd_card_split(); 394 395 ALOGI("%s: Loading usecase tuning configs", __func__); 396 397 ctl_uc = mixer_get_ctl_by_name(adev->mixer, CRUS_SP_USECASE_MIXER); 398 ctl_config = mixer_get_ctl_by_name(adev->mixer, 399 CRUS_SP_LOAD_CONF_MIXER); 400 if (!ctl_uc || !ctl_config) { 401 ALOGE("%s: Could not get ctl for mixer commands", __func__); 402 ret = -EINVAL; 403 goto exit; 404 } 405 406 filename = calloc(1 , CONFIG_FILE_SIZE); 407 if (!filename) { 408 ALOGE("%s: allocate memory failed", __func__); 409 ret = -ENOMEM; 410 goto exit; 411 } 412 413 default_uc = mixer_ctl_get_value(ctl_uc, 0); 414 415 ret = mixer_ctl_set_value(ctl_uc, 0, default_uc); 416 if (ret < 0) { 417 ALOGE("%s set uscase %d failed", __func__, default_uc); 418 goto exit; 419 } 420 421 /* Load TX Tuning Config (if available) */ 422 snprintf(filename, CONFIG_FILE_SIZE, CRUS_TX_CONF_FILE, snd_split_handle->form_factor); 423 if (access(filename, R_OK) == 0) { 424 ret = mixer_ctl_set_value(ctl_config, 0, 2); 425 if (ret < 0) { 426 ALOGE("%s set tx config failed", __func__); 427 goto exit; 428 } 429 } else { 430 ALOGE("%s: Tuning file not found (%s)", __func__, 431 filename); 432 ret = -EINVAL; 433 goto exit; 434 } 435 /* Load RX Tuning Config (if available) */ 436 snprintf(filename, CONFIG_FILE_SIZE, CRUS_RX_CONF_FILE, snd_split_handle->form_factor); 437 if (access(filename, R_OK) == 0) { 438 ret = mixer_ctl_set_value(ctl_config, 0, 1); 439 if (ret < 0) { 440 ALOGE("%s set rx config failed", __func__); 441 goto exit; 442 } 443 } else { 444 ALOGE("%s: Tuning file not found (%s)", __func__, 445 filename); 446 ret = -EINVAL; 447 goto exit; 448 } 449 450 ALOGI("%s: Cirrus SP loaded available usecase configs", __func__); 451 exit: 452 free(filename); 453 ALOGI("%s: Exit", __func__); 454 455 return ret; 456 } 457 458 static void *audio_extn_cirrus_calibration_thread() { 459 struct audio_device *adev = handle.adev_handle; 460 struct audio_usecase *uc_info_rx = NULL; 461 int ret = 0; 462 int32_t pcm_dev_rx_id, prev_state; 463 uint32_t retries = 5; 464 465 ALOGI("%s: PCM Stream thread", __func__); 466 467 while (!adev->platform && retries) { 468 sleep(1); 469 ALOGI("%s: Waiting...", __func__); 470 retries--; 471 } 472 473 prev_state = handle.state; 474 handle.state = CALIBRATING; 475 476 uc_info_rx = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); 477 if (!uc_info_rx) { 478 ALOGE("%s: rx usecase can not be found", __func__); 479 goto exit; 480 } 481 pthread_mutex_lock(&adev->lock); 482 483 uc_info_rx->id = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; 484 uc_info_rx->type = PCM_PLAYBACK; 485 uc_info_rx->in_snd_device = SND_DEVICE_NONE; 486 uc_info_rx->stream.out = adev->primary_output; 487 uc_info_rx->out_snd_device = SND_DEVICE_OUT_SPEAKER; 488 list_add_tail(&adev->usecase_list, &uc_info_rx->list); 489 490 enable_snd_device(adev, SND_DEVICE_OUT_SPEAKER); 491 enable_audio_route(adev, uc_info_rx); 492 pcm_dev_rx_id = platform_get_pcm_device_id(uc_info_rx->id, PCM_PLAYBACK); 493 494 if (pcm_dev_rx_id < 0) { 495 ALOGE("%s: Invalid pcm device for usecase (%d)", 496 __func__, uc_info_rx->id); 497 pthread_mutex_unlock(&adev->lock); 498 goto exit; 499 } 500 501 handle.pcm_rx = pcm_open(adev->snd_card, pcm_dev_rx_id, 502 PCM_OUT, &pcm_config_cirrus_rx); 503 504 if (handle.pcm_rx && !pcm_is_ready(handle.pcm_rx)) { 505 ALOGE("%s: PCM device not ready: %s", __func__, 506 pcm_get_error(handle.pcm_rx)); 507 pthread_mutex_unlock(&adev->lock); 508 goto close_stream; 509 } 510 511 if (pcm_start(handle.pcm_rx) < 0) { 512 ALOGE("%s: pcm start for RX failed; error = %s", __func__, 513 pcm_get_error(handle.pcm_rx)); 514 pthread_mutex_unlock(&adev->lock); 515 goto close_stream; 516 } 517 pthread_mutex_unlock(&adev->lock); 518 ALOGI("%s: PCM thread streaming", __func__); 519 520 ret = audio_extn_cirrus_run_calibration(); 521 ALOGE_IF(ret < 0, "%s: Calibration procedure failed (%d)", __func__, ret); 522 523 ret = audio_extn_cirrus_load_usecase_configs(); 524 ALOGE_IF(ret < 0, "%s: Set tuning configs failed (%d)", __func__, ret); 525 526 close_stream: 527 pthread_mutex_lock(&adev->lock); 528 if (handle.pcm_rx) { 529 ALOGI("%s: pcm_rx_close", __func__); 530 pcm_close(handle.pcm_rx); 531 handle.pcm_rx = NULL; 532 } 533 disable_audio_route(adev, uc_info_rx); 534 disable_snd_device(adev, SND_DEVICE_OUT_SPEAKER); 535 list_remove(&uc_info_rx->list); 536 free(uc_info_rx); 537 pthread_mutex_unlock(&adev->lock); 538 exit: 539 handle.state = (prev_state == PLAYBACK) ? PLAYBACK : IDLE; 540 541 #ifdef ENABLE_CIRRUS_DETECTION 542 if (handle.state == PLAYBACK) 543 (void)pthread_create(&handle.failure_detect_thread, 544 (const pthread_attr_t *) NULL, 545 audio_extn_cirrus_failure_detect_thread, 546 &handle); 547 #endif 548 549 ALOGV("%s: Exit", __func__); 550 551 pthread_exit(0); 552 return NULL; 553 } 554 555 #else 556 static void *audio_extn_cirrus_config_thread(void) { 557 struct audio_device *adev = handle.adev_handle; 558 struct crus_sp_ioctl_header header; 559 struct cirrus_cal_result_t result; 560 struct mixer_ctl *ctl_config = NULL; 561 FILE *cal_file = NULL; 562 int ret = 0, dev_file = -1; 563 564 ALOGI("%s: ++", __func__); 565 566 memset(&result, 0, sizeof(result)); 567 568 dev_file = open(CRUS_SP_FILE, O_RDWR | O_NONBLOCK); 569 if (dev_file < 0) { 570 ALOGE("%s: Failed to open Cirrus Playback IOCTL (%d)", 571 __func__, dev_file); 572 ret = -EINVAL; 573 goto exit; 574 } 575 576 cal_file = fopen(CRUS_CAL_FILE, "r"); 577 if (cal_file) { 578 ret = fread(&result, sizeof(result), 1, cal_file); 579 580 if (ret != 1) { 581 ALOGE("%s: Cirrus SP calibration file cannot be read , read size: %lu file error: %d", 582 __func__, (unsigned long)ret * sizeof(result), ferror(cal_file)); 583 ret = -EINVAL; 584 goto exit; 585 } 586 } 587 588 header.size = sizeof(header); 589 header.module_id = CRUS_MODULE_ID_TX; 590 header.param_id = 0; 591 header.data_length = sizeof(result); 592 header.data = &result; 593 594 ret = ioctl(dev_file, CRUS_SP_IOCTL_SET_CALIB, &header); 595 596 if (ret < 0) { 597 ALOGE("%s: Cirrus SP calibration IOCTL failure", __func__); 598 goto exit; 599 } 600 601 ctl_config = mixer_get_ctl_by_name(adev->mixer, 602 CRUS_SP_LOAD_CONF_MIXER); 603 if (!ctl_config) { 604 ALOGE("%s: Could not get ctl for mixer commands", __func__); 605 ret = -EINVAL; 606 goto exit; 607 } 608 609 ret = mixer_ctl_set_value(ctl_config, 0, 2); 610 if (ret < 0) { 611 ALOGE("%s load tx config failed", __func__); 612 goto exit; 613 } 614 615 ret = mixer_ctl_set_value(ctl_config, 0, 1); 616 if (ret < 0) { 617 ALOGE("%s load rx config failed", __func__); 618 goto exit; 619 } 620 621 ret = mixer_ctl_set_value(ctl_config, 0, 0); 622 if (ret < 0) { 623 ALOGE("%s set idle state failed", __func__); 624 goto exit; 625 } 626 627 exit: 628 if (dev_file >= 0) 629 close(dev_file); 630 if (cal_file) 631 fclose(cal_file); 632 633 ALOGI("%s: ret: %d --", __func__, ret); 634 return NULL; 635 } 636 #endif 637 638 #ifdef ENABLE_CIRRUS_DETECTION 639 void *audio_extn_cirrus_failure_detect_thread() { 640 struct audio_device *adev = handle.adev_handle; 641 struct crus_sp_ioctl_header header; 642 struct mixer_ctl *ctl = NULL; 643 const int32_t r_scale_factor = 100000000; 644 const int32_t t_scale_factor = 100000; 645 const int32_t r_err_range = 70000000; 646 const int32_t t_err_range = 210000; 647 const int32_t amp_factor = 71498; 648 const int32_t material = 250; 649 int32_t *buffer = NULL; 650 int ret = 0, dev_file = -1, out_cal0 = 0, out_cal1 = 0; 651 int rL = 0, rR = 0, zL = 0, zR = 0, tL = 0, tR = 0; 652 int rdL = 0, rdR = 0, tdL = 0, tdR = 0, ambL = 0, ambR = 0; 653 bool left_cal_done = false, right_cal_done = false; 654 bool det_en = false; 655 656 ALOGI("%s: Entry", __func__); 657 658 ctl = mixer_get_ctl_by_name(adev->mixer, CRUS_SP_FAIL_DET_MIXER); 659 det_en = mixer_ctl_get_value(ctl, 0); 660 661 if (!det_en) 662 goto exit; 663 664 dev_file = open(CRUS_SP_FILE, O_RDWR | O_NONBLOCK); 665 if (dev_file < 0) { 666 ALOGE("%s: Failed to open Cirrus Playback IOCTL (%d)", 667 __func__, dev_file); 668 goto exit; 669 } 670 671 buffer = calloc(1, CRUS_PARAM_TEMP_MAX_LENGTH); 672 if (!buffer) { 673 ALOGE("%s: allocate memory failed", __func__); 674 goto exit; 675 } 676 677 header.size = sizeof(header); 678 header.module_id = CRUS_MODULE_ID_RX; 679 header.param_id = CRUS_PARAM_RX_GET_TEMP; 680 header.data_length = CRUS_PARAM_TEMP_MAX_LENGTH; 681 header.data = buffer; 682 683 usleep(FAIL_DETECT_INIT_WAIT_US); 684 685 pthread_mutex_lock(&handle.fb_prot_mutex); 686 ret = ioctl(dev_file, CRUS_SP_IOCTL_GET, &header); 687 pthread_mutex_unlock(&handle.fb_prot_mutex); 688 if (ret < 0) { 689 ALOGE("%s: Cirrus SP IOCTL failure (%d)", 690 __func__, ret); 691 goto exit; 692 } 693 694 zL = buffer[2] * amp_factor; 695 zR = buffer[4] * amp_factor; 696 697 ambL = buffer[10]; 698 ambR = buffer[6]; 699 700 out_cal0 = buffer[12]; 701 out_cal1 = buffer[13]; 702 703 left_cal_done = (out_cal0 == 2) && (out_cal1 == 2) && 704 (buffer[2] != CRUS_DEFAULT_CAL_L); 705 706 out_cal0 = buffer[14]; 707 out_cal1 = buffer[15]; 708 709 right_cal_done = (out_cal0 == 2) && (out_cal1 == 2) && 710 (buffer[4] != CRUS_DEFAULT_CAL_R); 711 712 if (left_cal_done) { 713 ALOGI("%s: L Speaker Impedance: %d.%08d ohms", __func__, 714 zL / r_scale_factor, abs(zL) % r_scale_factor); 715 ALOGI("%s: L Calibration Temperature: %d C", __func__, ambL); 716 } else 717 ALOGE("%s: Left speaker uncalibrated", __func__); 718 719 if (right_cal_done) { 720 ALOGI("%s: R Speaker Impedance: %d.%08d ohms", __func__, 721 zR / r_scale_factor, abs(zR) % r_scale_factor); 722 ALOGI("%s: R Calibration Temperature: %d C", __func__, ambR); 723 } else 724 ALOGE("%s: Right speaker uncalibrated", __func__); 725 726 if (!left_cal_done && !right_cal_done) 727 goto exit; 728 729 ALOGI("%s: Monitoring speaker impedance & temperature...", __func__); 730 731 while ((handle.state == PLAYBACK) && det_en) { 732 pthread_mutex_lock(&handle.fb_prot_mutex); 733 ret = ioctl(dev_file, CRUS_SP_IOCTL_GET, &header); 734 pthread_mutex_unlock(&handle.fb_prot_mutex); 735 if (ret < 0) { 736 ALOGE("%s: Cirrus SP IOCTL failure (%d)", 737 __func__, ret); 738 goto loop; 739 } 740 741 rL = buffer[3]; 742 rR = buffer[1]; 743 744 zL = buffer[2]; 745 zR = buffer[4]; 746 747 if ((zL == 0) || (zR == 0)) 748 goto loop; 749 750 tdL = (material * t_scale_factor * (rL-zL) / zL); 751 tdR = (material * t_scale_factor * (rR-zR) / zR); 752 753 rL *= amp_factor; 754 rR *= amp_factor; 755 756 zL *= amp_factor; 757 zR *= amp_factor; 758 759 tL = tdL + (ambL * t_scale_factor); 760 tR = tdR + (ambR * t_scale_factor); 761 762 rdL = abs(zL - rL); 763 rdR = abs(zR - rR); 764 765 if (left_cal_done && (rL != 0) && (rdL > r_err_range)) 766 ALOGI("%s: Left speaker impedance out of range (%d.%08d ohms)", 767 __func__, rL / r_scale_factor, 768 abs(rL % r_scale_factor)); 769 770 if (right_cal_done && (rR != 0) && (rdR > r_err_range)) 771 ALOGI("%s: Right speaker impedance out of range (%d.%08d ohms)", 772 __func__, rR / r_scale_factor, 773 abs(rR % r_scale_factor)); 774 775 if (left_cal_done && (rL != 0) && (tdL > t_err_range)) 776 ALOGI("%s: Left speaker temperature out of range (%d.%05d C)", 777 __func__, tL / t_scale_factor, 778 abs(tL % t_scale_factor)); 779 780 if (right_cal_done && (rR != 0) && (tdR > t_err_range)) 781 ALOGI("%s: Right speaker temperature out of range (%d.%05d C)", 782 __func__, tR / t_scale_factor, 783 abs(tR % t_scale_factor)); 784 785 loop: 786 det_en = mixer_ctl_get_value(ctl, 0); 787 usleep(FAIL_DETECT_LOOP_WAIT_US); 788 } 789 790 exit: 791 if (dev_file >= 0) 792 close(dev_file); 793 free(buffer); 794 ALOGI("%s: Exit ", __func__); 795 796 pthread_exit(0); 797 return NULL; 798 } 799 #endif 800 801 int audio_extn_spkr_prot_start_processing(snd_device_t snd_device) { 802 struct audio_usecase *uc_info_tx; 803 struct audio_device *adev = handle.adev_handle; 804 int32_t pcm_dev_tx_id = -1, ret = 0; 805 806 ALOGV("%s: Entry", __func__); 807 808 if (!adev) { 809 ALOGE("%s: Invalid params", __func__); 810 return -EINVAL; 811 } 812 813 uc_info_tx = (struct audio_usecase *)calloc(1, sizeof(*uc_info_tx)); 814 if (!uc_info_tx) { 815 ALOGE("%s: allocate memory failed", __func__); 816 return -ENOMEM; 817 } 818 819 audio_route_apply_and_update_path(adev->audio_route, 820 platform_get_snd_device_name(snd_device)); 821 822 pthread_mutex_lock(&handle.fb_prot_mutex); 823 uc_info_tx->id = USECASE_AUDIO_SPKR_CALIB_TX; 824 uc_info_tx->type = PCM_CAPTURE; 825 uc_info_tx->in_snd_device = SND_DEVICE_IN_CAPTURE_VI_FEEDBACK; 826 uc_info_tx->out_snd_device = SND_DEVICE_NONE; 827 handle.pcm_tx = NULL; 828 829 list_add_tail(&adev->usecase_list, &uc_info_tx->list); 830 831 enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK); 832 enable_audio_route(adev, uc_info_tx); 833 834 pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE); 835 836 if (pcm_dev_tx_id < 0) { 837 ALOGE("%s: Invalid pcm device for usecase (%d)", 838 __func__, uc_info_tx->id); 839 ret = -ENODEV; 840 goto exit; 841 } 842 843 handle.pcm_tx = pcm_open(adev->snd_card, 844 pcm_dev_tx_id, 845 PCM_IN, &pcm_config_cirrus_tx); 846 847 if (handle.pcm_tx && !pcm_is_ready(handle.pcm_tx)) { 848 ALOGE("%s: PCM device not ready: %s", __func__, pcm_get_error(handle.pcm_tx)); 849 ret = -EIO; 850 goto exit; 851 } 852 853 if (pcm_start(handle.pcm_tx) < 0) { 854 ALOGE("%s: pcm start for TX failed; error = %s", __func__, 855 pcm_get_error(handle.pcm_tx)); 856 ret = -EINVAL; 857 goto exit; 858 } 859 860 #ifdef ENABLE_CIRRUS_DETECTION 861 if (handle.state == IDLE) 862 (void)pthread_create(&handle.failure_detect_thread, 863 (const pthread_attr_t *) NULL, 864 audio_extn_cirrus_failure_detect_thread, 865 &handle); 866 #endif 867 868 handle.state = PLAYBACK; 869 exit: 870 if (ret) { 871 handle.state = IDLE; 872 if (handle.pcm_tx) { 873 ALOGI("%s: pcm_tx_close", __func__); 874 pcm_close(handle.pcm_tx); 875 handle.pcm_tx = NULL; 876 } 877 878 disable_audio_route(adev, uc_info_tx); 879 disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK); 880 list_remove(&uc_info_tx->list); 881 free(uc_info_tx); 882 } 883 884 pthread_mutex_unlock(&handle.fb_prot_mutex); 885 ALOGV("%s: Exit", __func__); 886 return ret; 887 } 888 889 void audio_extn_spkr_prot_stop_processing(snd_device_t snd_device) { 890 struct audio_usecase *uc_info_tx; 891 struct audio_device *adev = handle.adev_handle; 892 893 ALOGV("%s: Entry", __func__); 894 895 pthread_mutex_lock(&handle.fb_prot_mutex); 896 897 handle.state = IDLE; 898 uc_info_tx = get_usecase_from_list(adev, USECASE_AUDIO_SPKR_CALIB_TX); 899 900 if (uc_info_tx) { 901 if (handle.pcm_tx) { 902 ALOGI("%s: pcm_tx_close", __func__); 903 pcm_close(handle.pcm_tx); 904 handle.pcm_tx = NULL; 905 } 906 907 disable_audio_route(adev, uc_info_tx); 908 disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK); 909 list_remove(&uc_info_tx->list); 910 free(uc_info_tx); 911 912 audio_route_reset_path(adev->audio_route, 913 platform_get_snd_device_name(snd_device)); 914 } 915 916 pthread_mutex_unlock(&handle.fb_prot_mutex); 917 918 ALOGV("%s: Exit", __func__); 919 } 920 921 bool audio_extn_spkr_prot_is_enabled() { 922 return true; 923 } 924 925 int audio_extn_get_spkr_prot_snd_device(snd_device_t snd_device) { 926 switch(snd_device) { 927 case SND_DEVICE_OUT_SPEAKER: 928 case SND_DEVICE_OUT_SPEAKER_REVERSE: 929 return SND_DEVICE_OUT_SPEAKER_PROTECTED; 930 case SND_DEVICE_OUT_SPEAKER_SAFE: 931 return SND_DEVICE_OUT_SPEAKER_SAFE; 932 case SND_DEVICE_OUT_VOICE_SPEAKER: 933 return SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED; 934 default: 935 return snd_device; 936 } 937 } 938 939 void audio_extn_spkr_prot_calib_cancel(__unused void *adev) { 940 // FIXME: wait or cancel audio_extn_cirrus_run_calibration 941 } 942