blob: 8618d41a5bdb54c38ad0dea28df4a0e6c230ef94 [file] [log] [blame]
wei.wang1e45cfd32023-07-10 08:33:46 +00001/*
2 * Copyright (C) 2023 Amlogic Corporation.
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#define LOG_TAG "AML_Audio_Setting"
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <stdint.h>
21#include <string.h>
22#include <unistd.h>
23#include <fcntl.h>
24#include <errno.h>
25#include <ctype.h>
26#include <poll.h>
27#include <sys/ioctl.h>
28#include <pthread.h>
29#include <linux/ioctl.h>
30#define __force
31#define __bitwise
32#define __user
33#include <sound/asound.h>
34#include "AML_Audio_Setting.h"
35#include <cutils/log.h>
36
37#ifndef SNDRV_CTL_ELEM_ID_NAME_MAXLEN
38#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN 44
39#endif
40#define DEFAULT_AML_SOUND_CARD 0
41/* TLV header size*/
42#define TLV_HEADER_SIZE (2 * sizeof(unsigned int))
43
44#define TDMB_GAIN "TDMOUT_B Software Gain"
wei.wang158743372023-08-07 08:07:05 +000045#define TDMA_GAIN "TDMOUT_A Software Gain"
46#define AML_CHIP_ID "AML chip id"
47#define AML_CHIP_ID_S1A 69
wei.wang1e45cfd32023-07-10 08:33:46 +000048#define HDMI_OUT_MUTE "Audio hdmi-out mute"
49#define DAC_DIGITAL_VOLUME "DAC Digital Playback Volume"
haiyang.renfdc144e2023-09-01 02:55:50 +000050#define DIGITAL_MODE "Audio Digital Mode"
haiyang.ren936bfc52023-09-18 05:46:24 +000051#define DRC_CONTROL "Audio DRC Control"
yuliang.huf4792d52023-09-19 10:14:14 +000052#define HDMI_CON "Audio Output Select"
haiyang.ren85627e82024-02-26 11:16:42 +000053#define SPDIF_FORMAT "Audio spdif format"
wei.wang1e45cfd32023-07-10 08:33:46 +000054#define DAC_DIGITAl_DEFAULT_VOLUME (251)
55#define HEADPHONE_DAC_CHANNEL_NUM (2)
56
haiyang.ren936bfc52023-09-18 05:46:24 +000057#define DRC_MODE_LINE 2
58#define DRC_MODE_RF 3
59#define DRC_MODE_BIT 0
60#define DRC_HIGH_CUT_BIT 3
61#define DRC_LOW_BST_BIT 16
62
wei.wang1e45cfd32023-07-10 08:33:46 +000063extern "C" {
64
65struct mixer_ctl {
66 struct mixer *mixer;
67 struct snd_ctl_elem_info *info;
68 char **ename;
69 bool info_retrieved;
70};
71
72struct mixer {
73 int fd;
74 struct snd_ctl_card_info card_info;
75 struct snd_ctl_elem_info *elem_info;
76 struct mixer_ctl *ctl;
77 unsigned int count;
78};
79
80/* Mixer control types */
81enum mixer_ctl_type {
82 MIXER_CTL_TYPE_BOOL,
83 MIXER_CTL_TYPE_INT,
84 MIXER_CTL_TYPE_ENUM,
85 MIXER_CTL_TYPE_BYTE,
86 MIXER_CTL_TYPE_IEC958,
87 MIXER_CTL_TYPE_INT64,
88 MIXER_CTL_TYPE_UNKNOWN,
89
90 MIXER_CTL_TYPE_MAX,
91};
92
93static pthread_mutex_t g_volume_lock = PTHREAD_MUTEX_INITIALIZER;
94static pthread_mutex_t g_mute_lock = PTHREAD_MUTEX_INITIALIZER;
haiyang.ren49ae2c82023-11-02 09:31:41 +000095static int reserved_volume = 30;
wei.wang158743372023-08-07 08:07:05 +000096static int chip_id = 0;
wei.wang1e45cfd32023-07-10 08:33:46 +000097
98static void _mixer_close(struct mixer *mixer)
99{
100 unsigned int n,m;
101
102 if (!mixer)
103 return;
104
105 if (mixer->fd >= 0)
106 close(mixer->fd);
107
108 if (mixer->ctl) {
109 for (n = 0; n < mixer->count; n++) {
110 if (mixer->ctl[n].ename) {
111 unsigned int max = mixer->ctl[n].info->value.enumerated.items;
112 for (m = 0; m < max; m++)
113 free(mixer->ctl[n].ename[m]);
114 free(mixer->ctl[n].ename);
115 }
116 }
117 free(mixer->ctl);
118 }
119
120 if (mixer->elem_info)
121 free(mixer->elem_info);
122
123 free(mixer);
124
125 /* TODO: verify frees */
126}
127
128static struct mixer *_mixer_open(unsigned int card)
129{
130 struct snd_ctl_elem_list elist;
131 struct snd_ctl_elem_id *eid = NULL;
132 struct mixer *mixer = NULL;
133 unsigned int n;
134 int fd;
135 char fn[256];
136
137 snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card);
138 fd = open(fn, O_RDWR);
139 if (fd < 0)
140 return 0;
141
142 memset(&elist, 0, sizeof(elist));
143 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
144 goto fail;
145
146 mixer = (struct mixer *)calloc(1, sizeof(*mixer));
147 if (!mixer)
148 goto fail;
149
150 mixer->ctl = (struct mixer_ctl *)calloc(elist.count, sizeof(struct mixer_ctl));
151 mixer->elem_info = (struct snd_ctl_elem_info *)calloc(elist.count, sizeof(struct snd_ctl_elem_info));
152 if (!mixer->ctl || !mixer->elem_info)
153 goto fail;
154
155 if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0)
156 goto fail;
157
158 eid = (struct snd_ctl_elem_id *)calloc(elist.count, sizeof(struct snd_ctl_elem_id));
159 if (!eid)
160 goto fail;
161
162 mixer->count = elist.count;
163 mixer->fd = fd;
164 elist.space = mixer->count;
165 elist.pids = eid;
166 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
167 goto fail;
168
169 for (n = 0; n < mixer->count; n++) {
170 struct mixer_ctl *ctl = mixer->ctl + n;
171
172 ctl->mixer = mixer;
173 ctl->info = mixer->elem_info + n;
174 ctl->info->id.numid = eid[n].numid;
175 strncpy((char *)ctl->info->id.name, (char *)eid[n].name,
176 SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
177 ctl->info->id.name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
178 }
179
180 free(eid);
181 return mixer;
182
183fail:
184 /* TODO: verify frees in failure case */
185 if (eid)
186 free(eid);
187 if (mixer)
188 _mixer_close(mixer);
189 else if (fd >= 0)
190 close(fd);
191 return 0;
192}
193
194static bool _mixer_ctl_get_elem_info(struct mixer_ctl* ctl)
195{
196 if (!ctl->info_retrieved) {
197 if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info) < 0)
198 return false;
199 ctl->info_retrieved = true;
200 }
201
202 if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED || ctl->ename)
203 return true;
204
205 struct snd_ctl_elem_info tmp;
206 char** enames = (char**)calloc(ctl->info->value.enumerated.items, sizeof(char*));
207 if (!enames)
208 return false;
209
210 for (unsigned int i = 0; i < ctl->info->value.enumerated.items; i++) {
211 memset(&tmp, 0, sizeof(tmp));
212 tmp.id.numid = ctl->info->id.numid;
213 tmp.value.enumerated.item = i;
214 if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
215 goto fail;
216 enames[i] = strdup(tmp.value.enumerated.name);
217 if (!enames[i])
218 goto fail;
219 }
220 ctl->ename = enames;
221 return true;
222
223fail:
224 free(enames);
225 return false;
226}
227
228static const char *_mixer_get_name(struct mixer *mixer)
229{
230 return (const char *)mixer->card_info.name;
231}
232
233static unsigned int _mixer_get_num_ctls(struct mixer *mixer)
234{
235 if (!mixer)
236 return 0;
237
238 return mixer->count;
239}
240
241static struct mixer_ctl *_mixer_get_ctl(struct mixer *mixer, unsigned int id)
242{
243 struct mixer_ctl *ctl;
244
245 if (!mixer || (id >= mixer->count))
246 return NULL;
247
248 ctl = mixer->ctl + id;
249 if (!_mixer_ctl_get_elem_info(ctl))
250 return NULL;
251
252 return ctl;
253}
254
255static struct mixer_ctl *_mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
256{
257 unsigned int n;
258
259 if (!mixer)
260 return NULL;
261
262 for (n = 0; n < mixer->count; n++)
263 if (!strcmp(name, (char*) mixer->elem_info[n].id.name))
264 return _mixer_get_ctl(mixer, n);
265
266 return NULL;
267}
268
269static void _mixer_ctl_update(struct mixer_ctl *ctl)
270{
271 ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info);
272}
273
274static const char *_mixer_ctl_get_name(struct mixer_ctl *ctl)
275{
276 if (!ctl)
277 return NULL;
278
279 return (const char *)ctl->info->id.name;
280}
281
282static enum mixer_ctl_type _mixer_ctl_get_type(struct mixer_ctl *ctl)
283{
284 if (!ctl)
285 return MIXER_CTL_TYPE_UNKNOWN;
286
287 switch (ctl->info->type) {
288 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL;
289 case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT;
290 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM;
291 case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE;
292 case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958;
293 case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64;
294 default: return MIXER_CTL_TYPE_UNKNOWN;
295 };
296}
297
298static const char *_mixer_ctl_get_type_string(struct mixer_ctl *ctl)
299{
300 if (!ctl)
301 return "";
302
303 switch (ctl->info->type) {
304 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
305 case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT";
306 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
307 case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE";
308 case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
309 case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
310 default: return "Unknown";
311 };
312}
313
314static unsigned int _mixer_ctl_get_num_values(struct mixer_ctl *ctl)
315{
316 if (!ctl)
317 return 0;
318
319 return ctl->info->count;
320}
321
322static int percent_to_int(struct snd_ctl_elem_info *ei, int percent)
323{
324 int range;
325
326 if (percent > 100)
327 percent = 100;
328 else if (percent < 0)
329 percent = 0;
330
331 range = (ei->value.integer.max - ei->value.integer.min);
332
333 return ei->value.integer.min + (range * percent) / 100;
334}
335
336static int int_to_percent(struct snd_ctl_elem_info *ei, int value)
337{
338 int range = (ei->value.integer.max - ei->value.integer.min);
339
340 if (range == 0)
341 return 0;
342
343 return ((value - ei->value.integer.min) / range) * 100;
344}
345
346static int _mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
347{
348 struct snd_ctl_elem_value ev;
349 int ret;
350
351 if (!ctl || (id >= ctl->info->count))
352 return -EINVAL;
353
354 memset(&ev, 0, sizeof(ev));
355 ev.id.numid = ctl->info->id.numid;
356 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
357 if (ret < 0)
358 return ret;
359
360 switch (ctl->info->type) {
361 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
362 ev.value.integer.value[id] = !!value;
363 break;
364
365 case SNDRV_CTL_ELEM_TYPE_INTEGER:
366 ev.value.integer.value[id] = value;
367 break;
368
369 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
370 ev.value.enumerated.item[id] = value;
371 break;
372
373 case SNDRV_CTL_ELEM_TYPE_BYTES:
374 ev.value.bytes.data[id] = value;
375 break;
376
377 default:
378 return -EINVAL;
379 }
380
381 return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
382}
383
384static int _mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id)
385{
386 struct snd_ctl_elem_value ev;
387 int ret;
388
389 if (!ctl || (id >= ctl->info->count))
390 return -EINVAL;
391
392 memset(&ev, 0, sizeof(ev));
393 ev.id.numid = ctl->info->id.numid;
394 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
395 if (ret < 0)
396 return ret;
397
398 switch (ctl->info->type) {
399 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
400 return !!ev.value.integer.value[id];
401
402 case SNDRV_CTL_ELEM_TYPE_INTEGER:
403 return ev.value.integer.value[id];
404
405 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
406 return ev.value.enumerated.item[id];
407
408 case SNDRV_CTL_ELEM_TYPE_BYTES:
409 return ev.value.bytes.data[id];
410
411 default:
412 return -EINVAL;
413 }
414
415 return 0;
416}
417
418static int _mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id)
419{
420 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
421 return -EINVAL;
422
423 return int_to_percent(ctl->info, _mixer_ctl_get_value(ctl, id));
424}
425
426static int _mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent)
427{
428 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
429 return -EINVAL;
430
431 return _mixer_ctl_set_value(ctl, id, percent_to_int(ctl->info, percent));
432}
433
434static int _mixer_ctl_is_access_tlv_rw(struct mixer_ctl *ctl)
435{
436 return (ctl->info->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE);
437}
438
439static int _mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count)
440{
441 struct snd_ctl_elem_value ev;
442 int ret = 0;
443 size_t size;
444 void *source;
445 size_t total_count;
446
447 if ((!ctl) || !count || !array)
448 return -EINVAL;
449
450 total_count = ctl->info->count;
451
452 if ((ctl->info->type == SNDRV_CTL_ELEM_TYPE_BYTES) &&
453 _mixer_ctl_is_access_tlv_rw(ctl)) {
454 /* Additional two words is for the TLV header */
455 total_count += TLV_HEADER_SIZE;
456 }
457
458 if (count > total_count)
459 return -EINVAL;
460
461 memset(&ev, 0, sizeof(ev));
462 ev.id.numid = ctl->info->id.numid;
463
464 switch (ctl->info->type) {
465 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
466 case SNDRV_CTL_ELEM_TYPE_INTEGER:
467 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
468 if (ret < 0)
469 return ret;
470 size = sizeof(ev.value.integer.value[0]);
471 source = ev.value.integer.value;
472 break;
473
474 case SNDRV_CTL_ELEM_TYPE_BYTES:
475 /* check if this is new bytes TLV */
476 if (_mixer_ctl_is_access_tlv_rw(ctl)) {
477 struct snd_ctl_tlv *tlv;
478 int ret;
479
480 if (count > SIZE_MAX - sizeof(*tlv))
481 return -EINVAL;
482 tlv = (struct snd_ctl_tlv *)calloc(1, sizeof(*tlv) + count);
483 if (!tlv)
484 return -ENOMEM;
485 tlv->numid = ctl->info->id.numid;
486 tlv->length = count;
487 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_READ, tlv);
488
489 source = tlv->tlv;
490 memcpy(array, source, count);
491
492 free(tlv);
493
494 return ret;
495 } else {
496 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
497 if (ret < 0)
498 return ret;
499 size = sizeof(ev.value.bytes.data[0]);
500 source = ev.value.bytes.data;
501 break;
502 }
503
504 case SNDRV_CTL_ELEM_TYPE_IEC958:
505 size = sizeof(ev.value.iec958);
506 source = &ev.value.iec958;
507 break;
508
509 default:
510 return -EINVAL;
511 }
512
513 memcpy(array, source, size * count);
514
515 return 0;
516}
517
518static int _mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count)
519{
520 struct snd_ctl_elem_value ev;
521 size_t size;
522 void *dest;
523 size_t total_count;
524
525 if ((!ctl) || !count || !array)
526 return -EINVAL;
527
528 total_count = ctl->info->count;
529
530 if ((ctl->info->type == SNDRV_CTL_ELEM_TYPE_BYTES) &&
531 _mixer_ctl_is_access_tlv_rw(ctl)) {
532 /* Additional two words is for the TLV header */
533 total_count += TLV_HEADER_SIZE;
534 }
535
536 if (count > total_count)
537 return -EINVAL;
538
539 memset(&ev, 0, sizeof(ev));
540 ev.id.numid = ctl->info->id.numid;
541
542 switch (ctl->info->type) {
543 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
544 case SNDRV_CTL_ELEM_TYPE_INTEGER:
545 size = sizeof(ev.value.integer.value[0]);
546 dest = ev.value.integer.value;
547 break;
548
549 case SNDRV_CTL_ELEM_TYPE_BYTES:
550 /* check if this is new bytes TLV */
551 if (_mixer_ctl_is_access_tlv_rw(ctl)) {
552 struct snd_ctl_tlv *tlv;
553 int ret = 0;
554 if (count > SIZE_MAX - sizeof(*tlv))
555 return -EINVAL;
556 tlv = (struct snd_ctl_tlv *)calloc(1, sizeof(*tlv) + count);
557 if (!tlv)
558 return -ENOMEM;
559 tlv->numid = ctl->info->id.numid;
560 tlv->length = count;
561 memcpy(tlv->tlv, array, count);
562
563 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_WRITE, tlv);
564 free(tlv);
565
566 return ret;
567 } else {
568 size = sizeof(ev.value.bytes.data[0]);
569 dest = ev.value.bytes.data;
570 }
571 break;
572
573 case SNDRV_CTL_ELEM_TYPE_IEC958:
574 size = sizeof(ev.value.iec958);
575 dest = &ev.value.iec958;
576 break;
577
578 default:
579 return -EINVAL;
580 }
581
582 memcpy(dest, array, size * count);
583
584 return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
585}
586
587static int _mixer_ctl_get_range_min(struct mixer_ctl *ctl)
588{
589 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
590 return -EINVAL;
591
592 return ctl->info->value.integer.min;
593}
594
595static int _mixer_ctl_get_range_max(struct mixer_ctl *ctl)
596{
597 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
598 return -EINVAL;
599
600 return ctl->info->value.integer.max;
601}
602
603static unsigned int _mixer_ctl_get_num_enums(struct mixer_ctl *ctl)
604{
605 if (!ctl)
606 return 0;
607
608 return ctl->info->value.enumerated.items;
609}
610
611static const char *_mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
612 unsigned int enum_id)
613{
614 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
615 (enum_id >= ctl->info->value.enumerated.items))
616 return NULL;
617
618 return (const char *)ctl->ename[enum_id];
619}
620
621static int _mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string)
622{
623 unsigned int i, num_enums;
624 struct snd_ctl_elem_value ev;
625 int ret;
626
627 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED))
628 return -EINVAL;
629
630 num_enums = ctl->info->value.enumerated.items;
631 for (i = 0; i < num_enums; i++) {
632 if (!strcmp(string, ctl->ename[i])) {
633 memset(&ev, 0, sizeof(ev));
634 ev.value.enumerated.item[0] = i;
635 ev.id.numid = ctl->info->id.numid;
636 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
637 if (ret < 0)
638 return ret;
639 return 0;
640 }
641 }
642
643 return -EINVAL;
644}
645
646static int aml_audio_mixer_int(const char *control, int value, bool set)
647{
648 int ret = -1;
649 struct mixer_ctl *pCtrl = NULL;
650 struct mixer *mixer = NULL;
651 if (control == NULL) {
652 ALOGE("[%s:%d] control is invalid!\n", __FUNCTION__, __LINE__);
653 return ret;
654 }
655 mixer = _mixer_open(DEFAULT_AML_SOUND_CARD);
656
657 if (mixer == NULL) {
658 ALOGE("[%s:%d] mixer is invalid!\n", __FUNCTION__, __LINE__);
659 return ret;
660 }
661
662 pCtrl = _mixer_get_ctl_by_name(mixer, control);
663 if (pCtrl == NULL) {
664 ALOGE("[%s:%d] Failed to find control: %s\n", __FUNCTION__, __LINE__, control);
665 _mixer_close(mixer);
666 return ret;
667 }
668 if (set) {
669 ret = _mixer_ctl_set_value(pCtrl, 0, value);
670 ALOGV("[%s:%d] set %s: %d, ret %d", __FUNCTION__, __LINE__, control, value, ret);
671 } else {
672 ret = _mixer_ctl_get_value(pCtrl, 0);
673 }
674 _mixer_close(mixer);
675
676 return ret;
677}
678
679static int aml_audio_mixer_array(const char *control, void *array, size_t count, bool set)
680{
681 int ret = -1;
682 struct mixer_ctl *pCtrl = NULL;
683 struct mixer *mixer = NULL;
684 if (control == NULL) {
685 ALOGE("[%s:%d] control is invalid!\n", __FUNCTION__, __LINE__);
686 return ret;
687 }
688 mixer = _mixer_open(DEFAULT_AML_SOUND_CARD);
689
690 if (mixer == NULL) {
691 ALOGE("[%s:%d] mixer is invalid!\n", __FUNCTION__, __LINE__);
692 return ret;
693 }
694
695 pCtrl = _mixer_get_ctl_by_name(mixer, control);
696 if (pCtrl == NULL) {
697 ALOGE("[%s:%d] Failed to find control: %s\n", __FUNCTION__, __LINE__, control);
698 _mixer_close(mixer);
699 return ret;
700 }
701 if (set) {
702 ret = _mixer_ctl_set_array(pCtrl, array, count);
703 ALOGV("[%s:%d] set %s, ret %d", __FUNCTION__, __LINE__, control, ret);
704 } else {
705 ret = _mixer_ctl_get_array(pCtrl, array, count);
706 }
707 _mixer_close(mixer);
708
709 return ret;
710}
711
712/* Headphone mute */
713static int set_dac_digital_mute(bool mute)
714{
715 int ret = 0;
716 static bool last_mute_state = false;
717 static int dac_digital_volume = DAC_DIGITAl_DEFAULT_VOLUME; // volume range: 0 ~ 255
718 int headphone_dac_gain[HEADPHONE_DAC_CHANNEL_NUM] = {dac_digital_volume, dac_digital_volume};
719
720 if (last_mute_state == mute) {
721 return ret;
722 }
723 if (mute) {
724 dac_digital_volume = aml_audio_mixer_int(DAC_DIGITAL_VOLUME, 0, false);//get current hp vol
725 headphone_dac_gain[0] = headphone_dac_gain[1] = 0;
726 ret = aml_audio_mixer_array(DAC_DIGITAL_VOLUME, headphone_dac_gain, HEADPHONE_DAC_CHANNEL_NUM, true);
727 } else {
728 //headphone_dac_gain[0] = headphone_dac_gain[1] = dac_digital_volume;
729 ret = aml_audio_mixer_array(DAC_DIGITAL_VOLUME, headphone_dac_gain, HEADPHONE_DAC_CHANNEL_NUM, true);
730 }
731 last_mute_state = mute;
732 ALOGD("[%s:%d] DAC Digital %smute, dac_digital_volume is %d", __func__, __LINE__, mute?" ":"un", dac_digital_volume);
733 return ret;
734}
735
yuliang.huf4792d52023-09-19 10:14:14 +0000736int aml_audio_set_hdmi_param(bool isconnect)
737{
738 int ret = 0;
739 pthread_mutex_lock(&g_volume_lock);
740 chip_id = aml_audio_mixer_int(AML_CHIP_ID, 0, false);
741 /*s1a use this way to set hdmi status*/
742 if (AML_CHIP_ID_S1A == chip_id) {
743 ret = aml_audio_mixer_int(HDMI_CON, isconnect, true);
744 ALOGD("[%s:%d] isconnect: %d, ret: %d", __func__, __LINE__, isconnect, ret);
745 }
746 pthread_mutex_unlock(&g_volume_lock);
747 return ret;
748}
749
wei.wang1e45cfd32023-07-10 08:33:46 +0000750int aml_audio_set_volume(int value)
751{
752 int ret = 0;
753 if (value < 0 || value > 100) {
754 ALOGE("[%s:%d]bad volume: %d", __func__, __LINE__, value);
755 return -1;
756 }
757
758 pthread_mutex_lock(&g_volume_lock);
wei.wang158743372023-08-07 08:07:05 +0000759 chip_id = aml_audio_mixer_int(AML_CHIP_ID, 0, false);
haiyang.ren603e5892024-08-13 09:31:50 +0000760 reserved_volume = value;
wei.wang158743372023-08-07 08:07:05 +0000761 /*s1a use TDM-A as cvbs/hdmi_tx samesource*/
762 if (AML_CHIP_ID_S1A == chip_id)
763 ret = aml_audio_mixer_int(TDMA_GAIN, value, true);
764 else
765 ret = aml_audio_mixer_int(TDMB_GAIN, value, true);
766
767 ALOGD("[%s:%d] chip_id: %d, volume: %d, ret: %d", __func__, __LINE__, chip_id, value, ret);
wei.wang1e45cfd32023-07-10 08:33:46 +0000768 pthread_mutex_unlock(&g_volume_lock);
769
770 return ret;
771}
772
773int aml_audio_get_volume()
774{
775 pthread_mutex_lock(&g_volume_lock);
776 int ret = 0;
haiyang.renf9cfa202024-04-07 09:26:30 +0000777 chip_id = aml_audio_mixer_int(AML_CHIP_ID, 0, false);
wei.wang158743372023-08-07 08:07:05 +0000778 if (AML_CHIP_ID_S1A == chip_id)
779 ret = aml_audio_mixer_int(TDMA_GAIN, 0, false);
780 else
781 ret = aml_audio_mixer_int(TDMB_GAIN, 0, false);
782 ALOGD("[%s:%d] chip_id: %d, volume: %d", __func__, __LINE__, chip_id, ret);
wei.wang1e45cfd32023-07-10 08:33:46 +0000783 pthread_mutex_unlock(&g_volume_lock);
784
785 return ret;
786}
787
788int aml_audio_set_mute(int port, bool mute)
789{
790 pthread_mutex_lock(&g_mute_lock);
791 int ret = -1;
792 if (port <= AUDIO_PORT_MIN || port >= AUDIO_PORT_MAX) {
793 ALOGE("[%s:%d]bad port: %d", __func__, __LINE__, port);
794 } else if (port == AUDIO_PORT_HDMI) {
haiyang.ren85627e82024-02-26 11:16:42 +0000795 if (aml_audio_get_spdif_format() == AUD_CODEC_TYPE_STEREO_PCM) {
796 if (mute && !(aml_audio_get_volume() == 0)) {
797 reserved_volume = aml_audio_get_volume();
798 ret = aml_audio_set_volume(0);
799 } else if (!mute) {
800 ret = aml_audio_set_volume(reserved_volume);
801 }
802 } else {
803 ret = aml_audio_mixer_int(HDMI_OUT_MUTE, mute ? 1 : 0, true);
haiyang.ren49ae2c82023-11-02 09:31:41 +0000804 }
wei.wang1e45cfd32023-07-10 08:33:46 +0000805 } else if (port == AUDIO_PORT_HEADPHONE) {
806 ret = set_dac_digital_mute(mute);
807 }
808 ALOGD("[%s:%d] port: %d, mute: %d, ret: %d", __func__, __LINE__, port, mute, ret);
809 pthread_mutex_unlock(&g_mute_lock);
810 return ret;
811}
812
813bool aml_audio_get_mute(int port)
814{
815 pthread_mutex_lock(&g_mute_lock);
816 bool ret = false;
817 if (port <= AUDIO_PORT_MIN || port >= AUDIO_PORT_MAX) {
818 ALOGE("[%s:%d]bad port: %d", __func__, __LINE__, port);
819 } else if (port == AUDIO_PORT_HDMI) {
haiyang.ren85627e82024-02-26 11:16:42 +0000820 if (aml_audio_get_spdif_format() == AUD_CODEC_TYPE_STEREO_PCM) {
821 ret = (aml_audio_get_volume() == 0) ? true : false;
822 } else {
823 ret = aml_audio_mixer_int(HDMI_OUT_MUTE, 0, false) ? true : false;
824 }
wei.wang1e45cfd32023-07-10 08:33:46 +0000825 } else if (port == AUDIO_PORT_HEADPHONE) {
826 ret = aml_audio_mixer_int(DAC_DIGITAL_VOLUME, 0, false) ? false : true;
827 }
828 ALOGD("[%s:%d] port: %d, mute: %d", __func__, __LINE__, port, ret);
829 pthread_mutex_unlock(&g_mute_lock);
830 return ret;
831}
832
haiyang.ren936bfc52023-09-18 05:46:24 +0000833int aml_audio_set_digital_mode(enum audio_digital_mode mode)
834{
835 int ret = 0;
836 if ((mode != AML_HAL_PCM) && (mode != AML_HAL_DDP) &&
837 (mode != AML_HAL_AUTO) && (mode != AML_HAL_BYPASS) &&
838 (mode != AML_HAL_DD)) {
839 printf("Invalid mode\n");
840 return false;
haiyang.renfdc144e2023-09-01 02:55:50 +0000841 }
842
haiyang.ren936bfc52023-09-18 05:46:24 +0000843 pthread_mutex_lock(&g_volume_lock);
844 ret = aml_audio_mixer_int(DIGITAL_MODE, mode, true);
845 ALOGD("[%s:%d] mode: %d, ret: %d", __func__, __LINE__, mode, ret);
846 pthread_mutex_unlock(&g_volume_lock);
haiyang.renfdc144e2023-09-01 02:55:50 +0000847
haiyang.ren936bfc52023-09-18 05:46:24 +0000848 return ret;
849}
850
851int aml_audio_get_digital_mode()
852{
853 pthread_mutex_lock(&g_volume_lock);
854 int ret = 0;
855 ret = aml_audio_mixer_int(DIGITAL_MODE, 0, false);
856 ALOGD("[%s:%d] mod: %d", __func__, __LINE__, ret);
857 pthread_mutex_unlock(&g_volume_lock);
858
859 return ret;
860}
861
862int aml_audio_set_drc_mode(enum audio_drc_mode mode)
863{
864 int ret = 0;
865 int drc_control = DRC_MODE_LINE;
866 if ((mode != DRC_RF) && (mode != DRC_LINE) && (mode != DRC_OFF)) {
867 printf("Invalid mode!\n");
868 return false;
haiyang.renfdc144e2023-09-01 02:55:50 +0000869 }
870
haiyang.ren936bfc52023-09-18 05:46:24 +0000871 pthread_mutex_lock(&g_volume_lock);
872 if (mode == DRC_LINE) {
873 drc_control = (DRC_MODE_LINE<<DRC_MODE_BIT)|(100<<DRC_HIGH_CUT_BIT)|(100<<DRC_LOW_BST_BIT);
874 } else if (mode == DRC_RF) {
875 drc_control = (DRC_MODE_RF<<DRC_MODE_BIT)|(100<<DRC_HIGH_CUT_BIT)|(100<<DRC_LOW_BST_BIT);
876 }
877 ret = aml_audio_mixer_int(DRC_CONTROL, drc_control, true);
878 ALOGD("[%s:%d] mode: %d, drc_control: %#x, ret: %d.", __func__, __LINE__, mode, drc_control, ret);
879 pthread_mutex_unlock(&g_volume_lock);
880
881 return ret;
882}
883
884int aml_audio_get_drc_mode()
885{
886 pthread_mutex_lock(&g_volume_lock);
887 int ret = 0, drc_control;
888 drc_control = aml_audio_mixer_int(DRC_CONTROL, 0, false);
889
890 if (drc_control == DRC_MODE_LINE)
891 ret = DRC_OFF;
892 else
893 ret = (drc_control&3 == DRC_MODE_LINE) ? DRC_LINE : DRC_RF;
894 ALOGD("[%s:%d] mode: %d", __func__, __LINE__, ret);
895 pthread_mutex_unlock(&g_volume_lock);
896
897 return ret;
898}
haiyang.ren85627e82024-02-26 11:16:42 +0000899
900int aml_audio_get_spdif_format()
901{
902 pthread_mutex_lock(&g_volume_lock);
903 int ret = 0;
904 ret = aml_audio_mixer_int(SPDIF_FORMAT, 0, false);
905 ALOGD("[%s:%d] ret: %x.", __func__, __LINE__, ret);
906 pthread_mutex_unlock(&g_volume_lock);
907
908 return ret;
909}
wei.wang1e45cfd32023-07-10 08:33:46 +0000910}//extern c