hal: codec calibration data using hwdep nodes

Push the codec driver calibration using hwdep nodes.

Based on CAF commit:
55e6df22520565e752d40a66b5ed5180f63d6ba1

Change-Id: If8ae828135a708567fd42b6fc5ff40d107aa1235
diff --git a/hal/Android.mk b/hal/Android.mk
index 73a298d..0d931c1 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -31,7 +31,6 @@
 	audio_extn/ext_speaker.c \
 	$(AUDIO_PLATFORM)/platform.c
 
-
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
@@ -82,6 +81,13 @@
     LOCAL_SRC_FILES += audio_extn/dsm_feedback.c
 endif
 
+ifneq ($(filter msm8992 msm8994,$(TARGET_BOARD_PLATFORM)),)
+  # push codec/mad calibration to HW dep node
+  # applicable to msm8992/8994 or newer platforms
+  LOCAL_CFLAGS += -DHWDEP_CAL_ENABLED
+  LOCAL_SRC_FILES += audio_extn/hwdep_cal.c
+endif
+
 LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
 
 LOCAL_MODULE_RELATIVE_PATH := hw
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 51abf46..b99378e 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -95,4 +95,10 @@
                          bool benable);
 #endif
 
+#ifndef HWDEP_CAL_ENABLED
+#define  audio_extn_hwdep_cal_send(snd_card, acdb_handle) (0)
+#else
+void audio_extn_hwdep_cal_send(int snd_card, void *acdb_handle);
+#endif
+
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/hwdep_cal.c b/hal/audio_extn/hwdep_cal.c
new file mode 100644
index 0000000..811db3e
--- /dev/null
+++ b/hal/audio_extn/hwdep_cal.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hardware_cal"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#ifdef HWDEP_CAL_ENABLED
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <cutils/log.h>
+#include <audio_hw.h>
+#include "audio_extn.h"
+#include "sound/msmcal-hwdep.h"
+
+#define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
+#define MAX_CAL_NAME 20
+
+typedef struct acdb_audio_cal_cfg {
+    uint32_t             persist;
+    uint32_t             snd_dev_id;
+    audio_devices_t      dev_id;
+    int32_t              acdb_dev_id;
+    uint32_t             app_type;
+    uint32_t             topo_id;
+    uint32_t             sampling_rate;
+    uint32_t             cal_type;
+    uint32_t             module_id;
+    uint32_t             param_id;
+} acdb_audio_cal_cfg_t;
+
+struct param_data {
+    int    use_case;
+    int    acdb_id;
+    int    get_size;
+    int    buff_size;
+    int    data_size;
+    void   *buff;
+};
+
+char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
+        [WCD9XXX_ANC_CAL] = "anc_cal",
+        [WCD9XXX_MBHC_CAL] = "mbhc_cal",
+        [WCD9XXX_MAD_CAL] = "mad_cal",
+};
+
+typedef int (*acdb_get_calibration_t)(char *attr, int size, void *data);
+acdb_get_calibration_t     acdb_get_calibration;
+
+static int hw_util_open(int card_no)
+{
+    int fd = -1;
+    char dev_name[256];
+
+    snprintf(dev_name, sizeof(dev_name), "/dev/snd/hwC%uD%u",
+                               card_no, WCD9XXX_CODEC_HWDEP_NODE);
+    ALOGD("%s: Opening device %s\n", __func__, dev_name);
+    fd = open(dev_name, O_WRONLY);
+    if (fd < 0) {
+        ALOGE("%s: cannot open device '%s'\n", __func__, dev_name);
+        return fd;
+    }
+    ALOGD("%s: success", __func__);
+    return fd;
+}
+
+static int send_codec_cal(acdb_get_calibration_t acdb_loader_get_calibration, int fd)
+{
+    int ret = 0, type;
+
+    for (type = WCD9XXX_ANC_CAL; type < WCD9XXX_MAX_CAL; type++) {
+        struct wcdcal_ioctl_buffer codec_buffer;
+        struct param_data calib;
+
+        if (!strcmp(cal_name_info[type], "mad_cal"))
+            calib.acdb_id = SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID;
+        calib.get_size = 1;
+        ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data),
+                                                                 &calib);
+        if (ret < 0) {
+            ALOGE("%s get_calibration failed\n", __func__);
+            return ret;
+        }
+        calib.get_size = 0;
+        calib.buff = malloc(calib.buff_size);
+        ret = acdb_loader_get_calibration(cal_name_info[type],
+                              sizeof(struct param_data), &calib);
+        if (ret < 0) {
+            ALOGE("%s get_calibration failed\n", __func__);
+            free(calib.buff);
+            return ret;
+        }
+        codec_buffer.buffer = calib.buff;
+        codec_buffer.size = calib.data_size;
+        codec_buffer.cal_type = type;
+        if (ioctl(fd, SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE, &codec_buffer) < 0)
+            ALOGE("Failed to call ioctl  for %s err=%d",
+                                  cal_name_info[type], errno);
+        ALOGD("%s cal sent for %s", __func__, cal_name_info[type]);
+        free(calib.buff);
+    }
+    return ret;
+}
+
+
+void audio_extn_hwdep_cal_send(int snd_card, void *acdb_handle)
+{
+    int fd;
+
+    fd = hw_util_open(snd_card);
+    if (fd == -1) {
+        ALOGE("%s error open\n", __func__);
+        return;
+    }
+
+    acdb_get_calibration = (acdb_get_calibration_t)
+          dlsym(acdb_handle, "acdb_loader_get_calibration");
+
+    if (acdb_get_calibration == NULL) {
+        ALOGE("%s: ERROR. dlsym Error:%s acdb_loader_get_calibration", __func__,
+           dlerror());
+        return;
+    }
+    if (send_codec_cal(acdb_get_calibration, fd) < 0)
+        ALOGE("%s: Could not send anc cal", __FUNCTION__);
+
+    close(fd);
+}
+
+#endif
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 305e1c1..39d1aa5 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -816,8 +816,11 @@
 
     /* Initialize platform specific ids and/or backends*/
     platform_info_init();
+
     audio_extn_spkr_prot_init(adev);
 
+    audio_extn_hwdep_cal_send(adev->snd_card, my_data->acdb_handle);
+
     /* load csd client */
     platform_csd_init(my_data);