From 759368fbc09c9ebbed0678b5fbc8a6bd142312c1 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 2 Feb 2017 16:11:14 +0100 Subject: audio: Add a delay for DSP firmware loading This is turned off by default. Change-Id: Idf764933c67e6666cb2cc0043fa7a7e86935488d --- audio/audio_hw.c | 66 +++++++++++++++++++++++++++++++++++++++++-- audio/audio_hw.h | 1 + audio/include/samsung_audio.h | 11 ++++++++ 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 + * Copyright (C) 2017 Andreas Schneider * * 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 -- cgit v1.2.3