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