summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Schneider <asn@cryptomilk.org>2017-02-02 16:11:14 +0100
committerChristopher N. Hesse <raymanfx@gmail.com>2017-02-10 16:18:59 +0000
commit759368fbc09c9ebbed0678b5fbc8a6bd142312c1 (patch)
treecf5d1f4f495d85b253f80324c82f14161503afff
parent5fada9b0c83ab53e06a6e95f4c7eb271f8b9422d (diff)
downloadandroid_hardware_samsung-759368fbc09c9ebbed0678b5fbc8a6bd142312c1.tar.gz
android_hardware_samsung-759368fbc09c9ebbed0678b5fbc8a6bd142312c1.tar.bz2
android_hardware_samsung-759368fbc09c9ebbed0678b5fbc8a6bd142312c1.zip
audio: Add a delay for DSP firmware loading
This is turned off by default. Change-Id: Idf764933c67e6666cb2cc0043fa7a7e86935488d
-rw-r--r--audio/audio_hw.c66
-rw-r--r--audio/audio_hw.h1
-rw-r--r--audio/include/samsung_audio.h11
3 files changed, 76 insertions, 2 deletions
diff --git a/audio/audio_hw.c b/audio/audio_hw.c
index cfe3013..3d80f7b 100644
--- a/audio/audio_hw.c
+++ b/audio/audio_hw.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2013 The Android Open Source Project
* Copyright (C) 2017 Christopher N. Hesse <raymanfx@gmail.com>
+ * Copyright (C) 2017 Andreas Schneider <asn@cryptomilk.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -243,6 +244,35 @@ static const struct string_to_enum out_channels_name_to_enum_table[] = {
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
};
+struct timespec time_spec_diff(struct timespec time1, struct timespec time0) {
+ struct timespec ret;
+ int xsec = 0;
+ int sign = 1;
+
+ if (time0.tv_nsec > time1.tv_nsec) {
+ xsec = (int) ((time0.tv_nsec - time1.tv_nsec) / (1E9 + 1));
+ time0.tv_nsec -= (long int) (1E9 * xsec);
+ time0.tv_sec += xsec;
+ }
+
+ if ((time1.tv_nsec - time0.tv_nsec) > 1E9) {
+ xsec = (int) ((time1.tv_nsec - time0.tv_nsec) / 1E9);
+ time0.tv_nsec += (long int) (1E9 * xsec);
+ time0.tv_sec -= xsec;
+ }
+
+ ret.tv_sec = time1.tv_sec - time0.tv_sec;
+ ret.tv_nsec = time1.tv_nsec - time0.tv_nsec;
+
+ if (time1.tv_sec < time0.tv_sec) {
+ sign = -1;
+ }
+
+ ret.tv_sec = ret.tv_sec * sign;
+
+ return ret;
+}
+
static bool is_supported_format(audio_format_t format)
{
if (format == AUDIO_FORMAT_MP3 ||
@@ -389,6 +419,11 @@ static int mixer_init(struct audio_device *adev)
mixer_card->card = card;
mixer_card->mixer = mixer;
mixer_card->audio_route = audio_route;
+
+ /* Do not sleep on first enable_snd_device() */
+ mixer_card->dsp_poweroff_time.tv_sec = 1;
+ mixer_card->dsp_poweroff_time.tv_nsec = 0;
+
list_add_tail(&adev->mixer_list, &mixer_card->adev_list_node);
}
}
@@ -702,6 +737,10 @@ static int enable_snd_device(struct audio_device *adev,
struct mixer_card *mixer_card;
struct listnode *node;
const char *snd_device_name = get_snd_device_name(snd_device);
+#ifdef DSP_POWEROFF_DELAY
+ struct timespec activation_time;
+ struct timespec elapsed_time;
+#endif /* DSP_POWEROFF_DELAY */
if (snd_device_name == NULL)
return -EINVAL;
@@ -724,9 +763,25 @@ static int enable_snd_device(struct audio_device *adev,
list_for_each(node, &uc_info->mixer_list) {
mixer_card = node_to_item(node, struct mixer_card, uc_list_node[uc_info->id]);
+
+#ifdef DSP_POWEROFF_DELAY
+ clock_gettime(CLOCK_MONOTONIC, &activation_time);
+
+ elapsed_time = time_spec_diff(mixer_card->dsp_poweroff_time,
+ activation_time);
+ if (elapsed_time.tv_sec == 0) {
+ long elapsed_usec = elapsed_time.tv_nsec / 1000;
+
+ if (elapsed_usec < DSP_POWEROFF_DELAY) {
+ usleep(DSP_POWEROFF_DELAY - elapsed_usec);
+ }
+ }
+ update_mixer = true;
+#endif /* DSP_POWEROFF_DELAY */
audio_route_apply_path(mixer_card->audio_route, snd_device_name);
- if (update_mixer)
+ if (update_mixer) {
audio_route_update_mixer(mixer_card->audio_route);
+ }
}
return 0;
@@ -761,9 +816,16 @@ int disable_snd_device(struct audio_device *adev,
snd_device, snd_device_name);
list_for_each(node, &uc_info->mixer_list) {
mixer_card = node_to_item(node, struct mixer_card, uc_list_node[uc_info->id]);
+#ifdef DSP_POWEROFF_DELAY
+ update_mixer = true;
+#endif /* DSP_POWEROFF_DELAY */
audio_route_reset_path(mixer_card->audio_route, snd_device_name);
- if (update_mixer)
+ if (update_mixer) {
audio_route_update_mixer(mixer_card->audio_route);
+ }
+#ifdef DSP_POWEROFF_DELAY
+ clock_gettime(CLOCK_MONOTONIC, &(mixer_card->dsp_poweroff_time));
+#endif /* DSP_POWEROFF_DELAY */
}
}
return 0;
diff --git a/audio/audio_hw.h b/audio/audio_hw.h
index fddeffc..da5cd86 100644
--- a/audio/audio_hw.h
+++ b/audio/audio_hw.h
@@ -355,6 +355,7 @@ struct mixer_card {
int card;
struct mixer* mixer;
struct audio_route* audio_route;
+ struct timespec dsp_poweroff_time;
};
struct audio_usecase {
diff --git a/audio/include/samsung_audio.h b/audio/include/samsung_audio.h
index 8b8aeac..1bd094a 100644
--- a/audio/include/samsung_audio.h
+++ b/audio/include/samsung_audio.h
@@ -57,4 +57,15 @@
*/
#define SUPPORTS_IRQ_AFFINITY 0
+/*
+ * The Wolfson/Cirruslogic chips need to shutdown the DAPM route completely
+ * to be able to load a new firmware. Some of these chips need a delay after
+ * shutodown to full poweroff the DSPs.
+ *
+ * A good value to start with is 10ms:
+ *
+ * #define DSP_POWEROFF_DELAY 10 * 1000
+ */
+/* #define DSP_POWEROFF_DELAY 0 */
+
#endif // SAMSUNG_AUDIO_H