soft locker: Need to monitor soft locker diff and control it [1/3]
PD#SWPL-124975
Problem:
Excessive soft locker diff values can lead to underrun.
Solution:
Add application to control PPM.
Verify:
AV400-A113X2.
Change-Id: Ia34cde125a05391c9d20a3b9d225e8abbd7238a3
Signed-off-by: jin.wang1 <jin.wang1@amlogic.com>
diff --git a/aml_audio_clock_sync/Makefile b/aml_audio_clock_sync/Makefile
new file mode 100644
index 0000000..e0a8064
--- /dev/null
+++ b/aml_audio_clock_sync/Makefile
@@ -0,0 +1,39 @@
+# Copyright (C) 2023 Amlogic, Inc. All rights reserved.
+#
+# All information contained herein is Amlogic confidential.
+#
+# This software is provided to you pursuant to Software License
+# Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+# used only in accordance with the terms of this agreement.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification is strictly prohibited without prior written permission
+# from Amlogic.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+target = aml_audio_clock_sync
+
+CFLAGS = -I/$(TARGET_DIR)/host/arm-linux-gnueabihf/sysroot/usr/include
+LDFLAGS = -L/$(TARGET_DIR)/target/usr/lib
+LDLIBS = -lasound
+
+all: $(target)
+
+aml_audio_clock_sync: main.c aml_hw_file.c aml_mixer_alsa.c mixer.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o aml_audio_clock_sync main.c aml_hw_file.c aml_mixer_alsa.c mixer.c
+
+clean:
+ rm $(target)
+
+.PHONY: all clean
diff --git a/aml_audio_clock_sync/README.md b/aml_audio_clock_sync/README.md
new file mode 100644
index 0000000..be9dc38
--- /dev/null
+++ b/aml_audio_clock_sync/README.md
@@ -0,0 +1,38 @@
+# Copyright (C) 2023 Amlogic, Inc. All rights reserved.
+#
+# All information contained herein is Amlogic confidential.
+#
+# This software is provided to you pursuant to Software License
+# Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+# used only in accordance with the terms of this agreement.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification is strictly prohibited without prior written permission
+# from Amlogic.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+### Audio Clock Sync
+
+notice
+==========
+This package can only be used successfully in kernel with soft locker
+and enable clk_tuning_enable of output device in dts.
+
+script usage
+==========
+Need to write the device's soft locker in and out device numbers
+in the script (usr/bin/aml_audio_clock_sync -i=4 -o=2 -e=1&; i
+is soft locker in, o is soft locker out, and e is soft locker enable).
+Use arecord -l and aplay -l to view the input and output devices of the
+sound card respectively. Once set, it will run at the end after the board starts.
diff --git a/aml_audio_clock_sync/S99aml_audio_clock_sync b/aml_audio_clock_sync/S99aml_audio_clock_sync
new file mode 100644
index 0000000..8453381
--- /dev/null
+++ b/aml_audio_clock_sync/S99aml_audio_clock_sync
@@ -0,0 +1,22 @@
+#! /bin/sh
+
+start_correct_mclk() {
+ usr/bin/aml_audio_clock_sync -i=4 -o=2 -e=1&
+}
+
+case "$1" in
+ start)
+ start_correct_mclk
+ ;;
+ stop)
+ /usr/bin/killall -9 aml_audio_clock_sync
+ ;;
+ restart)
+ $0 stop
+ $0 start
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart}"
+ exit 1
+ ;;
+esac
diff --git a/aml_audio_clock_sync/aml_hw_file.c b/aml_audio_clock_sync/aml_hw_file.c
new file mode 100644
index 0000000..187203b
--- /dev/null
+++ b/aml_audio_clock_sync/aml_hw_file.c
@@ -0,0 +1,64 @@
+// Copyright (C) 2023 Amlogic, Inc. All rights reserved.
+//
+// All information contained herein is Amlogic confidential.
+//
+// This software is provided to you pursuant to Software License
+// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+// used only in accordance with the terms of this agreement.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification is strictly prohibited without prior written permission
+// from Amlogic.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "aml_hw_file.h"
+
+#define SOUND_CARDS_PATH "/proc/asound/cards"
+int aml_get_sound_card_main()
+{
+ int card = -1, err = 0;
+ int fd = -1;
+ unsigned fileSize = 512;
+ char *read_buf = NULL, *pd = NULL;
+
+ fd = open(SOUND_CARDS_PATH, O_RDONLY);
+ if (fd < 0) {
+ printf("[%s:%d] Failed to open config file %s\n", __FUNCTION__, __LINE__, SOUND_CARDS_PATH);
+ close(fd);
+ return -EINVAL;
+ }
+
+ read_buf = (char *) malloc(fileSize);
+ if (!read_buf) {
+ printf("[%s:%d] Failed to malloc read_buf\n", __FUNCTION__, __LINE__);
+ close(fd);
+ return -ENOMEM;
+ }
+ memset(read_buf, 0x0, fileSize);
+ err = read(fd, read_buf, (fileSize-1));
+ if (err < 0) {
+ printf("[%s:%d] Failed to read config file %s\n", __FUNCTION__, __LINE__, SOUND_CARDS_PATH);
+ close(fd);
+ free(read_buf);
+ return -EINVAL;
+ }
+ pd = strstr(read_buf, "AML");
+ if ((pd != NULL) && (pd >= (read_buf+3))) {
+ card = *(pd - 3) - '0';
+ }
+
+ free(read_buf);
+ close(fd);
+ return card;
+}
diff --git a/aml_audio_clock_sync/aml_hw_file.h b/aml_audio_clock_sync/aml_hw_file.h
new file mode 100644
index 0000000..a99ea55
--- /dev/null
+++ b/aml_audio_clock_sync/aml_hw_file.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2023 Amlogic, Inc. All rights reserved.
+//
+// All information contained herein is Amlogic confidential.
+//
+// This software is provided to you pursuant to Software License
+// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+// used only in accordance with the terms of this agreement.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification is strictly prohibited without prior written permission
+// from Amlogic.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef _AML_HW_FILE_H_
+#define _AML_HW_FILE_H_
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+int aml_get_sound_card_main();
+
+#endif
diff --git a/aml_audio_clock_sync/aml_mixer_alsa.c b/aml_audio_clock_sync/aml_mixer_alsa.c
new file mode 100644
index 0000000..a87432d
--- /dev/null
+++ b/aml_audio_clock_sync/aml_mixer_alsa.c
@@ -0,0 +1,157 @@
+// Copyright (C) 2023 Amlogic, Inc. All rights reserved.
+//
+// All information contained herein is Amlogic confidential.
+//
+// This software is provided to you pursuant to Software License
+// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+// used only in accordance with the terms of this agreement.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification is strictly prohibited without prior written permission
+// from Amlogic.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "aml_mixer_alsa.h"
+#include "aml_hw_file.h"
+#include "mixer.h"
+
+struct aml_mixer_handle {
+ struct mixer *pMixer;
+ pthread_mutex_t lock;
+};
+
+static struct aml_mixer_list gAmlMixerList[] = {
+ {AML_MIXER_ID_LOCKER_IN_SRC, "locker in src"},
+ {AML_MIXER_ID_LOCKER_OUT_SINK, "locker out sink"},
+ {AML_MIXER_ID_LOCKER_EN, "soft locker enable"},
+ {AML_MIXER_ID_LOCKER_DIFF, "soft locker diff"},
+ {AML_MIXER_ID_MCLK_FINE_SETTING, "TDM MCLK Fine Setting"},
+};
+
+static struct aml_mixer_handle * mixer_handle = NULL;
+
+static char *_get_mixer_name_by_id(int mixer_id)
+{
+ int i;
+ int cnt_mixer = sizeof(gAmlMixerList) / sizeof(struct aml_mixer_list);
+
+ for (i = 0; i < cnt_mixer; i++) {
+ if (gAmlMixerList[i].id == mixer_id) {
+ return gAmlMixerList[i].mixer_name;
+ }
+ }
+
+ return NULL;
+}
+
+static struct mixer_ctl *_get_mixer_ctl_handle(struct mixer *pmixer, int mixer_id)
+{
+ struct mixer_ctl *pCtrl = NULL;
+
+ if (_get_mixer_name_by_id(mixer_id) != NULL) {
+ pCtrl = mixer_get_ctl_by_name(pmixer,_get_mixer_name_by_id(mixer_id));
+ }
+
+ return pCtrl;
+}
+
+static struct mixer *_open_mixer_handle(void)
+{
+ int card = 0;
+ struct mixer *pmixer = NULL;
+
+ if (mixer_handle != NULL) {
+ return mixer_handle->pMixer;
+ }
+
+ mixer_handle = (struct aml_mixer_handle *)calloc(1,sizeof(struct aml_mixer_handle));
+
+ card = aml_get_sound_card_main();
+ if (card < 0) {
+ printf("[%s:%d] Failed to get sound card\n", __FUNCTION__, __LINE__);
+ return NULL;
+ }
+
+ pmixer = mixer_open(card);
+ if (NULL == pmixer) {
+ printf("[%s:%d] Failed to open mixer \n", __FUNCTION__, __LINE__);
+ return NULL;
+ }
+
+ mixer_handle->pMixer = pmixer;
+ pthread_mutex_init(&mixer_handle->lock, NULL);
+
+ return pmixer;
+}
+
+int aml_mixer_ctrl_get_int(int mixer_id)
+{
+ struct mixer *pMixer;
+ struct mixer_ctl *pCtrl;
+ int value = -1;
+
+ pMixer = _open_mixer_handle();
+ if (pMixer == NULL) {
+ printf("[%s:%d] Failed to open mixer\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+ pthread_mutex_lock (&mixer_handle->lock);
+
+ pCtrl = _get_mixer_ctl_handle(pMixer, mixer_id);
+ if (pCtrl == NULL) {
+ printf("[%s:%d] Failed to open mixer\n", __FUNCTION__, __LINE__);
+ pthread_mutex_unlock (&mixer_handle->lock);
+ return -1;
+ }
+
+ value = mixer_ctl_get_value(pCtrl, 0);
+ pthread_mutex_unlock (&mixer_handle->lock);
+ return value;
+}
+
+int aml_mixer_ctrl_set_int(int mixer_id, int value)
+{
+ struct mixer *pMixer;
+ struct mixer_ctl *pCtrl;
+
+ pMixer = _open_mixer_handle();
+ if (pMixer == NULL) {
+ printf("[%s:%d] Failed to open mixer\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+ pthread_mutex_lock (&mixer_handle->lock);
+
+ pCtrl = _get_mixer_ctl_handle(pMixer, mixer_id);
+ if (pCtrl == NULL) {
+ printf("[%s:%d] Failed to open mixer %s\n", __FUNCTION__, __LINE__,_get_mixer_name_by_id(mixer_id));
+ return -1;
+ }
+
+ mixer_ctl_set_value(pCtrl, 0, value);
+ pthread_mutex_unlock (&mixer_handle->lock);
+
+ return 0;
+}
+
+void aml_close_mixer() {
+ if (mixer_handle->pMixer != NULL) {
+ mixer_close(mixer_handle->pMixer);
+ mixer_handle->pMixer = NULL;
+ }
+
+ if (mixer_handle != NULL) {
+ free(mixer_handle);
+ mixer_handle = NULL;
+ }
+}
diff --git a/aml_audio_clock_sync/aml_mixer_alsa.h b/aml_audio_clock_sync/aml_mixer_alsa.h
new file mode 100644
index 0000000..c8ed1b7
--- /dev/null
+++ b/aml_audio_clock_sync/aml_mixer_alsa.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 Amlogic, Inc. All rights reserved.
+//
+// All information contained herein is Amlogic confidential.
+//
+// This software is provided to you pursuant to Software License
+// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+// used only in accordance with the terms of this agreement.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification is strictly prohibited without prior written permission
+// from Amlogic.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef _AML_MIXER_ALSA_H_
+#define _AML_MIXER_ALSA_H_
+#include <stdlib.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+struct aml_mixer_list {
+ int id;
+ char mixer_name[50];
+};
+
+typedef enum AML_MIXER_CTRL_ID {
+ AML_MIXER_ID_LOCKER_IN_SRC = 0,
+ AML_MIXER_ID_LOCKER_OUT_SINK,
+ AML_MIXER_ID_LOCKER_EN,
+ AML_MIXER_ID_LOCKER_DIFF,
+ AML_MIXER_ID_MCLK_FINE_SETTING,
+}eMixerCtrlID;
+
+void aml_close_mixer();
+int aml_mixer_ctrl_get_int(int mixer_id);
+int aml_mixer_ctrl_set_int(int mixer_id, int value);
+
+#endif
diff --git a/aml_audio_clock_sync/main.c b/aml_audio_clock_sync/main.c
new file mode 100644
index 0000000..f1aabf5
--- /dev/null
+++ b/aml_audio_clock_sync/main.c
@@ -0,0 +1,178 @@
+// Copyright (C) 2023 Amlogic, Inc. All rights reserved.
+//
+// All information contained herein is Amlogic confidential.
+//
+// This software is provided to you pursuant to Software License
+// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+// used only in accordance with the terms of this agreement.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification is strictly prohibited without prior written permission
+// from Amlogic.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include "aml_mixer_alsa.h"
+
+typedef struct anti_clk_drift_s
+{
+ int audio_locker_cnt;
+ int src_alsa_device;
+ int sink_alsa_device;
+ bool is_init;
+} anti_clk_drift_t;
+
+int soft_lock_in = -1;
+int soft_lock_out = -1;
+int soft_lock_enable = -1;
+
+#define CLK_DRIFT_THRESHOLD_MS 2
+#define CLK_SETTING_OFFSET 1000000
+#define CLK_appreciation_multiple 100
+#define CLK_CHANGE_THRESHOLD 10000
+
+static anti_clk_drift_t _anti_clk_drift = {
+ .audio_locker_cnt = 0,
+ .src_alsa_device = -1,
+ .sink_alsa_device = -1,
+ .is_init = false,
+};
+
+int aml_set_locker_in_src(int alsa_device)
+{
+ aml_mixer_ctrl_set_int(AML_MIXER_ID_LOCKER_IN_SRC, alsa_device);
+ _anti_clk_drift.src_alsa_device = alsa_device;
+
+ return 0;
+}
+
+int aml_set_locker_out_sink(int alsa_device)
+{
+ aml_mixer_ctrl_set_int(AML_MIXER_ID_LOCKER_OUT_SINK, alsa_device);
+ _anti_clk_drift.sink_alsa_device = alsa_device;
+
+ return 0;
+}
+
+int aml_set_locker_enable(int en)
+{
+ if (_anti_clk_drift.src_alsa_device == -1) {
+ printf("[%s:%d] locker in src not set\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+
+ if (_anti_clk_drift.sink_alsa_device == -1) {
+ printf("[%s:%d] locker out sink not set\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+
+ aml_mixer_ctrl_set_int(AML_MIXER_ID_LOCKER_EN, en);
+ _anti_clk_drift.audio_locker_cnt = 0;
+ _anti_clk_drift.is_init = true;
+}
+
+int aml_get_soft_locker_diff()
+{
+ if (!_anti_clk_drift.is_init) {
+ printf("[%s:%d] soft locker is not init\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+
+ return aml_mixer_ctrl_get_int(AML_MIXER_ID_LOCKER_DIFF);
+}
+
+int aml_set_mclk(int val)
+{
+ aml_mixer_ctrl_set_int(AML_MIXER_ID_MCLK_FINE_SETTING, val);
+
+ return 0;
+}
+
+int aml_get_parameter(int argc,char *argv[]) {
+ int i;
+ for (i = 1;i < argc;++i) {
+ switch (argv[i][1])
+ {
+ case 'i':
+ soft_lock_in = argv[i][3] - '0';
+ break;
+ case 'o':
+ soft_lock_out = argv[i][3] - '0';
+ break;
+ case 'e':
+ soft_lock_enable = argv[i][3] - '0';
+ break;
+ case 'h':
+ printf("-i : =soft_lock_in\n \
+ -o : =soft_lock_out\n \
+ -e : =soft_lock_enable\n");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void aml_process_ended() {
+ aml_close_mixer();
+ exit(1);
+}
+
+int main(int argc,const char *argv[])
+{
+ int diff_ms = 0;
+ int previous_diff = 0;
+ int tune_val;
+ int mclk_appreciation = 0;
+ int diff_difference = 0;
+
+ aml_get_parameter(argc,argv);
+
+ //Set soft lock related devices and enable soft lock.
+ aml_set_locker_in_src(soft_lock_in);
+ aml_set_locker_out_sink(soft_lock_out);
+ aml_set_locker_enable(soft_lock_enable);
+ signal(SIGTERM,aml_process_ended);
+
+ if (!_anti_clk_drift.is_init) {
+ printf("[%s:%d] clk anti drift is not init yet\n", __FUNCTION__, __LINE__);
+ return 0;
+ }
+ //Get soft locker in out difference.
+ previous_diff = aml_get_soft_locker_diff();
+ while (1) {
+ diff_ms = aml_get_soft_locker_diff();
+
+ //If the diff value is greater than the threshold and in an upward trend, change CLK
+ if (abs(diff_ms) > CLK_DRIFT_THRESHOLD_MS && abs(diff_ms) >= abs(previous_diff)) {
+ diff_difference = diff_ms - previous_diff;
+ mclk_appreciation = (diff_difference * abs(diff_difference) + diff_ms / 5) * CLK_appreciation_multiple;
+ if (abs(mclk_appreciation) > CLK_CHANGE_THRESHOLD)
+ mclk_appreciation = CLK_CHANGE_THRESHOLD * (mclk_appreciation/abs(mclk_appreciation));
+ tune_val = CLK_SETTING_OFFSET - mclk_appreciation;
+ aml_set_mclk(tune_val);
+ }
+ previous_diff = diff_ms;
+ sleep(2);
+ }
+ aml_close_mixer();
+
+ return 0;
+
+}
diff --git a/aml_audio_clock_sync/mixer.c b/aml_audio_clock_sync/mixer.c
new file mode 100644
index 0000000..e9b3bb6
--- /dev/null
+++ b/aml_audio_clock_sync/mixer.c
@@ -0,0 +1,229 @@
+/* mixer.c
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of The Android Open Source Project nor the names of
+** its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+** DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include "mixer.h"
+
+void mixer_close(struct mixer *mixer)
+{
+ unsigned int n,m;
+
+ if (!mixer)
+ return;
+
+ if (mixer->fd >= 0)
+ close(mixer->fd);
+
+ if (mixer->ctl) {
+ for (n = 0; n < mixer->count; n++) {
+ if (mixer->ctl[n].ename) {
+ unsigned int max = mixer->ctl[n].info->value.enumerated.items;
+ for (m = 0; m < max; m++)
+ free(mixer->ctl[n].ename[m]);
+ free(mixer->ctl[n].ename);
+ }
+ }
+ free(mixer->ctl);
+ }
+
+ if (mixer->elem_info)
+ free(mixer->elem_info);
+
+ free(mixer);
+}
+
+struct mixer *mixer_open(unsigned int card)
+{
+ struct snd_ctl_elem_list elist;
+ struct snd_ctl_elem_info tmp;
+ struct snd_ctl_elem_id *eid = NULL;
+ struct mixer *mixer = NULL;
+ unsigned int n, m;
+ int fd;
+ char fn[256];
+
+ snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card);
+ fd = open(fn, O_RDWR);
+ if (fd < 0)
+ return 0;
+
+ memset(&elist, 0, sizeof(elist));
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
+ goto fail;
+
+ mixer = (struct mixer *)calloc(1, sizeof(*mixer));
+ if (!mixer)
+ goto fail;
+
+ mixer->ctl = (struct mixer_ctl *)calloc(elist.count, sizeof(struct mixer_ctl));
+ mixer->elem_info = (struct snd_ctl_elem_info*)calloc(elist.count, sizeof(struct snd_ctl_elem_info));
+ if (!mixer->ctl || !mixer->elem_info)
+ goto fail;
+
+ if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0)
+ goto fail;
+
+ eid = (struct snd_ctl_elem_id *)calloc(elist.count, sizeof(struct snd_ctl_elem_id));
+ if (!eid)
+ goto fail;
+
+ mixer->count = elist.count;
+ mixer->fd = fd;
+ elist.space = mixer->count;
+ elist.pids = eid;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
+ goto fail;
+
+ for (n = 0; n < mixer->count; n++) {
+ struct snd_ctl_elem_info *ei = mixer->elem_info + n;
+ ei->id.numid = eid[n].numid;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)
+ goto fail;
+ mixer->ctl[n].info = ei;
+ mixer->ctl[n].mixer = mixer;
+ if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+ char **enames = (char **)calloc(ei->value.enumerated.items, sizeof(char*));
+ if (!enames)
+ goto fail;
+ mixer->ctl[n].ename = enames;
+ for (m = 0; m < ei->value.enumerated.items; m++) {
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.id.numid = ei->id.numid;
+ tmp.value.enumerated.item = m;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
+ goto fail;
+ enames[m] = strdup(tmp.value.enumerated.name);
+ if (!enames[m])
+ goto fail;
+ }
+ }
+ }
+
+ free(eid);
+ return mixer;
+
+fail:
+ if (eid)
+ free(eid);
+ if (mixer)
+ mixer_close(mixer);
+ else if (fd >= 0)
+ close(fd);
+ return NULL;
+}
+
+struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
+{
+ unsigned int n;
+
+ if (!mixer)
+ return NULL;
+
+ for (n = 0; n < mixer->count; n++)
+ if (!strcmp(name, (char*) mixer->elem_info[n].id.name))
+ return mixer->ctl + n;
+
+ return NULL;
+}
+
+int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id)
+{
+ struct snd_ctl_elem_value ev;
+ int ret;
+
+ if (!ctl || (id >= ctl->info->count))
+ return -EINVAL;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.id.numid = ctl->info->id.numid;
+ ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
+ if (ret < 0)
+ return ret;
+
+ switch (ctl->info->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ return !!ev.value.integer.value[id];
+
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ return ev.value.integer.value[id];
+
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+ return ev.value.enumerated.item[id];
+
+ case SNDRV_CTL_ELEM_TYPE_BYTES:
+ return ev.value.bytes.data[id];
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
+{
+ struct snd_ctl_elem_value ev;
+ int ret;
+
+ if (!ctl || (id >= ctl->info->count))
+ return -EINVAL;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.id.numid = ctl->info->id.numid;
+ ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
+ if (ret < 0)
+ return ret;
+
+ switch (ctl->info->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ ev.value.integer.value[id] = !!value;
+ break;
+
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ ev.value.integer.value[id] = value;
+ break;
+
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+ ev.value.enumerated.item[id] = value;
+ break;
+
+ case SNDRV_CTL_ELEM_TYPE_BYTES:
+ ev.value.bytes.data[id] = value;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
+}
diff --git a/aml_audio_clock_sync/mixer.h b/aml_audio_clock_sync/mixer.h
new file mode 100644
index 0000000..3cbf7bb
--- /dev/null
+++ b/aml_audio_clock_sync/mixer.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2023 Amlogic, Inc. All rights reserved.
+//
+// All information contained herein is Amlogic confidential.
+//
+// This software is provided to you pursuant to Software License
+// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+// used only in accordance with the terms of this agreement.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification is strictly prohibited without prior written permission
+// from Amlogic.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef _MIXER_H_
+#define _MIXER_H_
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sound/asound.h>
+
+struct mixer_ctl {
+ struct mixer *mixer;
+ struct snd_ctl_elem_info *info;
+ char **ename;
+};
+
+struct mixer {
+ int fd;
+ struct snd_ctl_card_info card_info;
+ struct snd_ctl_elem_info *elem_info;
+ struct mixer_ctl *ctl;
+ unsigned int count;
+};
+
+void mixer_close(struct mixer *mixer);
+struct mixer *mixer_open(unsigned int card);
+struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name);
+int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id);
+int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value);
+#endif