summaryrefslogtreecommitdiff
path: root/drivers/staging/greybus
diff options
context:
space:
mode:
authorVaibhav Agarwal <vaibhav.agarwal@linaro.org>2016-01-14 00:07:55 +0300
committerGreg Kroah-Hartman <gregkh@google.com>2016-01-14 03:48:49 +0300
commit25de3491f11064845a45606fa5828a200ecf8c53 (patch)
treefd2a2f106c0ed47960735bb547f3857cf6262848 /drivers/staging/greybus
parent538ecb5a05049fcd23043ed5c97e42c379e5ccb0 (diff)
downloadlinux-25de3491f11064845a45606fa5828a200ecf8c53.tar.xz
greybus: audio: Cleanup GB protocol connections in case of abrupt codec removal
We need to clean up GB protocl connections, otherwise successive codec insertions fails repeatedly. NOTE: As per suggestion, since codec is already removed, one should not trigger any GB command. It'll cause a delay of atleast TIMEOUT value. HOwever, failing to cleanup GB protocol, causes successive module insertion to fail Signed-off-by: Vaibhav Agarwal <vaibhav.agarwal@linaro.org> Signed-off-by: Mark Greer <mgreer@animalcreek.com> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus')
-rw-r--r--drivers/staging/greybus/audio_codec.c58
-rw-r--r--drivers/staging/greybus/audio_codec.h3
2 files changed, 61 insertions, 0 deletions
diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c
index 93906c8128de..2b4fcbedd161 100644
--- a/drivers/staging/greybus/audio_codec.c
+++ b/drivers/staging/greybus/audio_codec.c
@@ -56,6 +56,9 @@ static int gbcodec_startup(struct snd_pcm_substream *substream,
dev_dbg(dai->dev, "Register %s:%d DAI, ret:%d\n", dai->name, cportid,
ret);
+ if (!ret)
+ atomic_inc(&gb->users);
+
return ret;
}
@@ -83,6 +86,8 @@ static void gbcodec_shutdown(struct snd_pcm_substream *substream,
return;
}
+ atomic_dec(&gb->users);
+
/* deactivate rx/tx */
cportid = gb_dai->connection->intf_cport_id;
@@ -428,6 +433,7 @@ static struct snd_soc_codec_driver soc_codec_dev_gbcodec = {
.reg_word_size = 1,
.idle_bias_off = true,
+ .ignore_pmdown_time = 1,
};
/*
@@ -573,6 +579,50 @@ struct device_driver gb_codec_driver = {
.owner = THIS_MODULE,
};
+/* XXX
+ * since BE DAI path is not yet properly closed from above layer,
+ * dsp dai.mi2s_dai_data.status_mask is still set to STATUS_PORT_STARTED
+ * this causes immediate playback/capture to fail in case relevant mixer
+ * control is not turned OFF
+ * user need to try once again after failure to recover DSP state.
+ */
+static void gb_audio_cleanup(struct gbaudio_codec_info *gb)
+{
+ int cportid, ret;
+ struct gbaudio_dai *gb_dai;
+ struct gb_connection *connection;
+ struct device *dev = gb->dev;
+
+ list_for_each_entry(gb_dai, &gb->dai_list, list) {
+ /*
+ * In case of BE dailink, need to deactivate APBridge
+ * manually
+ */
+ if (gbaudio_dailink.no_pcm && atomic_read(&gb->users)) {
+ connection = gb_dai->connection;
+ /* PB active */
+ ret = gb_audio_apbridgea_stop_tx(connection, 0);
+ if (ret)
+ dev_info(dev, "%d:Failed during APBridge stop_tx\n",
+ ret);
+ cportid = connection->intf_cport_id;
+ ret = gb_audio_gb_deactivate_tx(gb->mgmt_connection,
+ cportid);
+ if (ret)
+ dev_info(dev,
+ "%d:Failed during deactivate_tx\n",
+ ret);
+ cportid = connection->hd_cport_id;
+ ret = gb_audio_apbridgea_unregister_cport(connection, 0,
+ cportid);
+ if (ret)
+ dev_info(dev, "%d:Failed during unregister cport\n",
+ ret);
+ atomic_dec(&gb->users);
+ }
+ }
+}
+
static int gbaudio_codec_probe(struct gb_connection *connection)
{
int ret, i;
@@ -641,6 +691,9 @@ static int gbaudio_codec_probe(struct gb_connection *connection)
mutex_lock(&gbcodec->lock);
gbcodec->codec_registered = 1;
+ /* codec cleanup related */
+ atomic_set(&gbcodec->users, 0);
+
/* inform above layer for uevent */
if (!gbcodec->set_uevent &&
(gbcodec->dai_added == gbcodec->num_dais)) {
@@ -696,6 +749,11 @@ static void gbaudio_codec_remove(struct gb_connection *connection)
}
mutex_unlock(&gbcodec->lock);
+ if (atomic_read(&gbcodec->users)) {
+ dev_err(dev, "Cleanup Error: BE stream not yet closed\n");
+ gb_audio_cleanup(gbcodec);
+ }
+
msm8994_remove_dailink("msm8994-tomtom-mtp-snd-card", &gbaudio_dailink,
1);
gbaudio_remove_dailinks(gbcodec);
diff --git a/drivers/staging/greybus/audio_codec.h b/drivers/staging/greybus/audio_codec.h
index fcf3a0602176..0b587ef74d16 100644
--- a/drivers/staging/greybus/audio_codec.h
+++ b/drivers/staging/greybus/audio_codec.h
@@ -131,6 +131,9 @@ struct gbaudio_codec_info {
struct snd_soc_dapm_route *routes;
struct snd_soc_dai_driver *dais;
+ /* codec users */
+ atomic_t users;
+
/* lists */
struct list_head dai_list;
struct list_head widget_list;