From: Vaibhav Agarwal Date: Thu, 4 Aug 2016 09:44:38 +0000 (+0530) Subject: greybus: audio: Maintain runtime stream params for each DAI X-Git-Tag: v4.9-rc1~119^2~378^2~21^2~63 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=19866603be2ad58735f82511f3d5f680e61479ea;p=karo-tx-linux.git greybus: audio: Maintain runtime stream params for each DAI Runtime streams are required while configuring GB module plugged-in during active stream. Currently, it is maintained for single stream. However, this should be maintained for a stream corresponding to each DAI. Fix this! Signed-off-by: Vaibhav Agarwal Reviewed-by: Mark Greer Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c index 9f050bd95c7c..e1ad685b00dc 100644 --- a/drivers/staging/greybus/audio_codec.c +++ b/drivers/staging/greybus/audio_codec.c @@ -30,6 +30,18 @@ find_data(struct gbaudio_module_info *module, int id) 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) { @@ -38,13 +50,7 @@ static int gbaudio_module_enable_tx(struct gbaudio_codec_info *codec, uint8_t sig_bits, channels; uint32_t format, rate; struct gbaudio_data_connection *data; - const char *dai_name; - - dai_name = codec->stream[SNDRV_PCM_STREAM_PLAYBACK].dai_name; - format = codec->stream[SNDRV_PCM_STREAM_PLAYBACK].format; - channels = codec->stream[SNDRV_PCM_STREAM_PLAYBACK].channels; - rate = codec->stream[SNDRV_PCM_STREAM_PLAYBACK].rate; - sig_bits = codec->stream[SNDRV_PCM_STREAM_PLAYBACK].sig_bits; + struct gbaudio_stream_params *params; module_state = module->ctrlstate[SNDRV_PCM_STREAM_PLAYBACK]; @@ -55,6 +61,12 @@ static int gbaudio_module_enable_tx(struct gbaudio_codec_info *codec, return -ENODEV; } + 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 */ @@ -69,12 +81,15 @@ static int gbaudio_module_enable_tx(struct gbaudio_codec_info *codec, } module->ctrlstate[SNDRV_PCM_STREAM_PLAYBACK] = GBAUDIO_CODEC_STARTUP; - dev_dbg(module->dev, "Dynamic Register %s:%d DAI\n", dai_name, - cportid); + 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); @@ -85,8 +100,7 @@ static int gbaudio_module_enable_tx(struct gbaudio_codec_info *codec, } module->ctrlstate[SNDRV_PCM_STREAM_PLAYBACK] = GBAUDIO_CODEC_HWPARAMS; - dev_dbg(module->dev, "Dynamic hw_params %s:%d DAI\n", dai_name, - data_cport); + dev_dbg(module->dev, "Dynamic hw_params %d DAI\n", data_cport); } /* prepare */ @@ -109,8 +123,7 @@ static int gbaudio_module_enable_tx(struct gbaudio_codec_info *codec, } module->ctrlstate[SNDRV_PCM_STREAM_PLAYBACK] = GBAUDIO_CODEC_PREPARE; - dev_dbg(module->dev, "Dynamic prepare %s:%d DAI\n", dai_name, - data_cport); + dev_dbg(module->dev, "Dynamic prepare %d DAI\n", data_cport); } return 0; @@ -179,13 +192,8 @@ static int gbaudio_module_enable_rx(struct gbaudio_codec_info *codec, uint8_t sig_bits, channels; uint32_t format, rate; struct gbaudio_data_connection *data; - const char *dai_name; + struct gbaudio_stream_params *params; - dai_name = codec->stream[SNDRV_PCM_STREAM_CAPTURE].dai_name; - format = codec->stream[SNDRV_PCM_STREAM_CAPTURE].format; - channels = codec->stream[SNDRV_PCM_STREAM_CAPTURE].channels; - rate = codec->stream[SNDRV_PCM_STREAM_CAPTURE].rate; - sig_bits = codec->stream[SNDRV_PCM_STREAM_CAPTURE].sig_bits; module_state = module->ctrlstate[SNDRV_PCM_STREAM_CAPTURE]; /* find the dai */ @@ -195,6 +203,12 @@ static int gbaudio_module_enable_rx(struct gbaudio_codec_info *codec, return -ENODEV; } + 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 */ @@ -209,12 +223,15 @@ static int gbaudio_module_enable_rx(struct gbaudio_codec_info *codec, } module->ctrlstate[SNDRV_PCM_STREAM_CAPTURE] = GBAUDIO_CODEC_STARTUP; - dev_dbg(module->dev, "Dynamic Register %s:%d DAI\n", dai_name, - cportid); + 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); @@ -225,8 +242,7 @@ static int gbaudio_module_enable_rx(struct gbaudio_codec_info *codec, } module->ctrlstate[SNDRV_PCM_STREAM_CAPTURE] = GBAUDIO_CODEC_HWPARAMS; - dev_dbg(module->dev, "Dynamic hw_params %s:%d DAI\n", dai_name, - data_cport); + dev_dbg(module->dev, "Dynamic hw_params %d DAI\n", data_cport); } /* prepare */ @@ -249,8 +265,7 @@ static int gbaudio_module_enable_rx(struct gbaudio_codec_info *codec, } module->ctrlstate[SNDRV_PCM_STREAM_CAPTURE] = GBAUDIO_CODEC_PREPARE; - dev_dbg(module->dev, "Dynamic prepare %s:%d DAI\n", dai_name, - data_cport); + dev_dbg(module->dev, "Dynamic prepare %d DAI\n", data_cport); } return 0; @@ -361,6 +376,7 @@ 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); @@ -370,8 +386,13 @@ static int gbcodec_startup(struct snd_pcm_substream *substream, return -ENODEV; } - codec->stream[substream->stream].state = GBAUDIO_CODEC_STARTUP; - codec->stream[substream->stream].dai_name = dai->name; + 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); @@ -383,14 +404,20 @@ 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"); - codec->stream[substream->stream].state = GBAUDIO_CODEC_SHUTDOWN; - codec->stream[substream->stream].dai_name = NULL; + 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); return; @@ -407,6 +434,7 @@ static int gbcodec_hw_params(struct snd_pcm_substream *substream, 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); @@ -457,6 +485,13 @@ static int gbcodec_hw_params(struct snd_pcm_substream *substream, 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) { @@ -477,11 +512,11 @@ static int gbcodec_hw_params(struct snd_pcm_substream *substream, gb_pm_runtime_put_noidle(bundle); - codec->stream[substream->stream].state = GBAUDIO_CODEC_HWPARAMS; - codec->stream[substream->stream].format = format; - codec->stream[substream->stream].rate = rate; - codec->stream[substream->stream].channels = channels; - codec->stream[substream->stream].sig_bits = 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; @@ -495,6 +530,7 @@ static int gbcodec_prepare(struct snd_pcm_substream *substream, 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); @@ -516,6 +552,13 @@ static int gbcodec_prepare(struct snd_pcm_substream *substream, 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) { @@ -542,7 +585,7 @@ static int gbcodec_prepare(struct snd_pcm_substream *substream, gb_pm_runtime_put_noidle(bundle); - codec->stream[substream->stream].state = GBAUDIO_CODEC_PREPARE; + params->state = GBAUDIO_CODEC_PREPARE; mutex_unlock(&codec->lock); return 0; } @@ -554,16 +597,25 @@ static int gbcodec_mute_stream(struct snd_soc_dai *dai, int mute, int stream) 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) { - codec->stream[stream].state = GBAUDIO_CODEC_STOP; + params->state = GBAUDIO_CODEC_STOP; ret = 0; } else { ret = -ENODEV; @@ -598,26 +650,26 @@ static int gbcodec_mute_stream(struct snd_soc_dai *dai, int mute, int stream) if (!ret) ret = gb_audio_apbridgea_start_tx(data->connection, 0, 0); - codec->stream[stream].state = GBAUDIO_CODEC_START; + 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); - codec->stream[stream].state = GBAUDIO_CODEC_START; + 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); - codec->stream[stream].state = GBAUDIO_CODEC_STOP; + 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); - codec->stream[stream].state = GBAUDIO_CODEC_STOP; + params->state = GBAUDIO_CODEC_STOP; } else ret = -EINVAL; if (ret) @@ -639,6 +691,32 @@ static struct snd_soc_dai_ops gbcodec_dai_ops = { .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, + }, + .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, + }, + .ops = &gbcodec_dai_ops, + }, +}; + static int gbaudio_init_jack(struct gbaudio_module_info *module, struct snd_soc_codec *codec) { @@ -898,7 +976,9 @@ EXPORT_SYMBOL(gbaudio_unregister_module); */ 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) @@ -907,6 +987,17 @@ static int gbcodec_probe(struct snd_soc_codec *codec) 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; @@ -964,32 +1055,6 @@ static unsigned int gbcodec_read(struct snd_soc_codec *codec, return val; } -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, - }, - .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, - }, - .ops = &gbcodec_dai_ops, - }, -}; - static struct snd_soc_codec_driver soc_codec_dev_gbaudio = { .probe = gbcodec_probe, .remove = gbcodec_remove, diff --git a/drivers/staging/greybus/audio_codec.h b/drivers/staging/greybus/audio_codec.h index 7a2dbc517663..40c39b30d951 100644 --- a/drivers/staging/greybus/audio_codec.h +++ b/drivers/staging/greybus/audio_codec.h @@ -98,18 +98,25 @@ enum gbaudio_codec_state { GBAUDIO_CODEC_STOP, }; -struct gbaudio_stream { - const char *dai_name; +struct gbaudio_stream_params { int state; uint8_t sig_bits, channels; uint32_t format, rate; }; +struct gbaudio_codec_dai { + int id; + /* runtime params for playback/capture streams */ + struct gbaudio_stream_params params[2]; + struct list_head list; +}; + struct gbaudio_codec_info { struct device *dev; struct snd_soc_codec *codec; struct list_head module_list; - struct gbaudio_stream stream[2]; /* PB/CAP */ + /* to maintain runtime stream params for each DAI */ + struct list_head dai_list; struct mutex lock; u8 reg[GBCODEC_REG_COUNT]; };