GREYBUS_AUDIO_MSM8994 is not an existing configuration option and as reported in September 2016, it depends on an "out-of-tree qualcomm audio driver". This driver never made it upstream.
https://lore.kernel.org/lkml/20160921073905.GA31263@kroah.com/
Moreover, there doesn't seem to be any interest in actually fixing the driver as it uses ASoC APIs that have been removed from the kernel in 2018 as shown by its use of snd_soc_register_codec and snd_soc_codec_get_drvdata, removed in commit 999f7f5af8eb ("ASoC: remove Codec related code").
Signed-off-by: Alexandre Belloni alexandre.belloni@bootlin.com --- drivers/staging/greybus/Makefile | 4 - drivers/staging/greybus/audio_codec.c | 1103 ---------------- drivers/staging/greybus/audio_module.c | 478 ------- drivers/staging/greybus/audio_topology.c | 1448 ---------------------- 4 files changed, 3033 deletions(-) delete mode 100644 drivers/staging/greybus/audio_codec.c delete mode 100644 drivers/staging/greybus/audio_module.c delete mode 100644 drivers/staging/greybus/audio_topology.c
diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile index 627e44f2a983..af88583cdc20 100644 --- a/drivers/staging/greybus/Makefile +++ b/drivers/staging/greybus/Makefile @@ -27,8 +27,6 @@ obj-$(CONFIG_GREYBUS_RAW) += gb-raw.o obj-$(CONFIG_GREYBUS_VIBRATOR) += gb-vibrator.o
# Greybus Audio is a bunch of modules -gb-audio-module-y := audio_module.o audio_topology.o -gb-audio-codec-y := audio_codec.o gb-audio-gb-y := audio_gb.o gb-audio-apbridgea-y := audio_apbridgea.o gb-audio-manager-y := audio_manager.o audio_manager_module.o @@ -40,8 +38,6 @@ gb-audio-manager-y := audio_manager.o audio_manager_module.o #ccflags-y += -DGB_AUDIO_MANAGER_SYSFS #endif
-obj-$(CONFIG_GREYBUS_AUDIO_MSM8994) += gb-audio-codec.o -obj-$(CONFIG_GREYBUS_AUDIO_MSM8994) += gb-audio-module.o obj-$(CONFIG_GREYBUS_AUDIO) += gb-audio-gb.o obj-$(CONFIG_GREYBUS_AUDIO) += gb-audio-apbridgea.o obj-$(CONFIG_GREYBUS_AUDIO) += gb-audio-manager.o diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c deleted file mode 100644 index 08746c85dea6..000000000000 --- a/drivers/staging/greybus/audio_codec.c +++ /dev/null @@ -1,1103 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * APBridge ALSA SoC dummy codec driver - * Copyright 2016 Google Inc. - * Copyright 2016 Linaro Ltd. - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pm_runtime.h> -#include <sound/soc.h> -#include <sound/pcm_params.h> -#include <uapi/linux/input.h> - -#include "audio_codec.h" -#include "audio_apbridgea.h" -#include "audio_manager.h" - -static struct gbaudio_codec_info *gbcodec; - -static struct gbaudio_data_connection * -find_data(struct gbaudio_module_info *module, int id) -{ - struct gbaudio_data_connection *data; - - list_for_each_entry(data, &module->data_list, list) { - if (id == data->id) - return data; - } - return NULL; -} - -static struct gbaudio_stream_params * -find_dai_stream_params(struct gbaudio_codec_info *codec, int id, int stream) -{ - struct gbaudio_codec_dai *dai; - - list_for_each_entry(dai, &codec->dai_list, list) { - if (dai->id == id) - return &dai->params[stream]; - } - return NULL; -} - -static int gbaudio_module_enable_tx(struct gbaudio_codec_info *codec, - struct gbaudio_module_info *module, int id) -{ - int module_state, ret = 0; - u16 data_cport, i2s_port, cportid; - u8 sig_bits, channels; - u32 format, rate; - struct gbaudio_data_connection *data; - struct gbaudio_stream_params *params; - - /* find the dai */ - data = find_data(module, id); - if (!data) { - dev_err(module->dev, "%d:DATA connection missing\n", id); - return -ENODEV; - } - module_state = data->state[SNDRV_PCM_STREAM_PLAYBACK]; - - params = find_dai_stream_params(codec, id, SNDRV_PCM_STREAM_PLAYBACK); - if (!params) { - dev_err(codec->dev, "Failed to fetch dai_stream pointer\n"); - return -EINVAL; - } - - /* register cport */ - if (module_state < GBAUDIO_CODEC_STARTUP) { - i2s_port = 0; /* fixed for now */ - cportid = data->connection->hd_cport_id; - ret = gb_audio_apbridgea_register_cport(data->connection, - i2s_port, cportid, - AUDIO_APBRIDGEA_DIRECTION_TX); - if (ret) { - dev_err_ratelimited(module->dev, - "reg_cport failed:%d\n", ret); - return ret; - } - data->state[SNDRV_PCM_STREAM_PLAYBACK] = - GBAUDIO_CODEC_STARTUP; - dev_dbg(module->dev, "Dynamic Register %d DAI\n", cportid); - } - - /* hw_params */ - if (module_state < GBAUDIO_CODEC_HWPARAMS) { - format = params->format; - channels = params->channels; - rate = params->rate; - sig_bits = params->sig_bits; - data_cport = data->connection->intf_cport_id; - ret = gb_audio_gb_set_pcm(module->mgmt_connection, data_cport, - format, rate, channels, sig_bits); - if (ret) { - dev_err_ratelimited(module->dev, "set_pcm failed:%d\n", - ret); - return ret; - } - data->state[SNDRV_PCM_STREAM_PLAYBACK] = - GBAUDIO_CODEC_HWPARAMS; - dev_dbg(module->dev, "Dynamic hw_params %d DAI\n", data_cport); - } - - /* prepare */ - if (module_state < GBAUDIO_CODEC_PREPARE) { - data_cport = data->connection->intf_cport_id; - ret = gb_audio_gb_set_tx_data_size(module->mgmt_connection, - data_cport, 192); - if (ret) { - dev_err_ratelimited(module->dev, - "set_tx_data_size failed:%d\n", - ret); - return ret; - } - ret = gb_audio_gb_activate_tx(module->mgmt_connection, - data_cport); - if (ret) { - dev_err_ratelimited(module->dev, - "activate_tx failed:%d\n", ret); - return ret; - } - data->state[SNDRV_PCM_STREAM_PLAYBACK] = - GBAUDIO_CODEC_PREPARE; - dev_dbg(module->dev, "Dynamic prepare %d DAI\n", data_cport); - } - - return 0; -} - -static int gbaudio_module_disable_tx(struct gbaudio_module_info *module, int id) -{ - int ret; - u16 data_cport, cportid, i2s_port; - int module_state; - struct gbaudio_data_connection *data; - - /* find the dai */ - data = find_data(module, id); - if (!data) { - dev_err(module->dev, "%d:DATA connection missing\n", id); - return -ENODEV; - } - module_state = data->state[SNDRV_PCM_STREAM_PLAYBACK]; - - if (module_state > GBAUDIO_CODEC_HWPARAMS) { - data_cport = data->connection->intf_cport_id; - ret = gb_audio_gb_deactivate_tx(module->mgmt_connection, - data_cport); - if (ret) { - dev_err_ratelimited(module->dev, - "deactivate_tx failed:%d\n", ret); - return ret; - } - dev_dbg(module->dev, "Dynamic deactivate %d DAI\n", data_cport); - data->state[SNDRV_PCM_STREAM_PLAYBACK] = - GBAUDIO_CODEC_HWPARAMS; - } - - if (module_state > GBAUDIO_CODEC_SHUTDOWN) { - i2s_port = 0; /* fixed for now */ - cportid = data->connection->hd_cport_id; - ret = gb_audio_apbridgea_unregister_cport(data->connection, - i2s_port, cportid, - AUDIO_APBRIDGEA_DIRECTION_TX); - if (ret) { - dev_err_ratelimited(module->dev, - "unregister_cport failed:%d\n", - ret); - return ret; - } - dev_dbg(module->dev, "Dynamic Unregister %d DAI\n", cportid); - data->state[SNDRV_PCM_STREAM_PLAYBACK] = - GBAUDIO_CODEC_SHUTDOWN; - } - - return 0; -} - -static int gbaudio_module_enable_rx(struct gbaudio_codec_info *codec, - struct gbaudio_module_info *module, int id) -{ - int module_state, ret = 0; - u16 data_cport, i2s_port, cportid; - u8 sig_bits, channels; - u32 format, rate; - struct gbaudio_data_connection *data; - struct gbaudio_stream_params *params; - - /* find the dai */ - data = find_data(module, id); - if (!data) { - dev_err(module->dev, "%d:DATA connection missing\n", id); - return -ENODEV; - } - module_state = data->state[SNDRV_PCM_STREAM_CAPTURE]; - - params = find_dai_stream_params(codec, id, SNDRV_PCM_STREAM_CAPTURE); - if (!params) { - dev_err(codec->dev, "Failed to fetch dai_stream pointer\n"); - return -EINVAL; - } - - /* register cport */ - if (module_state < GBAUDIO_CODEC_STARTUP) { - i2s_port = 0; /* fixed for now */ - cportid = data->connection->hd_cport_id; - ret = gb_audio_apbridgea_register_cport(data->connection, - i2s_port, cportid, - AUDIO_APBRIDGEA_DIRECTION_RX); - if (ret) { - dev_err_ratelimited(module->dev, - "reg_cport failed:%d\n", ret); - return ret; - } - data->state[SNDRV_PCM_STREAM_CAPTURE] = - GBAUDIO_CODEC_STARTUP; - dev_dbg(module->dev, "Dynamic Register %d DAI\n", cportid); - } - - /* hw_params */ - if (module_state < GBAUDIO_CODEC_HWPARAMS) { - format = params->format; - channels = params->channels; - rate = params->rate; - sig_bits = params->sig_bits; - data_cport = data->connection->intf_cport_id; - ret = gb_audio_gb_set_pcm(module->mgmt_connection, data_cport, - format, rate, channels, sig_bits); - if (ret) { - dev_err_ratelimited(module->dev, "set_pcm failed:%d\n", - ret); - return ret; - } - data->state[SNDRV_PCM_STREAM_CAPTURE] = - GBAUDIO_CODEC_HWPARAMS; - dev_dbg(module->dev, "Dynamic hw_params %d DAI\n", data_cport); - } - - /* prepare */ - if (module_state < GBAUDIO_CODEC_PREPARE) { - data_cport = data->connection->intf_cport_id; - ret = gb_audio_gb_set_rx_data_size(module->mgmt_connection, - data_cport, 192); - if (ret) { - dev_err_ratelimited(module->dev, - "set_rx_data_size failed:%d\n", - ret); - return ret; - } - ret = gb_audio_gb_activate_rx(module->mgmt_connection, - data_cport); - if (ret) { - dev_err_ratelimited(module->dev, - "activate_rx failed:%d\n", ret); - return ret; - } - data->state[SNDRV_PCM_STREAM_CAPTURE] = - GBAUDIO_CODEC_PREPARE; - dev_dbg(module->dev, "Dynamic prepare %d DAI\n", data_cport); - } - - return 0; -} - -static int gbaudio_module_disable_rx(struct gbaudio_module_info *module, int id) -{ - int ret; - u16 data_cport, cportid, i2s_port; - int module_state; - struct gbaudio_data_connection *data; - - /* find the dai */ - data = find_data(module, id); - if (!data) { - dev_err(module->dev, "%d:DATA connection missing\n", id); - return -ENODEV; - } - module_state = data->state[SNDRV_PCM_STREAM_CAPTURE]; - - if (module_state > GBAUDIO_CODEC_HWPARAMS) { - data_cport = data->connection->intf_cport_id; - ret = gb_audio_gb_deactivate_rx(module->mgmt_connection, - data_cport); - if (ret) { - dev_err_ratelimited(module->dev, - "deactivate_rx failed:%d\n", ret); - return ret; - } - dev_dbg(module->dev, "Dynamic deactivate %d DAI\n", data_cport); - data->state[SNDRV_PCM_STREAM_CAPTURE] = - GBAUDIO_CODEC_HWPARAMS; - } - - if (module_state > GBAUDIO_CODEC_SHUTDOWN) { - i2s_port = 0; /* fixed for now */ - cportid = data->connection->hd_cport_id; - ret = gb_audio_apbridgea_unregister_cport(data->connection, - i2s_port, cportid, - AUDIO_APBRIDGEA_DIRECTION_RX); - if (ret) { - dev_err_ratelimited(module->dev, - "unregister_cport failed:%d\n", - ret); - return ret; - } - dev_dbg(module->dev, "Dynamic Unregister %d DAI\n", cportid); - data->state[SNDRV_PCM_STREAM_CAPTURE] = - GBAUDIO_CODEC_SHUTDOWN; - } - - return 0; -} - -int gbaudio_module_update(struct gbaudio_codec_info *codec, - struct snd_soc_dapm_widget *w, - struct gbaudio_module_info *module, int enable) -{ - int dai_id, ret; - char intf_name[NAME_SIZE], dir[NAME_SIZE]; - - dev_dbg(module->dev, "%s:Module update %s sequence\n", w->name, - enable ? "Enable" : "Disable"); - - if ((w->id != snd_soc_dapm_aif_in) && (w->id != snd_soc_dapm_aif_out)) { - dev_dbg(codec->dev, "No action required for %s\n", w->name); - return 0; - } - - /* parse dai_id from AIF widget's stream_name */ - ret = sscanf(w->sname, "%s %d %s", intf_name, &dai_id, dir); - if (ret < 3) { - dev_err(codec->dev, "Error while parsing dai_id for %s\n", - w->name); - return -EINVAL; - } - - mutex_lock(&codec->lock); - if (w->id == snd_soc_dapm_aif_in) { - if (enable) - ret = gbaudio_module_enable_tx(codec, module, dai_id); - else - ret = gbaudio_module_disable_tx(module, dai_id); - } else if (w->id == snd_soc_dapm_aif_out) { - if (enable) - ret = gbaudio_module_enable_rx(codec, module, dai_id); - else - ret = gbaudio_module_disable_rx(module, dai_id); - } - - mutex_unlock(&codec->lock); - - return ret; -} -EXPORT_SYMBOL(gbaudio_module_update); - -/* - * codec DAI ops - */ -static int gbcodec_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev); - struct gbaudio_stream_params *params; - - mutex_lock(&codec->lock); - - if (list_empty(&codec->module_list)) { - dev_err(codec->dev, "No codec module available\n"); - mutex_unlock(&codec->lock); - return -ENODEV; - } - - params = find_dai_stream_params(codec, dai->id, substream->stream); - if (!params) { - dev_err(codec->dev, "Failed to fetch dai_stream pointer\n"); - mutex_unlock(&codec->lock); - return -EINVAL; - } - params->state = GBAUDIO_CODEC_STARTUP; - mutex_unlock(&codec->lock); - /* to prevent suspend in case of active audio */ - pm_stay_awake(dai->dev); - - return 0; -} - -static void gbcodec_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev); - struct gbaudio_stream_params *params; - - mutex_lock(&codec->lock); - - if (list_empty(&codec->module_list)) - dev_info(codec->dev, "No codec module available during shutdown\n"); - - params = find_dai_stream_params(codec, dai->id, substream->stream); - if (!params) { - dev_err(codec->dev, "Failed to fetch dai_stream pointer\n"); - mutex_unlock(&codec->lock); - return; - } - params->state = GBAUDIO_CODEC_SHUTDOWN; - mutex_unlock(&codec->lock); - pm_relax(dai->dev); -} - -static int gbcodec_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hwparams, - struct snd_soc_dai *dai) -{ - int ret; - u8 sig_bits, channels; - u32 format, rate; - struct gbaudio_module_info *module; - struct gbaudio_data_connection *data; - struct gb_bundle *bundle; - struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev); - struct gbaudio_stream_params *params; - - mutex_lock(&codec->lock); - - if (list_empty(&codec->module_list)) { - dev_err(codec->dev, "No codec module available\n"); - mutex_unlock(&codec->lock); - return -ENODEV; - } - - /* - * assuming, currently only 48000 Hz, 16BIT_LE, stereo - * is supported, validate params before configuring codec - */ - if (params_channels(hwparams) != 2) { - dev_err(dai->dev, "Invalid channel count:%d\n", - params_channels(hwparams)); - mutex_unlock(&codec->lock); - return -EINVAL; - } - channels = params_channels(hwparams); - - if (params_rate(hwparams) != 48000) { - dev_err(dai->dev, "Invalid sampling rate:%d\n", - params_rate(hwparams)); - mutex_unlock(&codec->lock); - return -EINVAL; - } - rate = GB_AUDIO_PCM_RATE_48000; - - if (params_format(hwparams) != SNDRV_PCM_FORMAT_S16_LE) { - dev_err(dai->dev, "Invalid format:%d\n", - params_format(hwparams)); - mutex_unlock(&codec->lock); - return -EINVAL; - } - format = GB_AUDIO_PCM_FMT_S16_LE; - - /* find the data connection */ - list_for_each_entry(module, &codec->module_list, list) { - data = find_data(module, dai->id); - if (data) - break; - } - - if (!data) { - dev_err(dai->dev, "DATA connection missing\n"); - mutex_unlock(&codec->lock); - return -EINVAL; - } - - params = find_dai_stream_params(codec, dai->id, substream->stream); - if (!params) { - dev_err(codec->dev, "Failed to fetch dai_stream pointer\n"); - mutex_unlock(&codec->lock); - return -EINVAL; - } - - bundle = to_gb_bundle(module->dev); - ret = gb_pm_runtime_get_sync(bundle); - if (ret) { - mutex_unlock(&codec->lock); - return ret; - } - - ret = gb_audio_apbridgea_set_config(data->connection, 0, - AUDIO_APBRIDGEA_PCM_FMT_16, - AUDIO_APBRIDGEA_PCM_RATE_48000, - 6144000); - if (ret) { - dev_err_ratelimited(dai->dev, "%d: Error during set_config\n", - ret); - mutex_unlock(&codec->lock); - return ret; - } - - gb_pm_runtime_put_noidle(bundle); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - sig_bits = dai->driver->playback.sig_bits; - else - sig_bits = dai->driver->capture.sig_bits; - - params->state = GBAUDIO_CODEC_HWPARAMS; - params->format = format; - params->rate = rate; - params->channels = channels; - params->sig_bits = sig_bits; - - mutex_unlock(&codec->lock); - return 0; -} - -static int gbcodec_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - int ret; - struct gbaudio_module_info *module; - struct gbaudio_data_connection *data; - struct gb_bundle *bundle; - struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev); - struct gbaudio_stream_params *params; - - mutex_lock(&codec->lock); - - if (list_empty(&codec->module_list)) { - dev_err(codec->dev, "No codec module available\n"); - mutex_unlock(&codec->lock); - return -ENODEV; - } - - list_for_each_entry(module, &codec->module_list, list) { - /* find the dai */ - data = find_data(module, dai->id); - if (data) - break; - } - if (!data) { - dev_err(dai->dev, "DATA connection missing\n"); - mutex_unlock(&codec->lock); - return -ENODEV; - } - - params = find_dai_stream_params(codec, dai->id, substream->stream); - if (!params) { - dev_err(codec->dev, "Failed to fetch dai_stream pointer\n"); - mutex_unlock(&codec->lock); - return -EINVAL; - } - - bundle = to_gb_bundle(module->dev); - ret = gb_pm_runtime_get_sync(bundle); - if (ret) { - mutex_unlock(&codec->lock); - return ret; - } - - switch (substream->stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - ret = gb_audio_apbridgea_set_tx_data_size(data->connection, 0, - 192); - break; - case SNDRV_PCM_STREAM_CAPTURE: - ret = gb_audio_apbridgea_set_rx_data_size(data->connection, 0, - 192); - break; - } - if (ret) { - mutex_unlock(&codec->lock); - dev_err_ratelimited(dai->dev, "set_data_size failed:%d\n", - ret); - return ret; - } - - gb_pm_runtime_put_noidle(bundle); - - params->state = GBAUDIO_CODEC_PREPARE; - mutex_unlock(&codec->lock); - return 0; -} - -static int gbcodec_mute_stream(struct snd_soc_dai *dai, int mute, int stream) -{ - int ret; - struct gbaudio_data_connection *data; - struct gbaudio_module_info *module; - struct gb_bundle *bundle; - struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev); - struct gbaudio_stream_params *params; - - dev_dbg(dai->dev, "Mute:%d, Direction:%s\n", mute, - stream ? "CAPTURE" : "PLAYBACK"); - - mutex_lock(&codec->lock); - - params = find_dai_stream_params(codec, dai->id, stream); - if (!params) { - dev_err(codec->dev, "Failed to fetch dai_stream pointer\n"); - mutex_unlock(&codec->lock); - return -EINVAL; - } - - if (list_empty(&codec->module_list)) { - dev_err(codec->dev, "No codec module available\n"); - if (mute) { - params->state = GBAUDIO_CODEC_STOP; - ret = 0; - } else { - ret = -ENODEV; - } - mutex_unlock(&codec->lock); - return ret; - } - - list_for_each_entry(module, &codec->module_list, list) { - /* find the dai */ - data = find_data(module, dai->id); - if (data) - break; - } - if (!data) { - dev_err(dai->dev, "%s:%s DATA connection missing\n", - dai->name, module->name); - mutex_unlock(&codec->lock); - return -ENODEV; - } - - bundle = to_gb_bundle(module->dev); - ret = gb_pm_runtime_get_sync(bundle); - if (ret) { - mutex_unlock(&codec->lock); - return ret; - } - - if (!mute && !stream) {/* start playback */ - ret = gb_audio_apbridgea_prepare_tx(data->connection, - 0); - if (!ret) - ret = gb_audio_apbridgea_start_tx(data->connection, - 0, 0); - params->state = GBAUDIO_CODEC_START; - } else if (!mute && stream) {/* start capture */ - ret = gb_audio_apbridgea_prepare_rx(data->connection, - 0); - if (!ret) - ret = gb_audio_apbridgea_start_rx(data->connection, - 0); - params->state = GBAUDIO_CODEC_START; - } else if (mute && !stream) {/* stop playback */ - ret = gb_audio_apbridgea_stop_tx(data->connection, 0); - if (!ret) - ret = gb_audio_apbridgea_shutdown_tx(data->connection, - 0); - params->state = GBAUDIO_CODEC_STOP; - } else if (mute && stream) {/* stop capture */ - ret = gb_audio_apbridgea_stop_rx(data->connection, 0); - if (!ret) - ret = gb_audio_apbridgea_shutdown_rx(data->connection, - 0); - params->state = GBAUDIO_CODEC_STOP; - } else { - ret = -EINVAL; - } - - if (ret) - dev_err_ratelimited(dai->dev, - "%s:Error during %s %s stream:%d\n", - module->name, mute ? "Mute" : "Unmute", - stream ? "Capture" : "Playback", ret); - - gb_pm_runtime_put_noidle(bundle); - mutex_unlock(&codec->lock); - return ret; -} - -static const struct snd_soc_dai_ops gbcodec_dai_ops = { - .startup = gbcodec_startup, - .shutdown = gbcodec_shutdown, - .hw_params = gbcodec_hw_params, - .prepare = gbcodec_prepare, - .mute_stream = gbcodec_mute_stream, -}; - -static struct snd_soc_dai_driver gbaudio_dai[] = { - { - .name = "apb-i2s0", - .id = 0, - .playback = { - .stream_name = "I2S 0 Playback", - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FORMAT_S16_LE, - .rate_max = 48000, - .rate_min = 48000, - .channels_min = 1, - .channels_max = 2, - .sig_bits = 16, - }, - .capture = { - .stream_name = "I2S 0 Capture", - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FORMAT_S16_LE, - .rate_max = 48000, - .rate_min = 48000, - .channels_min = 1, - .channels_max = 2, - .sig_bits = 16, - }, - .ops = &gbcodec_dai_ops, - }, -}; - -static int gbaudio_init_jack(struct gbaudio_module_info *module, - struct snd_soc_codec *codec) -{ - int ret; - - if (!module->jack_mask) - return 0; - - snprintf(module->jack_name, NAME_SIZE, "GB %d Headset Jack", - module->dev_id); - ret = snd_soc_jack_new(codec, module->jack_name, module->jack_mask, - &module->headset_jack); - if (ret) { - dev_err(module->dev, "Failed to create new jack\n"); - return ret; - } - - if (!module->button_mask) - return 0; - - snprintf(module->button_name, NAME_SIZE, "GB %d Button Jack", - module->dev_id); - ret = snd_soc_jack_new(codec, module->button_name, module->button_mask, - &module->button_jack); - if (ret) { - dev_err(module->dev, "Failed to create button jack\n"); - return ret; - } - - /* - * Currently, max 4 buttons are supported with following key mapping - * BTN_0 = KEY_MEDIA - * BTN_1 = KEY_VOICECOMMAND - * BTN_2 = KEY_VOLUMEUP - * BTN_3 = KEY_VOLUMEDOWN - */ - - if (module->button_mask & SND_JACK_BTN_0) { - ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_0, - KEY_MEDIA); - if (ret) { - dev_err(module->dev, "Failed to set BTN_0\n"); - return ret; - } - } - - if (module->button_mask & SND_JACK_BTN_1) { - ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_1, - KEY_VOICECOMMAND); - if (ret) { - dev_err(module->dev, "Failed to set BTN_1\n"); - return ret; - } - } - - if (module->button_mask & SND_JACK_BTN_2) { - ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_2, - KEY_VOLUMEUP); - if (ret) { - dev_err(module->dev, "Failed to set BTN_2\n"); - return ret; - } - } - - if (module->button_mask & SND_JACK_BTN_3) { - ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_3, - KEY_VOLUMEDOWN); - if (ret) { - dev_err(module->dev, "Failed to set BTN_0\n"); - return ret; - } - } - - /* FIXME - * verify if this is really required - set_bit(INPUT_PROP_NO_DUMMY_RELEASE, - module->button_jack.jack->input_dev->propbit); - */ - - return 0; -} - -int gbaudio_register_module(struct gbaudio_module_info *module) -{ - int ret; - struct snd_soc_codec *codec; - struct snd_card *card; - struct snd_soc_jack *jack = NULL; - - if (!gbcodec) { - dev_err(module->dev, "GB Codec not yet probed\n"); - return -EAGAIN; - } - - codec = gbcodec->codec; - card = codec->card->snd_card; - - down_write(&card->controls_rwsem); - - if (module->num_dais) { - dev_err(gbcodec->dev, - "%d:DAIs not supported via gbcodec driver\n", - module->num_dais); - up_write(&card->controls_rwsem); - return -EINVAL; - } - - ret = gbaudio_init_jack(module, codec); - if (ret) { - up_write(&card->controls_rwsem); - return ret; - } - - if (module->dapm_widgets) - snd_soc_dapm_new_controls(&codec->dapm, module->dapm_widgets, - module->num_dapm_widgets); - if (module->controls) - snd_soc_add_codec_controls(codec, module->controls, - module->num_controls); - if (module->dapm_routes) - snd_soc_dapm_add_routes(&codec->dapm, module->dapm_routes, - module->num_dapm_routes); - - /* card already instantiated, create widgets here only */ - if (codec->card->instantiated) { - snd_soc_dapm_link_component_dai_widgets(codec->card, - &codec->dapm); -#ifdef CONFIG_SND_JACK - /* - * register jack devices for this module - * from codec->jack_list - */ - list_for_each_entry(jack, &codec->jack_list, list) { - if ((jack == &module->headset_jack) || - (jack == &module->button_jack)) - snd_device_register(codec->card->snd_card, - jack->jack); - } -#endif - } - - mutex_lock(&gbcodec->lock); - list_add(&module->list, &gbcodec->module_list); - mutex_unlock(&gbcodec->lock); - - if (codec->card->instantiated) - ret = snd_soc_dapm_new_widgets(&codec->dapm); - dev_dbg(codec->dev, "Registered %s module\n", module->name); - - up_write(&card->controls_rwsem); - return ret; -} -EXPORT_SYMBOL(gbaudio_register_module); - -static void gbaudio_codec_clean_data_tx(struct gbaudio_data_connection *data) -{ - u16 i2s_port, cportid; - int ret; - - if (list_is_singular(&gbcodec->module_list)) { - ret = gb_audio_apbridgea_stop_tx(data->connection, 0); - if (ret) - return; - ret = gb_audio_apbridgea_shutdown_tx(data->connection, - 0); - if (ret) - return; - } - i2s_port = 0; /* fixed for now */ - cportid = data->connection->hd_cport_id; - ret = gb_audio_apbridgea_unregister_cport(data->connection, - i2s_port, cportid, - AUDIO_APBRIDGEA_DIRECTION_TX); - data->state[0] = GBAUDIO_CODEC_SHUTDOWN; -} - -static void gbaudio_codec_clean_data_rx(struct gbaudio_data_connection *data) -{ - u16 i2s_port, cportid; - int ret; - - if (list_is_singular(&gbcodec->module_list)) { - ret = gb_audio_apbridgea_stop_rx(data->connection, 0); - if (ret) - return; - ret = gb_audio_apbridgea_shutdown_rx(data->connection, - 0); - if (ret) - return; - } - i2s_port = 0; /* fixed for now */ - cportid = data->connection->hd_cport_id; - ret = gb_audio_apbridgea_unregister_cport(data->connection, - i2s_port, cportid, - AUDIO_APBRIDGEA_DIRECTION_RX); - data->state[1] = GBAUDIO_CODEC_SHUTDOWN; -} - -static void gbaudio_codec_cleanup(struct gbaudio_module_info *module) -{ - struct gbaudio_data_connection *data; - int pb_state, cap_state; - - dev_dbg(gbcodec->dev, "%s: removed, cleanup APBridge\n", module->name); - list_for_each_entry(data, &module->data_list, list) { - pb_state = data->state[0]; - cap_state = data->state[1]; - - if (pb_state > GBAUDIO_CODEC_SHUTDOWN) - gbaudio_codec_clean_data_tx(data); - - if (cap_state > GBAUDIO_CODEC_SHUTDOWN) - gbaudio_codec_clean_data_rx(data); - } -} - -void gbaudio_unregister_module(struct gbaudio_module_info *module) -{ - struct snd_soc_codec *codec = gbcodec->codec; - struct snd_card *card = codec->card->snd_card; - struct snd_soc_jack *jack, *next_j; - int mask; - - dev_dbg(codec->dev, "Unregister %s module\n", module->name); - - down_write(&card->controls_rwsem); - mutex_lock(&gbcodec->lock); - gbaudio_codec_cleanup(module); - list_del(&module->list); - dev_dbg(codec->dev, "Process Unregister %s module\n", module->name); - mutex_unlock(&gbcodec->lock); - -#ifdef CONFIG_SND_JACK - /* free jack devices for this module from codec->jack_list */ - list_for_each_entry_safe(jack, next_j, &codec->jack_list, list) { - if (jack == &module->headset_jack) - mask = GBCODEC_JACK_MASK; - else if (jack == &module->button_jack) - mask = GBCODEC_JACK_BUTTON_MASK; - else - mask = 0; - if (mask) { - dev_dbg(module->dev, "Report %s removal\n", - jack->jack->id); - snd_soc_jack_report(jack, 0, mask); - snd_device_free(codec->card->snd_card, jack->jack); - list_del(&jack->list); - } - } -#endif - - if (module->dapm_routes) { - dev_dbg(codec->dev, "Removing %d routes\n", - module->num_dapm_routes); - snd_soc_dapm_del_routes(&codec->dapm, module->dapm_routes, - module->num_dapm_routes); - } - if (module->controls) { - dev_dbg(codec->dev, "Removing %d controls\n", - module->num_controls); - snd_soc_remove_codec_controls(codec, module->controls, - module->num_controls); - } - if (module->dapm_widgets) { - dev_dbg(codec->dev, "Removing %d widgets\n", - module->num_dapm_widgets); - snd_soc_dapm_free_controls(&codec->dapm, module->dapm_widgets, - module->num_dapm_widgets); - } - - dev_dbg(codec->dev, "Unregistered %s module\n", module->name); - - up_write(&card->controls_rwsem); -} -EXPORT_SYMBOL(gbaudio_unregister_module); - -/* - * codec driver ops - */ -static int gbcodec_probe(struct snd_soc_codec *codec) -{ - int i; - struct gbaudio_codec_info *info; - struct gbaudio_codec_dai *dai; - - info = devm_kzalloc(codec->dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->dev = codec->dev; - INIT_LIST_HEAD(&info->module_list); - mutex_init(&info->lock); - INIT_LIST_HEAD(&info->dai_list); - - /* init dai_list used to maintain runtime stream info */ - for (i = 0; i < ARRAY_SIZE(gbaudio_dai); i++) { - dai = devm_kzalloc(codec->dev, sizeof(*dai), GFP_KERNEL); - if (!dai) - return -ENOMEM; - dai->id = gbaudio_dai[i].id; - list_add(&dai->list, &info->dai_list); - } - - info->codec = codec; - snd_soc_codec_set_drvdata(codec, info); - gbcodec = info; - - device_init_wakeup(codec->dev, 1); - return 0; -} - -static int gbcodec_remove(struct snd_soc_codec *codec) -{ - /* Empty function for now */ - return 0; -} - -static int gbcodec_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - return 0; -} - -static unsigned int gbcodec_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return 0; -} - -static struct snd_soc_codec_driver soc_codec_dev_gbaudio = { - .probe = gbcodec_probe, - .remove = gbcodec_remove, - - .read = gbcodec_read, - .write = gbcodec_write, - - .idle_bias_off = true, - .ignore_pmdown_time = 1, -}; - -#ifdef CONFIG_PM -static int gbaudio_codec_suspend(struct device *dev) -{ - dev_dbg(dev, "%s: suspend\n", __func__); - return 0; -} - -static int gbaudio_codec_resume(struct device *dev) -{ - dev_dbg(dev, "%s: resume\n", __func__); - return 0; -} - -static const struct dev_pm_ops gbaudio_codec_pm_ops = { - .suspend = gbaudio_codec_suspend, - .resume = gbaudio_codec_resume, -}; -#endif - -static int gbaudio_codec_probe(struct platform_device *pdev) -{ - return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_gbaudio, - gbaudio_dai, ARRAY_SIZE(gbaudio_dai)); -} - -static int gbaudio_codec_remove(struct platform_device *pdev) -{ - snd_soc_unregister_codec(&pdev->dev); - return 0; -} - -static const struct of_device_id greybus_asoc_machine_of_match[] = { - { .compatible = "toshiba,apb-dummy-codec", }, - {}, -}; - -static struct platform_driver gbaudio_codec_driver = { - .driver = { - .name = "apb-dummy-codec", -#ifdef CONFIG_PM - .pm = &gbaudio_codec_pm_ops, -#endif - .of_match_table = greybus_asoc_machine_of_match, - }, - .probe = gbaudio_codec_probe, - .remove = gbaudio_codec_remove, -}; -module_platform_driver(gbaudio_codec_driver); - -MODULE_DESCRIPTION("APBridge ALSA SoC dummy codec driver"); -MODULE_AUTHOR("Vaibhav Agarwal vaibhav.agarwal@linaro.org"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:apb-dummy-codec"); diff --git a/drivers/staging/greybus/audio_module.c b/drivers/staging/greybus/audio_module.c deleted file mode 100644 index 300a2b4f3fc7..000000000000 --- a/drivers/staging/greybus/audio_module.c +++ /dev/null @@ -1,478 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Greybus audio driver - * Copyright 2015 Google Inc. - * Copyright 2015 Linaro Ltd. - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <sound/soc.h> -#include <sound/pcm_params.h> - -#include "audio_codec.h" -#include "audio_apbridgea.h" -#include "audio_manager.h" - -/* - * gb_snd management functions - */ - -static int gbaudio_request_jack(struct gbaudio_module_info *module, - struct gb_audio_jack_event_request *req) -{ - int report; - struct snd_jack *jack = module->headset_jack.jack; - struct snd_jack *btn_jack = module->button_jack.jack; - - if (!jack) { - dev_err_ratelimited(module->dev, - "Invalid jack event received:type: %u, event: %u\n", - req->jack_attribute, req->event); - return -EINVAL; - } - - dev_warn_ratelimited(module->dev, - "Jack Event received: type: %u, event: %u\n", - req->jack_attribute, req->event); - - if (req->event == GB_AUDIO_JACK_EVENT_REMOVAL) { - module->jack_type = 0; - if (btn_jack && module->button_status) { - snd_soc_jack_report(&module->button_jack, 0, - module->button_mask); - module->button_status = 0; - } - snd_soc_jack_report(&module->headset_jack, 0, - module->jack_mask); - return 0; - } - - report = req->jack_attribute & module->jack_mask; - if (!report) { - dev_err_ratelimited(module->dev, - "Invalid jack event received:type: %u, event: %u\n", - req->jack_attribute, req->event); - return -EINVAL; - } - - if (module->jack_type) - dev_warn_ratelimited(module->dev, - "Modifying jack from %d to %d\n", - module->jack_type, report); - - module->jack_type = report; - snd_soc_jack_report(&module->headset_jack, report, module->jack_mask); - - return 0; -} - -static int gbaudio_request_button(struct gbaudio_module_info *module, - struct gb_audio_button_event_request *req) -{ - int soc_button_id, report; - struct snd_jack *btn_jack = module->button_jack.jack; - - if (!btn_jack) { - dev_err_ratelimited(module->dev, - "Invalid button event received:type: %u, event: %u\n", - req->button_id, req->event); - return -EINVAL; - } - - dev_warn_ratelimited(module->dev, - "Button Event received: id: %u, event: %u\n", - req->button_id, req->event); - - /* currently supports 4 buttons only */ - if (!module->jack_type) { - dev_err_ratelimited(module->dev, - "Jack not present. Bogus event!!\n"); - return -EINVAL; - } - - report = module->button_status & module->button_mask; - soc_button_id = 0; - - switch (req->button_id) { - case 1: - soc_button_id = SND_JACK_BTN_0 & module->button_mask; - break; - - case 2: - soc_button_id = SND_JACK_BTN_1 & module->button_mask; - break; - - case 3: - soc_button_id = SND_JACK_BTN_2 & module->button_mask; - break; - - case 4: - soc_button_id = SND_JACK_BTN_3 & module->button_mask; - break; - } - - if (!soc_button_id) { - dev_err_ratelimited(module->dev, - "Invalid button request received\n"); - return -EINVAL; - } - - if (req->event == GB_AUDIO_BUTTON_EVENT_PRESS) - report = report | soc_button_id; - else - report = report & ~soc_button_id; - - module->button_status = report; - - snd_soc_jack_report(&module->button_jack, report, module->button_mask); - - return 0; -} - -static int gbaudio_request_stream(struct gbaudio_module_info *module, - struct gb_audio_streaming_event_request *req) -{ - dev_warn(module->dev, "Audio Event received: cport: %u, event: %u\n", - le16_to_cpu(req->data_cport), req->event); - - return 0; -} - -static int gbaudio_codec_request_handler(struct gb_operation *op) -{ - struct gb_connection *connection = op->connection; - struct gbaudio_module_info *module = - greybus_get_drvdata(connection->bundle); - struct gb_operation_msg_hdr *header = op->request->header; - struct gb_audio_streaming_event_request *stream_req; - struct gb_audio_jack_event_request *jack_req; - struct gb_audio_button_event_request *button_req; - int ret; - - switch (header->type) { - case GB_AUDIO_TYPE_STREAMING_EVENT: - stream_req = op->request->payload; - ret = gbaudio_request_stream(module, stream_req); - break; - - case GB_AUDIO_TYPE_JACK_EVENT: - jack_req = op->request->payload; - ret = gbaudio_request_jack(module, jack_req); - break; - - case GB_AUDIO_TYPE_BUTTON_EVENT: - button_req = op->request->payload; - ret = gbaudio_request_button(module, button_req); - break; - - default: - dev_err_ratelimited(&connection->bundle->dev, - "Invalid Audio Event received\n"); - return -EINVAL; - } - - return ret; -} - -static int gb_audio_add_mgmt_connection(struct gbaudio_module_info *gbmodule, - struct greybus_descriptor_cport *cport_desc, - struct gb_bundle *bundle) -{ - struct gb_connection *connection; - - /* Management Cport */ - if (gbmodule->mgmt_connection) { - dev_err(&bundle->dev, - "Can't have multiple Management connections\n"); - return -ENODEV; - } - - connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), - gbaudio_codec_request_handler); - if (IS_ERR(connection)) - return PTR_ERR(connection); - - greybus_set_drvdata(bundle, gbmodule); - gbmodule->mgmt_connection = connection; - - return 0; -} - -static int gb_audio_add_data_connection(struct gbaudio_module_info *gbmodule, - struct greybus_descriptor_cport *cport_desc, - struct gb_bundle *bundle) -{ - struct gb_connection *connection; - struct gbaudio_data_connection *dai; - - dai = devm_kzalloc(gbmodule->dev, sizeof(*dai), GFP_KERNEL); - if (!dai) - return -ENOMEM; - - connection = gb_connection_create_offloaded(bundle, - le16_to_cpu(cport_desc->id), - GB_CONNECTION_FLAG_CSD); - if (IS_ERR(connection)) { - devm_kfree(gbmodule->dev, dai); - return PTR_ERR(connection); - } - - greybus_set_drvdata(bundle, gbmodule); - dai->id = 0; - dai->data_cport = connection->intf_cport_id; - dai->connection = connection; - list_add(&dai->list, &gbmodule->data_list); - - return 0; -} - -/* - * This is the basic hook get things initialized and registered w/ gb - */ - -static int gb_audio_probe(struct gb_bundle *bundle, - const struct greybus_bundle_id *id) -{ - struct device *dev = &bundle->dev; - struct gbaudio_module_info *gbmodule; - struct greybus_descriptor_cport *cport_desc; - struct gb_audio_manager_module_descriptor desc; - struct gbaudio_data_connection *dai, *_dai; - int ret, i; - struct gb_audio_topology *topology; - - /* There should be at least one Management and one Data cport */ - if (bundle->num_cports < 2) - return -ENODEV; - - /* - * There can be only one Management connection and any number of data - * connections. - */ - gbmodule = devm_kzalloc(dev, sizeof(*gbmodule), GFP_KERNEL); - if (!gbmodule) - return -ENOMEM; - - gbmodule->num_data_connections = bundle->num_cports - 1; - INIT_LIST_HEAD(&gbmodule->data_list); - INIT_LIST_HEAD(&gbmodule->widget_list); - INIT_LIST_HEAD(&gbmodule->ctl_list); - INIT_LIST_HEAD(&gbmodule->widget_ctl_list); - gbmodule->dev = dev; - snprintf(gbmodule->name, NAME_SIZE, "%s.%s", dev->driver->name, - dev_name(dev)); - greybus_set_drvdata(bundle, gbmodule); - - /* Create all connections */ - for (i = 0; i < bundle->num_cports; i++) { - cport_desc = &bundle->cport_desc[i]; - - switch (cport_desc->protocol_id) { - case GREYBUS_PROTOCOL_AUDIO_MGMT: - ret = gb_audio_add_mgmt_connection(gbmodule, cport_desc, - bundle); - if (ret) - goto destroy_connections; - break; - case GREYBUS_PROTOCOL_AUDIO_DATA: - ret = gb_audio_add_data_connection(gbmodule, cport_desc, - bundle); - if (ret) - goto destroy_connections; - break; - default: - dev_err(dev, "Unsupported protocol: 0x%02x\n", - cport_desc->protocol_id); - ret = -ENODEV; - goto destroy_connections; - } - } - - /* There must be a management cport */ - if (!gbmodule->mgmt_connection) { - ret = -EINVAL; - dev_err(dev, "Missing management connection\n"); - goto destroy_connections; - } - - /* Initialize management connection */ - ret = gb_connection_enable(gbmodule->mgmt_connection); - if (ret) { - dev_err(dev, "%d: Error while enabling mgmt connection\n", ret); - goto destroy_connections; - } - gbmodule->dev_id = gbmodule->mgmt_connection->intf->interface_id; - - /* - * FIXME: malloc for topology happens via audio_gb driver - * should be done within codec driver itself - */ - ret = gb_audio_gb_get_topology(gbmodule->mgmt_connection, &topology); - if (ret) { - dev_err(dev, "%d:Error while fetching topology\n", ret); - goto disable_connection; - } - - /* process topology data */ - ret = gbaudio_tplg_parse_data(gbmodule, topology); - if (ret) { - dev_err(dev, "%d:Error while parsing topology data\n", - ret); - goto free_topology; - } - gbmodule->topology = topology; - - /* Initialize data connections */ - list_for_each_entry(dai, &gbmodule->data_list, list) { - ret = gb_connection_enable(dai->connection); - if (ret) { - dev_err(dev, - "%d:Error while enabling %d:data connection\n", - ret, dai->data_cport); - goto disable_data_connection; - } - } - - /* register module with gbcodec */ - ret = gbaudio_register_module(gbmodule); - if (ret) - goto disable_data_connection; - - /* inform above layer for uevent */ - dev_dbg(dev, "Inform set_event:%d to above layer\n", 1); - /* prepare for the audio manager */ - strlcpy(desc.name, gbmodule->name, GB_AUDIO_MANAGER_MODULE_NAME_LEN); - desc.vid = 2; /* todo */ - desc.pid = 3; /* todo */ - desc.intf_id = gbmodule->dev_id; - desc.op_devices = gbmodule->op_devices; - desc.ip_devices = gbmodule->ip_devices; - gbmodule->manager_id = gb_audio_manager_add(&desc); - - dev_dbg(dev, "Add GB Audio device:%s\n", gbmodule->name); - - gb_pm_runtime_put_autosuspend(bundle); - - return 0; - -disable_data_connection: - list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) - gb_connection_disable(dai->connection); - gbaudio_tplg_release(gbmodule); - gbmodule->topology = NULL; - -free_topology: - kfree(topology); - -disable_connection: - gb_connection_disable(gbmodule->mgmt_connection); - -destroy_connections: - list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) { - gb_connection_destroy(dai->connection); - list_del(&dai->list); - devm_kfree(dev, dai); - } - - if (gbmodule->mgmt_connection) - gb_connection_destroy(gbmodule->mgmt_connection); - - devm_kfree(dev, gbmodule); - - return ret; -} - -static void gb_audio_disconnect(struct gb_bundle *bundle) -{ - struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle); - struct gbaudio_data_connection *dai, *_dai; - - gb_pm_runtime_get_sync(bundle); - - /* cleanup module related resources first */ - gbaudio_unregister_module(gbmodule); - - /* inform uevent to above layers */ - gb_audio_manager_remove(gbmodule->manager_id); - - gbaudio_tplg_release(gbmodule); - kfree(gbmodule->topology); - gbmodule->topology = NULL; - gb_connection_disable(gbmodule->mgmt_connection); - list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) { - gb_connection_disable(dai->connection); - gb_connection_destroy(dai->connection); - list_del(&dai->list); - devm_kfree(gbmodule->dev, dai); - } - gb_connection_destroy(gbmodule->mgmt_connection); - gbmodule->mgmt_connection = NULL; - - devm_kfree(&bundle->dev, gbmodule); -} - -static const struct greybus_bundle_id gb_audio_id_table[] = { - { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO) }, - { } -}; -MODULE_DEVICE_TABLE(greybus, gb_audio_id_table); - -#ifdef CONFIG_PM -static int gb_audio_suspend(struct device *dev) -{ - struct gb_bundle *bundle = to_gb_bundle(dev); - struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle); - struct gbaudio_data_connection *dai; - - list_for_each_entry(dai, &gbmodule->data_list, list) - gb_connection_disable(dai->connection); - - gb_connection_disable(gbmodule->mgmt_connection); - - return 0; -} - -static int gb_audio_resume(struct device *dev) -{ - struct gb_bundle *bundle = to_gb_bundle(dev); - struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle); - struct gbaudio_data_connection *dai; - int ret; - - ret = gb_connection_enable(gbmodule->mgmt_connection); - if (ret) { - dev_err(dev, "%d:Error while enabling mgmt connection\n", ret); - return ret; - } - - list_for_each_entry(dai, &gbmodule->data_list, list) { - ret = gb_connection_enable(dai->connection); - if (ret) { - dev_err(dev, - "%d:Error while enabling %d:data connection\n", - ret, dai->data_cport); - return ret; - } - } - - return 0; -} -#endif - -static const struct dev_pm_ops gb_audio_pm_ops = { - SET_RUNTIME_PM_OPS(gb_audio_suspend, gb_audio_resume, NULL) -}; - -static struct greybus_driver gb_audio_driver = { - .name = "gb-audio", - .probe = gb_audio_probe, - .disconnect = gb_audio_disconnect, - .id_table = gb_audio_id_table, - .driver.pm = &gb_audio_pm_ops, -}; -module_greybus_driver(gb_audio_driver); - -MODULE_DESCRIPTION("Greybus Audio module driver"); -MODULE_AUTHOR("Vaibhav Agarwal vaibhav.agarwal@linaro.org"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:gbaudio-module"); diff --git a/drivers/staging/greybus/audio_topology.c b/drivers/staging/greybus/audio_topology.c deleted file mode 100644 index 4ac30accf226..000000000000 --- a/drivers/staging/greybus/audio_topology.c +++ /dev/null @@ -1,1448 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Greybus audio driver - * Copyright 2015-2016 Google Inc. - * Copyright 2015-2016 Linaro Ltd. - */ - -#include "audio_codec.h" -#include "greybus_protocols.h" - -#define GBAUDIO_INVALID_ID 0xFF - -/* mixer control */ -struct gb_mixer_control { - int min, max; - unsigned int reg, rreg, shift, rshift, invert; -}; - -struct gbaudio_ctl_pvt { - unsigned int ctl_id; - unsigned int data_cport; - unsigned int access; - unsigned int vcount; - struct gb_audio_ctl_elem_info *info; -}; - -static struct gbaudio_module_info *find_gb_module( - struct gbaudio_codec_info *codec, - char const *name) -{ - int dev_id, ret; - char begin[NAME_SIZE]; - struct gbaudio_module_info *module; - - if (!name) - return NULL; - - ret = sscanf(name, "%s %d", begin, &dev_id); - dev_dbg(codec->dev, "%s:Find module#%d\n", __func__, dev_id); - - mutex_lock(&codec->lock); - list_for_each_entry(module, &codec->module_list, list) { - if (module->dev_id == dev_id) { - mutex_unlock(&codec->lock); - return module; - } - } - mutex_unlock(&codec->lock); - dev_warn(codec->dev, "%s: module#%d missing in codec list\n", name, - dev_id); - return NULL; -} - -static const char *gbaudio_map_controlid(struct gbaudio_module_info *module, - __u8 control_id, __u8 index) -{ - struct gbaudio_control *control; - - if (control_id == GBAUDIO_INVALID_ID) - return NULL; - - list_for_each_entry(control, &module->ctl_list, list) { - if (control->id == control_id) { - if (index == GBAUDIO_INVALID_ID) - return control->name; - if (index >= control->items) - return NULL; - return control->texts[index]; - } - } - list_for_each_entry(control, &module->widget_ctl_list, list) { - if (control->id == control_id) { - if (index == GBAUDIO_INVALID_ID) - return control->name; - if (index >= control->items) - return NULL; - return control->texts[index]; - } - } - return NULL; -} - -static int gbaudio_map_controlname(struct gbaudio_module_info *module, - const char *name) -{ - struct gbaudio_control *control; - - list_for_each_entry(control, &module->ctl_list, list) { - if (!strncmp(control->name, name, NAME_SIZE)) - return control->id; - } - - dev_warn(module->dev, "%s: missing in modules controls list\n", name); - - return -EINVAL; -} - -static int gbaudio_map_wcontrolname(struct gbaudio_module_info *module, - const char *name) -{ - struct gbaudio_control *control; - - list_for_each_entry(control, &module->widget_ctl_list, list) { - if (!strncmp(control->wname, name, NAME_SIZE)) - return control->id; - } - dev_warn(module->dev, "%s: missing in modules controls list\n", name); - - return -EINVAL; -} - -static int gbaudio_map_widgetname(struct gbaudio_module_info *module, - const char *name) -{ - struct gbaudio_widget *widget; - - list_for_each_entry(widget, &module->widget_list, list) { - if (!strncmp(widget->name, name, NAME_SIZE)) - return widget->id; - } - dev_warn(module->dev, "%s: missing in modules widgets list\n", name); - - return -EINVAL; -} - -static const char *gbaudio_map_widgetid(struct gbaudio_module_info *module, - __u8 widget_id) -{ - struct gbaudio_widget *widget; - - list_for_each_entry(widget, &module->widget_list, list) { - if (widget->id == widget_id) - return widget->name; - } - return NULL; -} - -static const char **gb_generate_enum_strings(struct gbaudio_module_info *gb, - struct gb_audio_enumerated *gbenum) -{ - const char **strings; - int i; - unsigned int items; - __u8 *data; - - items = le32_to_cpu(gbenum->items); - strings = devm_kcalloc(gb->dev, items, sizeof(char *), GFP_KERNEL); - data = gbenum->names; - - for (i = 0; i < items; i++) { - strings[i] = (const char *)data; - while (*data != '\0') - data++; - data++; - } - - return strings; -} - -static int gbcodec_mixer_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - unsigned int max; - const char *name; - struct gbaudio_ctl_pvt *data; - struct gb_audio_ctl_elem_info *info; - struct gbaudio_module_info *module; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct gbaudio_codec_info *gbcodec = snd_soc_codec_get_drvdata(codec); - - dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name); - data = (struct gbaudio_ctl_pvt *)kcontrol->private_value; - info = (struct gb_audio_ctl_elem_info *)data->info; - - if (!info) { - dev_err(codec->dev, "NULL info for %s\n", uinfo->id.name); - return -EINVAL; - } - - /* update uinfo */ - uinfo->access = data->access; - uinfo->count = data->vcount; - uinfo->type = (snd_ctl_elem_type_t)info->type; - - switch (info->type) { - case GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN: - case GB_AUDIO_CTL_ELEM_TYPE_INTEGER: - uinfo->value.integer.min = le32_to_cpu(info->value.integer.min); - uinfo->value.integer.max = le32_to_cpu(info->value.integer.max); - break; - case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED: - max = le32_to_cpu(info->value.enumerated.items); - uinfo->value.enumerated.items = max; - if (uinfo->value.enumerated.item > max - 1) - uinfo->value.enumerated.item = max - 1; - module = find_gb_module(gbcodec, kcontrol->id.name); - if (!module) - return -EINVAL; - name = gbaudio_map_controlid(module, data->ctl_id, - uinfo->value.enumerated.item); - strlcpy(uinfo->value.enumerated.name, name, NAME_SIZE); - break; - default: - dev_err(codec->dev, "Invalid type: %d for %s:kcontrol\n", - info->type, kcontrol->id.name); - break; - } - return 0; -} - -static int gbcodec_mixer_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int ret; - struct gb_audio_ctl_elem_info *info; - struct gbaudio_ctl_pvt *data; - struct gb_audio_ctl_elem_value gbvalue; - struct gbaudio_module_info *module; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec); - struct gb_bundle *bundle; - - dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name); - module = find_gb_module(gb, kcontrol->id.name); - if (!module) - return -EINVAL; - - data = (struct gbaudio_ctl_pvt *)kcontrol->private_value; - info = (struct gb_audio_ctl_elem_info *)data->info; - bundle = to_gb_bundle(module->dev); - - ret = gb_pm_runtime_get_sync(bundle); - if (ret) - return ret; - - ret = gb_audio_gb_get_control(module->mgmt_connection, data->ctl_id, - GB_AUDIO_INVALID_INDEX, &gbvalue); - - gb_pm_runtime_put_autosuspend(bundle); - - if (ret) { - dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret, - __func__, kcontrol->id.name); - return ret; - } - - /* update ucontrol */ - switch (info->type) { - case GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN: - case GB_AUDIO_CTL_ELEM_TYPE_INTEGER: - ucontrol->value.integer.value[0] = - le32_to_cpu(gbvalue.value.integer_value[0]); - if (data->vcount == 2) - ucontrol->value.integer.value[1] = - le32_to_cpu(gbvalue.value.integer_value[1]); - break; - case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED: - ucontrol->value.enumerated.item[0] = - le32_to_cpu(gbvalue.value.enumerated_item[0]); - if (data->vcount == 2) - ucontrol->value.enumerated.item[1] = - le32_to_cpu(gbvalue.value.enumerated_item[1]); - break; - default: - dev_err(codec->dev, "Invalid type: %d for %s:kcontrol\n", - info->type, kcontrol->id.name); - ret = -EINVAL; - break; - } - return ret; -} - -static int gbcodec_mixer_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int ret = 0; - struct gb_audio_ctl_elem_info *info; - struct gbaudio_ctl_pvt *data; - struct gb_audio_ctl_elem_value gbvalue; - struct gbaudio_module_info *module; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec); - struct gb_bundle *bundle; - - dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name); - module = find_gb_module(gb, kcontrol->id.name); - if (!module) - return -EINVAL; - - data = (struct gbaudio_ctl_pvt *)kcontrol->private_value; - info = (struct gb_audio_ctl_elem_info *)data->info; - bundle = to_gb_bundle(module->dev); - - /* update ucontrol */ - switch (info->type) { - case GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN: - case GB_AUDIO_CTL_ELEM_TYPE_INTEGER: - gbvalue.value.integer_value[0] = - cpu_to_le32(ucontrol->value.integer.value[0]); - if (data->vcount == 2) - gbvalue.value.integer_value[1] = - cpu_to_le32(ucontrol->value.integer.value[1]); - break; - case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED: - gbvalue.value.enumerated_item[0] = - cpu_to_le32(ucontrol->value.enumerated.item[0]); - if (data->vcount == 2) - gbvalue.value.enumerated_item[1] = - cpu_to_le32(ucontrol->value.enumerated.item[1]); - break; - default: - dev_err(codec->dev, "Invalid type: %d for %s:kcontrol\n", - info->type, kcontrol->id.name); - ret = -EINVAL; - break; - } - - if (ret) - return ret; - - ret = gb_pm_runtime_get_sync(bundle); - if (ret) - return ret; - - ret = gb_audio_gb_set_control(module->mgmt_connection, data->ctl_id, - GB_AUDIO_INVALID_INDEX, &gbvalue); - - gb_pm_runtime_put_autosuspend(bundle); - - if (ret) { - dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret, - __func__, kcontrol->id.name); - } - - return ret; -} - -#define SOC_MIXER_GB(xname, kcount, data) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .count = kcount, .info = gbcodec_mixer_ctl_info, \ - .get = gbcodec_mixer_ctl_get, .put = gbcodec_mixer_ctl_put, \ - .private_value = (unsigned long)data } - -/* - * although below callback functions seems redundant to above functions. - * same are kept to allow provision for different handling in case - * of DAPM related sequencing, etc. - */ -static int gbcodec_mixer_dapm_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - int platform_max, platform_min; - struct gbaudio_ctl_pvt *data; - struct gb_audio_ctl_elem_info *info; - struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_widget *widget = wlist->widgets[0]; - struct snd_soc_codec *codec = widget->codec; - - dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name); - data = (struct gbaudio_ctl_pvt *)kcontrol->private_value; - info = (struct gb_audio_ctl_elem_info *)data->info; - - /* update uinfo */ - platform_max = le32_to_cpu(info->value.integer.max); - platform_min = le32_to_cpu(info->value.integer.min); - - if (platform_max == 1 && - !strnstr(kcontrol->id.name, " Volume", NAME_SIZE)) - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - else - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - - uinfo->count = data->vcount; - uinfo->value.integer.min = platform_min; - uinfo->value.integer.max = platform_max; - - return 0; -} - -static int gbcodec_mixer_dapm_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int ret; - struct gb_audio_ctl_elem_info *info; - struct gbaudio_ctl_pvt *data; - struct gb_audio_ctl_elem_value gbvalue; - struct gbaudio_module_info *module; - struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_widget *widget = wlist->widgets[0]; - struct snd_soc_codec *codec = widget->codec; - struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec); - struct gb_bundle *bundle; - - dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name); - module = find_gb_module(gb, kcontrol->id.name); - if (!module) - return -EINVAL; - - data = (struct gbaudio_ctl_pvt *)kcontrol->private_value; - info = (struct gb_audio_ctl_elem_info *)data->info; - bundle = to_gb_bundle(module->dev); - - if (data->vcount == 2) - dev_warn(widget->dapm->dev, - "GB: Control '%s' is stereo, which is not supported\n", - kcontrol->id.name); - - ret = gb_pm_runtime_get_sync(bundle); - if (ret) - return ret; - - ret = gb_audio_gb_get_control(module->mgmt_connection, data->ctl_id, - GB_AUDIO_INVALID_INDEX, &gbvalue); - - gb_pm_runtime_put_autosuspend(bundle); - - if (ret) { - dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret, - __func__, kcontrol->id.name); - return ret; - } - /* update ucontrol */ - ucontrol->value.integer.value[0] = - le32_to_cpu(gbvalue.value.integer_value[0]); - - return ret; -} - -static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int ret, wi, max, connect; - unsigned int mask, val; - struct gb_audio_ctl_elem_info *info; - struct gbaudio_ctl_pvt *data; - struct gb_audio_ctl_elem_value gbvalue; - struct gbaudio_module_info *module; - struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_widget *widget = wlist->widgets[0]; - struct snd_soc_codec *codec = widget->codec; - struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec); - struct gb_bundle *bundle; - - dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name); - module = find_gb_module(gb, kcontrol->id.name); - if (!module) - return -EINVAL; - - data = (struct gbaudio_ctl_pvt *)kcontrol->private_value; - info = (struct gb_audio_ctl_elem_info *)data->info; - bundle = to_gb_bundle(module->dev); - - if (data->vcount == 2) - dev_warn(widget->dapm->dev, - "GB: Control '%s' is stereo, which is not supported\n", - kcontrol->id.name); - - max = le32_to_cpu(info->value.integer.max); - mask = (1 << fls(max)) - 1; - val = ucontrol->value.integer.value[0] & mask; - connect = !!val; - - /* update ucontrol */ - if (gbvalue.value.integer_value[0] != val) { - for (wi = 0; wi < wlist->num_widgets; wi++) { - widget = wlist->widgets[wi]; - - widget->value = val; - widget->dapm->update = NULL; - snd_soc_dapm_mixer_update_power(widget, kcontrol, - connect); - } - gbvalue.value.integer_value[0] = - cpu_to_le32(ucontrol->value.integer.value[0]); - - ret = gb_pm_runtime_get_sync(bundle); - if (ret) - return ret; - - ret = gb_audio_gb_set_control(module->mgmt_connection, - data->ctl_id, - GB_AUDIO_INVALID_INDEX, &gbvalue); - - gb_pm_runtime_put_autosuspend(bundle); - - if (ret) { - dev_err_ratelimited(codec->dev, - "%d:Error in %s for %s\n", ret, - __func__, kcontrol->id.name); - return ret; - } - } - - return 0; -} - -#define SOC_DAPM_MIXER_GB(xname, kcount, data) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .count = kcount, .info = gbcodec_mixer_dapm_ctl_info, \ - .get = gbcodec_mixer_dapm_ctl_get, .put = gbcodec_mixer_dapm_ctl_put, \ - .private_value = (unsigned long)data} - -static int gbcodec_event_spk(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - /* Ensure GB speaker is connected */ - - return 0; -} - -static int gbcodec_event_hp(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - /* Ensure GB module supports jack slot */ - - return 0; -} - -static int gbcodec_event_int_mic(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - /* Ensure GB module supports jack slot */ - - return 0; -} - -static int gbaudio_validate_kcontrol_count(struct gb_audio_widget *w) -{ - int ret = 0; - - switch (w->type) { - case snd_soc_dapm_spk: - case snd_soc_dapm_hp: - case snd_soc_dapm_mic: - case snd_soc_dapm_output: - case snd_soc_dapm_input: - if (w->ncontrols) - ret = -EINVAL; - break; - case snd_soc_dapm_switch: - case snd_soc_dapm_mux: - if (w->ncontrols != 1) - ret = -EINVAL; - break; - default: - break; - } - - return ret; -} - -static int gbcodec_enum_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int ret, ctl_id; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct gb_audio_ctl_elem_value gbvalue; - struct gbaudio_module_info *module; - struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec); - struct gb_bundle *bundle; - - module = find_gb_module(gb, kcontrol->id.name); - if (!module) - return -EINVAL; - - ctl_id = gbaudio_map_controlname(module, kcontrol->id.name); - if (ctl_id < 0) - return -EINVAL; - - bundle = to_gb_bundle(module->dev); - - ret = gb_pm_runtime_get_sync(bundle); - if (ret) - return ret; - - ret = gb_audio_gb_get_control(module->mgmt_connection, ctl_id, - GB_AUDIO_INVALID_INDEX, &gbvalue); - - gb_pm_runtime_put_autosuspend(bundle); - - if (ret) { - dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret, - __func__, kcontrol->id.name); - return ret; - } - - ucontrol->value.enumerated.item[0] = - le32_to_cpu(gbvalue.value.enumerated_item[0]); - if (e->shift_l != e->shift_r) - ucontrol->value.enumerated.item[1] = - le32_to_cpu(gbvalue.value.enumerated_item[1]); - - return 0; -} - -static int gbcodec_enum_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int ret, ctl_id; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct gb_audio_ctl_elem_value gbvalue; - struct gbaudio_module_info *module; - struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec); - struct gb_bundle *bundle; - - module = find_gb_module(gb, kcontrol->id.name); - if (!module) - return -EINVAL; - - ctl_id = gbaudio_map_controlname(module, kcontrol->id.name); - if (ctl_id < 0) - return -EINVAL; - - if (ucontrol->value.enumerated.item[0] > e->max - 1) - return -EINVAL; - gbvalue.value.enumerated_item[0] = - cpu_to_le32(ucontrol->value.enumerated.item[0]); - - if (e->shift_l != e->shift_r) { - if (ucontrol->value.enumerated.item[1] > e->max - 1) - return -EINVAL; - gbvalue.value.enumerated_item[1] = - cpu_to_le32(ucontrol->value.enumerated.item[1]); - } - - bundle = to_gb_bundle(module->dev); - - ret = gb_pm_runtime_get_sync(bundle); - if (ret) - return ret; - - ret = gb_audio_gb_set_control(module->mgmt_connection, ctl_id, - GB_AUDIO_INVALID_INDEX, &gbvalue); - - gb_pm_runtime_put_autosuspend(bundle); - - if (ret) { - dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret, - __func__, kcontrol->id.name); - } - - return ret; -} - -static int gbaudio_tplg_create_enum_kctl(struct gbaudio_module_info *gb, - struct snd_kcontrol_new *kctl, - struct gb_audio_control *ctl) -{ - struct soc_enum *gbe; - struct gb_audio_enumerated *gb_enum; - int i; - - gbe = devm_kzalloc(gb->dev, sizeof(*gbe), GFP_KERNEL); - if (!gbe) - return -ENOMEM; - - gb_enum = &ctl->info.value.enumerated; - - /* since count=1, and reg is dummy */ - gbe->max = le32_to_cpu(gb_enum->items); - gbe->texts = gb_generate_enum_strings(gb, gb_enum); - - /* debug enum info */ - dev_dbg(gb->dev, "Max:%d, name_length:%d\n", gbe->max, - le16_to_cpu(gb_enum->names_length)); - for (i = 0; i < gbe->max; i++) - dev_dbg(gb->dev, "src[%d]: %s\n", i, gbe->texts[i]); - - *kctl = (struct snd_kcontrol_new) - SOC_ENUM_EXT(ctl->name, *gbe, gbcodec_enum_ctl_get, - gbcodec_enum_ctl_put); - return 0; -} - -static int gbaudio_tplg_create_kcontrol(struct gbaudio_module_info *gb, - struct snd_kcontrol_new *kctl, - struct gb_audio_control *ctl) -{ - int ret = 0; - struct gbaudio_ctl_pvt *ctldata; - - switch (ctl->iface) { - case SNDRV_CTL_ELEM_IFACE_MIXER: - switch (ctl->info.type) { - case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED: - ret = gbaudio_tplg_create_enum_kctl(gb, kctl, ctl); - break; - default: - ctldata = devm_kzalloc(gb->dev, - sizeof(struct gbaudio_ctl_pvt), - GFP_KERNEL); - if (!ctldata) - return -ENOMEM; - ctldata->ctl_id = ctl->id; - ctldata->data_cport = le16_to_cpu(ctl->data_cport); - ctldata->access = ctl->access; - ctldata->vcount = ctl->count_values; - ctldata->info = &ctl->info; - *kctl = (struct snd_kcontrol_new) - SOC_MIXER_GB(ctl->name, ctl->count, ctldata); - ctldata = NULL; - break; - } - break; - default: - return -EINVAL; - } - - dev_dbg(gb->dev, "%s:%d control created\n", ctl->name, ctl->id); - return ret; -} - -static int gbcodec_enum_dapm_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int ret, ctl_id; - struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_widget *widget = wlist->widgets[0]; - struct gbaudio_module_info *module; - struct gb_audio_ctl_elem_value gbvalue; - struct snd_soc_codec *codec = widget->codec; - struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct gb_bundle *bundle; - - module = find_gb_module(gb, kcontrol->id.name); - if (!module) - return -EINVAL; - - ctl_id = gbaudio_map_wcontrolname(module, kcontrol->id.name); - if (ctl_id < 0) - return -EINVAL; - - bundle = to_gb_bundle(module->dev); - - ret = gb_pm_runtime_get_sync(bundle); - if (ret) - return ret; - - ret = gb_audio_gb_get_control(module->mgmt_connection, ctl_id, - GB_AUDIO_INVALID_INDEX, &gbvalue); - - gb_pm_runtime_put_autosuspend(bundle); - - if (ret) { - dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret, - __func__, kcontrol->id.name); - return ret; - } - - ucontrol->value.enumerated.item[0] = gbvalue.value.enumerated_item[0]; - if (e->shift_l != e->shift_r) - ucontrol->value.enumerated.item[1] = - gbvalue.value.enumerated_item[1]; - - return 0; -} - -static int gbcodec_enum_dapm_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int ret, wi, ctl_id; - unsigned int val, mux, change; - unsigned int mask; - struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_widget *widget = wlist->widgets[0]; - struct gb_audio_ctl_elem_value gbvalue; - struct gbaudio_module_info *module; - struct snd_soc_codec *codec = widget->codec; - struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct gb_bundle *bundle; - - if (ucontrol->value.enumerated.item[0] > e->max - 1) - return -EINVAL; - - module = find_gb_module(gb, kcontrol->id.name); - if (!module) - return -EINVAL; - - ctl_id = gbaudio_map_wcontrolname(module, kcontrol->id.name); - if (ctl_id < 0) - return -EINVAL; - - change = 0; - bundle = to_gb_bundle(module->dev); - - ret = gb_pm_runtime_get_sync(bundle); - if (ret) - return ret; - - ret = gb_audio_gb_get_control(module->mgmt_connection, ctl_id, - GB_AUDIO_INVALID_INDEX, &gbvalue); - - gb_pm_runtime_put_autosuspend(bundle); - - if (ret) { - dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret, - __func__, kcontrol->id.name); - return ret; - } - - mux = ucontrol->value.enumerated.item[0]; - val = mux << e->shift_l; - mask = e->mask << e->shift_l; - - if (gbvalue.value.enumerated_item[0] != - ucontrol->value.enumerated.item[0]) { - change = 1; - gbvalue.value.enumerated_item[0] = - ucontrol->value.enumerated.item[0]; - } - - if (e->shift_l != e->shift_r) { - if (ucontrol->value.enumerated.item[1] > e->max - 1) - return -EINVAL; - val |= ucontrol->value.enumerated.item[1] << e->shift_r; - mask |= e->mask << e->shift_r; - if (gbvalue.value.enumerated_item[1] != - ucontrol->value.enumerated.item[1]) { - change = 1; - gbvalue.value.enumerated_item[1] = - ucontrol->value.enumerated.item[1]; - } - } - - if (change) { - ret = gb_pm_runtime_get_sync(bundle); - if (ret) - return ret; - - ret = gb_audio_gb_set_control(module->mgmt_connection, ctl_id, - GB_AUDIO_INVALID_INDEX, &gbvalue); - - gb_pm_runtime_put_autosuspend(bundle); - - if (ret) { - dev_err_ratelimited(codec->dev, - "%d:Error in %s for %s\n", ret, - __func__, kcontrol->id.name); - } - for (wi = 0; wi < wlist->num_widgets; wi++) { - widget = wlist->widgets[wi]; - - widget->value = val; - widget->dapm->update = NULL; - snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); - } - } - - return change; -} - -static int gbaudio_tplg_create_enum_ctl(struct gbaudio_module_info *gb, - struct snd_kcontrol_new *kctl, - struct gb_audio_control *ctl) -{ - struct soc_enum *gbe; - struct gb_audio_enumerated *gb_enum; - int i; - - gbe = devm_kzalloc(gb->dev, sizeof(*gbe), GFP_KERNEL); - if (!gbe) - return -ENOMEM; - - gb_enum = &ctl->info.value.enumerated; - - /* since count=1, and reg is dummy */ - gbe->max = le32_to_cpu(gb_enum->items); - gbe->texts = gb_generate_enum_strings(gb, gb_enum); - - /* debug enum info */ - dev_dbg(gb->dev, "Max:%d, name_length:%d\n", gbe->max, - le16_to_cpu(gb_enum->names_length)); - for (i = 0; i < gbe->max; i++) - dev_dbg(gb->dev, "src[%d]: %s\n", i, gbe->texts[i]); - - *kctl = (struct snd_kcontrol_new) - SOC_DAPM_ENUM_EXT(ctl->name, *gbe, gbcodec_enum_dapm_ctl_get, - gbcodec_enum_dapm_ctl_put); - return 0; -} - -static int gbaudio_tplg_create_mixer_ctl(struct gbaudio_module_info *gb, - struct snd_kcontrol_new *kctl, - struct gb_audio_control *ctl) -{ - struct gbaudio_ctl_pvt *ctldata; - - ctldata = devm_kzalloc(gb->dev, sizeof(struct gbaudio_ctl_pvt), - GFP_KERNEL); - if (!ctldata) - return -ENOMEM; - ctldata->ctl_id = ctl->id; - ctldata->data_cport = le16_to_cpu(ctl->data_cport); - ctldata->access = ctl->access; - ctldata->vcount = ctl->count_values; - ctldata->info = &ctl->info; - *kctl = (struct snd_kcontrol_new) - SOC_DAPM_MIXER_GB(ctl->name, ctl->count, ctldata); - - return 0; -} - -static int gbaudio_tplg_create_wcontrol(struct gbaudio_module_info *gb, - struct snd_kcontrol_new *kctl, - struct gb_audio_control *ctl) -{ - int ret; - - switch (ctl->iface) { - case SNDRV_CTL_ELEM_IFACE_MIXER: - switch (ctl->info.type) { - case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED: - ret = gbaudio_tplg_create_enum_ctl(gb, kctl, ctl); - break; - default: - ret = gbaudio_tplg_create_mixer_ctl(gb, kctl, ctl); - break; - } - break; - default: - return -EINVAL; - } - - dev_dbg(gb->dev, "%s:%d DAPM control created, ret:%d\n", ctl->name, - ctl->id, ret); - return ret; -} - -static int gbaudio_widget_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - int wid; - int ret; - struct snd_soc_codec *codec = w->codec; - struct gbaudio_codec_info *gbcodec = snd_soc_codec_get_drvdata(codec); - struct gbaudio_module_info *module; - struct gb_bundle *bundle; - - dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); - - /* Find relevant module */ - module = find_gb_module(gbcodec, w->name); - if (!module) - return -EINVAL; - - /* map name to widget id */ - wid = gbaudio_map_widgetname(module, w->name); - if (wid < 0) { - dev_err(codec->dev, "Invalid widget name:%s\n", w->name); - return -EINVAL; - } - - bundle = to_gb_bundle(module->dev); - - ret = gb_pm_runtime_get_sync(bundle); - if (ret) - return ret; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - ret = gb_audio_gb_enable_widget(module->mgmt_connection, wid); - if (!ret) - ret = gbaudio_module_update(gbcodec, w, module, 1); - break; - case SND_SOC_DAPM_POST_PMD: - ret = gb_audio_gb_disable_widget(module->mgmt_connection, wid); - if (!ret) - ret = gbaudio_module_update(gbcodec, w, module, 0); - break; - } - if (ret) - dev_err_ratelimited(codec->dev, - "%d: widget, event:%d failed:%d\n", wid, - event, ret); - - gb_pm_runtime_put_autosuspend(bundle); - - return ret; -} - -static int gbaudio_tplg_create_widget(struct gbaudio_module_info *module, - struct snd_soc_dapm_widget *dw, - struct gb_audio_widget *w, int *w_size) -{ - int i, ret, csize; - struct snd_kcontrol_new *widget_kctls; - struct gb_audio_control *curr; - struct gbaudio_control *control, *_control; - size_t size; - char temp_name[NAME_SIZE]; - - ret = gbaudio_validate_kcontrol_count(w); - if (ret) { - dev_err(module->dev, "Invalid kcontrol count=%d for %s\n", - w->ncontrols, w->name); - return ret; - } - - /* allocate memory for kcontrol */ - if (w->ncontrols) { - size = sizeof(struct snd_kcontrol_new) * w->ncontrols; - widget_kctls = devm_kzalloc(module->dev, size, GFP_KERNEL); - if (!widget_kctls) - return -ENOMEM; - } - - *w_size = sizeof(struct gb_audio_widget); - - /* create relevant kcontrols */ - curr = w->ctl; - for (i = 0; i < w->ncontrols; i++) { - ret = gbaudio_tplg_create_wcontrol(module, &widget_kctls[i], - curr); - if (ret) { - dev_err(module->dev, - "%s:%d type widget_ctl not supported\n", - curr->name, curr->iface); - goto error; - } - control = devm_kzalloc(module->dev, - sizeof(struct gbaudio_control), - GFP_KERNEL); - if (!control) { - ret = -ENOMEM; - goto error; - } - control->id = curr->id; - control->name = curr->name; - control->wname = w->name; - - if (curr->info.type == GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED) { - struct gb_audio_enumerated *gbenum = - &curr->info.value.enumerated; - - csize = offsetof(struct gb_audio_control, info); - csize += offsetof(struct gb_audio_ctl_elem_info, value); - csize += offsetof(struct gb_audio_enumerated, names); - csize += le16_to_cpu(gbenum->names_length); - control->texts = (const char * const *) - gb_generate_enum_strings(module, gbenum); - control->items = le32_to_cpu(gbenum->items); - } else { - csize = sizeof(struct gb_audio_control); - } - - *w_size += csize; - curr = (void *)curr + csize; - list_add(&control->list, &module->widget_ctl_list); - dev_dbg(module->dev, "%s: control of type %d created\n", - widget_kctls[i].name, widget_kctls[i].iface); - } - - /* Prefix dev_id to widget control_name */ - strlcpy(temp_name, w->name, NAME_SIZE); - snprintf(w->name, NAME_SIZE, "GB %d %s", module->dev_id, temp_name); - - switch (w->type) { - case snd_soc_dapm_spk: - *dw = (struct snd_soc_dapm_widget) - SND_SOC_DAPM_SPK(w->name, gbcodec_event_spk); - module->op_devices |= GBAUDIO_DEVICE_OUT_SPEAKER; - break; - case snd_soc_dapm_hp: - *dw = (struct snd_soc_dapm_widget) - SND_SOC_DAPM_HP(w->name, gbcodec_event_hp); - module->op_devices |= (GBAUDIO_DEVICE_OUT_WIRED_HEADSET - | GBAUDIO_DEVICE_OUT_WIRED_HEADPHONE); - module->ip_devices |= GBAUDIO_DEVICE_IN_WIRED_HEADSET; - break; - case snd_soc_dapm_mic: - *dw = (struct snd_soc_dapm_widget) - SND_SOC_DAPM_MIC(w->name, gbcodec_event_int_mic); - module->ip_devices |= GBAUDIO_DEVICE_IN_BUILTIN_MIC; - break; - case snd_soc_dapm_output: - *dw = (struct snd_soc_dapm_widget)SND_SOC_DAPM_OUTPUT(w->name); - break; - case snd_soc_dapm_input: - *dw = (struct snd_soc_dapm_widget)SND_SOC_DAPM_INPUT(w->name); - break; - case snd_soc_dapm_switch: - *dw = (struct snd_soc_dapm_widget) - SND_SOC_DAPM_SWITCH_E(w->name, SND_SOC_NOPM, 0, 0, - widget_kctls, - gbaudio_widget_event, - SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD); - break; - case snd_soc_dapm_pga: - *dw = (struct snd_soc_dapm_widget) - SND_SOC_DAPM_PGA_E(w->name, SND_SOC_NOPM, 0, 0, NULL, 0, - gbaudio_widget_event, - SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD); - break; - case snd_soc_dapm_mixer: - *dw = (struct snd_soc_dapm_widget) - SND_SOC_DAPM_MIXER_E(w->name, SND_SOC_NOPM, 0, 0, NULL, - 0, gbaudio_widget_event, - SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD); - break; - case snd_soc_dapm_mux: - *dw = (struct snd_soc_dapm_widget) - SND_SOC_DAPM_MUX_E(w->name, SND_SOC_NOPM, 0, 0, - widget_kctls, gbaudio_widget_event, - SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD); - break; - case snd_soc_dapm_aif_in: - *dw = (struct snd_soc_dapm_widget) - SND_SOC_DAPM_AIF_IN_E(w->name, w->sname, 0, - SND_SOC_NOPM, - 0, 0, gbaudio_widget_event, - SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD); - break; - case snd_soc_dapm_aif_out: - *dw = (struct snd_soc_dapm_widget) - SND_SOC_DAPM_AIF_OUT_E(w->name, w->sname, 0, - SND_SOC_NOPM, - 0, 0, gbaudio_widget_event, - SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD); - break; - default: - ret = -EINVAL; - goto error; - } - - dev_dbg(module->dev, "%s: widget of type %d created\n", dw->name, - dw->id); - return 0; -error: - list_for_each_entry_safe(control, _control, &module->widget_ctl_list, - list) { - list_del(&control->list); - devm_kfree(module->dev, control); - } - return ret; -} - -static int gbaudio_tplg_process_kcontrols(struct gbaudio_module_info *module, - struct gb_audio_control *controls) -{ - int i, csize, ret; - struct snd_kcontrol_new *dapm_kctls; - struct gb_audio_control *curr; - struct gbaudio_control *control, *_control; - size_t size; - char temp_name[NAME_SIZE]; - - size = sizeof(struct snd_kcontrol_new) * module->num_controls; - dapm_kctls = devm_kzalloc(module->dev, size, GFP_KERNEL); - if (!dapm_kctls) - return -ENOMEM; - - curr = controls; - for (i = 0; i < module->num_controls; i++) { - ret = gbaudio_tplg_create_kcontrol(module, &dapm_kctls[i], - curr); - if (ret) { - dev_err(module->dev, "%s:%d type not supported\n", - curr->name, curr->iface); - goto error; - } - control = devm_kzalloc(module->dev, sizeof(struct - gbaudio_control), - GFP_KERNEL); - if (!control) { - ret = -ENOMEM; - goto error; - } - control->id = curr->id; - /* Prefix dev_id to widget_name */ - strlcpy(temp_name, curr->name, NAME_SIZE); - snprintf(curr->name, NAME_SIZE, "GB %d %s", module->dev_id, - temp_name); - control->name = curr->name; - if (curr->info.type == GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED) { - struct gb_audio_enumerated *gbenum = - &curr->info.value.enumerated; - - csize = offsetof(struct gb_audio_control, info); - csize += offsetof(struct gb_audio_ctl_elem_info, value); - csize += offsetof(struct gb_audio_enumerated, names); - csize += le16_to_cpu(gbenum->names_length); - control->texts = (const char * const *) - gb_generate_enum_strings(module, gbenum); - control->items = le32_to_cpu(gbenum->items); - } else { - csize = sizeof(struct gb_audio_control); - } - - list_add(&control->list, &module->ctl_list); - dev_dbg(module->dev, "%d:%s created of type %d\n", curr->id, - curr->name, curr->info.type); - curr = (void *)curr + csize; - } - module->controls = dapm_kctls; - - return 0; -error: - list_for_each_entry_safe(control, _control, &module->ctl_list, - list) { - list_del(&control->list); - devm_kfree(module->dev, control); - } - devm_kfree(module->dev, dapm_kctls); - return ret; -} - -static int gbaudio_tplg_process_widgets(struct gbaudio_module_info *module, - struct gb_audio_widget *widgets) -{ - int i, ret, w_size; - struct snd_soc_dapm_widget *dapm_widgets; - struct gb_audio_widget *curr; - struct gbaudio_widget *widget, *_widget; - size_t size; - - size = sizeof(struct snd_soc_dapm_widget) * module->num_dapm_widgets; - dapm_widgets = devm_kzalloc(module->dev, size, GFP_KERNEL); - if (!dapm_widgets) - return -ENOMEM; - - curr = widgets; - for (i = 0; i < module->num_dapm_widgets; i++) { - ret = gbaudio_tplg_create_widget(module, &dapm_widgets[i], - curr, &w_size); - if (ret) { - dev_err(module->dev, "%s:%d type not supported\n", - curr->name, curr->type); - goto error; - } - widget = devm_kzalloc(module->dev, sizeof(struct - gbaudio_widget), - GFP_KERNEL); - if (!widget) { - ret = -ENOMEM; - goto error; - } - widget->id = curr->id; - widget->name = curr->name; - list_add(&widget->list, &module->widget_list); - curr = (void *)curr + w_size; - } - module->dapm_widgets = dapm_widgets; - - return 0; - -error: - list_for_each_entry_safe(widget, _widget, &module->widget_list, - list) { - list_del(&widget->list); - devm_kfree(module->dev, widget); - } - devm_kfree(module->dev, dapm_widgets); - return ret; -} - -static int gbaudio_tplg_process_routes(struct gbaudio_module_info *module, - struct gb_audio_route *routes) -{ - int i, ret; - struct snd_soc_dapm_route *dapm_routes; - struct gb_audio_route *curr; - size_t size; - - size = sizeof(struct snd_soc_dapm_route) * module->num_dapm_routes; - dapm_routes = devm_kzalloc(module->dev, size, GFP_KERNEL); - if (!dapm_routes) - return -ENOMEM; - - module->dapm_routes = dapm_routes; - curr = routes; - - for (i = 0; i < module->num_dapm_routes; i++) { - dapm_routes->sink = - gbaudio_map_widgetid(module, curr->destination_id); - if (!dapm_routes->sink) { - dev_err(module->dev, "%d:%d:%d:%d - Invalid sink\n", - curr->source_id, curr->destination_id, - curr->control_id, curr->index); - ret = -EINVAL; - goto error; - } - dapm_routes->source = - gbaudio_map_widgetid(module, curr->source_id); - if (!dapm_routes->source) { - dev_err(module->dev, "%d:%d:%d:%d - Invalid source\n", - curr->source_id, curr->destination_id, - curr->control_id, curr->index); - ret = -EINVAL; - goto error; - } - dapm_routes->control = - gbaudio_map_controlid(module, - curr->control_id, - curr->index); - if ((curr->control_id != GBAUDIO_INVALID_ID) && - !dapm_routes->control) { - dev_err(module->dev, "%d:%d:%d:%d - Invalid control\n", - curr->source_id, curr->destination_id, - curr->control_id, curr->index); - ret = -EINVAL; - goto error; - } - dev_dbg(module->dev, "Route {%s, %s, %s}\n", dapm_routes->sink, - (dapm_routes->control) ? dapm_routes->control : "NULL", - dapm_routes->source); - dapm_routes++; - curr++; - } - - return 0; - -error: - devm_kfree(module->dev, module->dapm_routes); - return ret; -} - -static int gbaudio_tplg_process_header(struct gbaudio_module_info *module, - struct gb_audio_topology *tplg_data) -{ - /* fetch no. of kcontrols, widgets & routes */ - module->num_controls = tplg_data->num_controls; - module->num_dapm_widgets = tplg_data->num_widgets; - module->num_dapm_routes = tplg_data->num_routes; - - /* update block offset */ - module->dai_offset = (unsigned long)&tplg_data->data; - module->control_offset = module->dai_offset + - le32_to_cpu(tplg_data->size_dais); - module->widget_offset = module->control_offset + - le32_to_cpu(tplg_data->size_controls); - module->route_offset = module->widget_offset + - le32_to_cpu(tplg_data->size_widgets); - - dev_dbg(module->dev, "DAI offset is 0x%lx\n", module->dai_offset); - dev_dbg(module->dev, "control offset is %lx\n", - module->control_offset); - dev_dbg(module->dev, "widget offset is %lx\n", module->widget_offset); - dev_dbg(module->dev, "route offset is %lx\n", module->route_offset); - - return 0; -} - -int gbaudio_tplg_parse_data(struct gbaudio_module_info *module, - struct gb_audio_topology *tplg_data) -{ - int ret; - struct gb_audio_control *controls; - struct gb_audio_widget *widgets; - struct gb_audio_route *routes; - unsigned int jack_type; - - if (!tplg_data) - return -EINVAL; - - ret = gbaudio_tplg_process_header(module, tplg_data); - if (ret) { - dev_err(module->dev, "%d: Error in parsing topology header\n", - ret); - return ret; - } - - /* process control */ - controls = (struct gb_audio_control *)module->control_offset; - ret = gbaudio_tplg_process_kcontrols(module, controls); - if (ret) { - dev_err(module->dev, - "%d: Error in parsing controls data\n", ret); - return ret; - } - dev_dbg(module->dev, "Control parsing finished\n"); - - /* process widgets */ - widgets = (struct gb_audio_widget *)module->widget_offset; - ret = gbaudio_tplg_process_widgets(module, widgets); - if (ret) { - dev_err(module->dev, - "%d: Error in parsing widgets data\n", ret); - return ret; - } - dev_dbg(module->dev, "Widget parsing finished\n"); - - /* process route */ - routes = (struct gb_audio_route *)module->route_offset; - ret = gbaudio_tplg_process_routes(module, routes); - if (ret) { - dev_err(module->dev, - "%d: Error in parsing routes data\n", ret); - return ret; - } - dev_dbg(module->dev, "Route parsing finished\n"); - - /* parse jack capabilities */ - jack_type = le32_to_cpu(tplg_data->jack_type); - if (jack_type) { - module->jack_mask = jack_type & GBCODEC_JACK_MASK; - module->button_mask = jack_type & GBCODEC_JACK_BUTTON_MASK; - } - - return ret; -} - -void gbaudio_tplg_release(struct gbaudio_module_info *module) -{ - struct gbaudio_control *control, *_control; - struct gbaudio_widget *widget, *_widget; - - if (!module->topology) - return; - - /* release kcontrols */ - list_for_each_entry_safe(control, _control, &module->ctl_list, - list) { - list_del(&control->list); - devm_kfree(module->dev, control); - } - if (module->controls) - devm_kfree(module->dev, module->controls); - - /* release widget controls */ - list_for_each_entry_safe(control, _control, &module->widget_ctl_list, - list) { - list_del(&control->list); - devm_kfree(module->dev, control); - } - - /* release widgets */ - list_for_each_entry_safe(widget, _widget, &module->widget_list, - list) { - list_del(&widget->list); - devm_kfree(module->dev, widget); - } - if (module->dapm_widgets) - devm_kfree(module->dev, module->dapm_widgets); - - /* release routes */ - if (module->dapm_routes) - devm_kfree(module->dev, module->dapm_routes); -}