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