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