From e66228212cc5afba26deb70af0fea5bb698b7138 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Wed, 13 Jun 2018 16:08:02 +0800 Subject: [PATCH 1/5] dai: add lbm status for dai ssp Add a status to track dai ssp lbm. Signed-off-by: Pan Xiuli --- src/include/sof/ssp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/sof/ssp.h b/src/include/sof/ssp.h index 8fa0df70055f..3914ccda3d99 100644 --- a/src/include/sof/ssp.h +++ b/src/include/sof/ssp.h @@ -236,6 +236,7 @@ struct ssp_pdata { uint32_t psp; spinlock_t lock; uint32_t state[2]; /* SSP_STATE_ for each direction */ + uint32_t lbm; completion_t drain_complete; struct sof_ipc_dai_config config; struct sof_ipc_dai_ssp_params params; From 71d32579711e5a1ab7ccf4a0e0b62d6b444682c5 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Tue, 19 Jun 2018 16:04:05 +0800 Subject: [PATCH 2/5] dai: add get_loopback_mode function get loopback mode status for dai. Signed-off-by: Pan Xiuli --- src/include/sof/dai.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/include/sof/dai.h b/src/include/sof/dai.h index e3bce1db566b..8cc579c45d44 100644 --- a/src/include/sof/dai.h +++ b/src/include/sof/dai.h @@ -64,6 +64,7 @@ struct dai_ops { int (*pm_context_store)(struct dai *dai); int (*probe)(struct dai *dai); int (*set_loopback_mode)(struct dai *dai, uint32_t lbm); + int (*get_loopback_mode)(struct dai *dai); }; /* DAI slot map to audio channel */ @@ -129,6 +130,11 @@ static inline int dai_set_loopback_mode(struct dai *dai, uint32_t lbm) return dai->ops->set_loopback_mode(dai, lbm); } +static inline int dai_get_loopback_mode(struct dai *dai) +{ + return dai->ops->get_loopback_mode(dai); +} + /* Digital Audio interface trigger */ static inline int dai_trigger(struct dai *dai, int cmd, int direction) { From f97f25444e12c9ef2f96472a0bbcb4ff683d6bd7 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Tue, 19 Jun 2018 16:11:12 +0800 Subject: [PATCH 3/5] DMIC: add empty get_loopback_mode function Return error value if it is called. Signed-off-by: Pan Xiuli --- src/drivers/dmic.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/drivers/dmic.c b/src/drivers/dmic.c index 47c966d263ef..eb7ad7422d93 100644 --- a/src/drivers/dmic.c +++ b/src/drivers/dmic.c @@ -1454,6 +1454,11 @@ static inline int dmic_set_loopback_mode(struct dai *dai, uint32_t lbm) return -EINVAL; } +static inline int dmic_get_loopback_mode(struct dai *dai) +{ + return -EINVAL; +} + const struct dai_ops dmic_ops = { .trigger = dmic_trigger, .set_config = dmic_set_config, @@ -1461,6 +1466,7 @@ const struct dai_ops dmic_ops = { .pm_context_restore = dmic_context_restore, .probe = dmic_probe, .set_loopback_mode = dmic_set_loopback_mode, + .get_loopback_mode = dmic_get_loopback_mode, }; #endif From 5867e43fd22d84558aa74c39dcf5762ef9369a81 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Tue, 19 Jun 2018 16:12:26 +0800 Subject: [PATCH 4/5] SSP: support for get/set_loopback_mode functions Add ssp_get_loopback_mode and refine ssp_set_loopback_mode function to support SSP loopback mode. Signed-off-by: Pan Xiuli --- src/drivers/apl-ssp.c | 22 +++++++++++++++++++--- src/drivers/byt-ssp.c | 22 +++++++++++++++++++--- src/drivers/hsw-ssp.c | 22 +++++++++++++++++++--- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/drivers/apl-ssp.c b/src/drivers/apl-ssp.c index 21065c3a89b7..2de96ca037ea 100644 --- a/src/drivers/apl-ssp.c +++ b/src/drivers/apl-ssp.c @@ -610,16 +610,31 @@ static inline int ssp_set_loopback_mode(struct dai *dai, uint32_t lbm) { struct ssp_pdata *ssp = dai_get_drvdata(dai); - trace_ssp("loo"); - spin_lock(&ssp->lock); + trace_ssp("los"); - ssp_update_bits(dai, SSCR1, SSCR1_LBM, lbm ? SSCR1_LBM : 0); + if (ssp->lbm == lbm) + return 0; + spin_lock(&ssp->lock); + ssp->lbm = lbm; + ssp_update_bits(dai, SSCR1, SSCR1_LBM, lbm ? SSCR1_LBM : 0); spin_unlock(&ssp->lock); return 0; } +static inline int ssp_get_loopback_mode(struct dai *dai) +{ + struct ssp_pdata *ssp = dai_get_drvdata(dai); + int ret; + + trace_ssp("log"); + spin_lock(&ssp->lock); + ret = ssp->lbm; + spin_unlock(&ssp->lock); + return ret; +} + /* start the SSP for either playback or capture */ static void ssp_start(struct dai *dai, int direction) { @@ -757,4 +772,5 @@ const struct dai_ops ssp_ops = { .pm_context_restore = ssp_context_restore, .probe = ssp_probe, .set_loopback_mode = ssp_set_loopback_mode, + .get_loopback_mode = ssp_get_loopback_mode, }; diff --git a/src/drivers/byt-ssp.c b/src/drivers/byt-ssp.c index a940ff98e2f8..590efdb55ef1 100644 --- a/src/drivers/byt-ssp.c +++ b/src/drivers/byt-ssp.c @@ -457,16 +457,31 @@ static inline int ssp_set_loopback_mode(struct dai *dai, uint32_t lbm) { struct ssp_pdata *ssp = dai_get_drvdata(dai); - trace_ssp("loo"); - spin_lock(&ssp->lock); + trace_ssp("los"); - ssp_update_bits(dai, SSCR1, SSCR1_LBM, lbm ? SSCR1_LBM : 0); + if (ssp->lbm == lbm) + return 0; + spin_lock(&ssp->lock); + ssp->lbm = lbm; + ssp_update_bits(dai, SSCR1, SSCR1_LBM, lbm ? SSCR1_LBM : 0); spin_unlock(&ssp->lock); return 0; } +static inline int ssp_get_loopback_mode(struct dai *dai) +{ + struct ssp_pdata *ssp = dai_get_drvdata(dai); + int ret; + + trace_ssp("log"); + spin_lock(&ssp->lock); + ret = ssp->lbm; + spin_unlock(&ssp->lock); + return ret; +} + /* start the SSP for either playback or capture */ static void ssp_start(struct dai *dai, int direction) { @@ -608,4 +623,5 @@ const struct dai_ops ssp_ops = { .pm_context_restore = ssp_context_restore, .probe = ssp_probe, .set_loopback_mode = ssp_set_loopback_mode, + .get_loopback_mode = ssp_get_loopback_mode, }; diff --git a/src/drivers/hsw-ssp.c b/src/drivers/hsw-ssp.c index 479ae27f05bb..7d3638c852c6 100644 --- a/src/drivers/hsw-ssp.c +++ b/src/drivers/hsw-ssp.c @@ -370,16 +370,31 @@ static inline int ssp_set_loopback_mode(struct dai *dai, uint32_t lbm) { struct ssp_pdata *ssp = dai_get_drvdata(dai); - trace_ssp("loo"); - spin_lock(&ssp->lock); + trace_ssp("los"); - ssp_update_bits(dai, SSCR1, SSCR1_LBM, lbm ? SSCR1_LBM : 0); + if (ssp->lbm == lbm) + return 0; + spin_lock(&ssp->lock); + ssp->lbm = lbm; + ssp_update_bits(dai, SSCR1, SSCR1_LBM, lbm ? SSCR1_LBM : 0); spin_unlock(&ssp->lock); return 0; } +static inline int ssp_get_loopback_mode(struct dai *dai) +{ + struct ssp_pdata *ssp = dai_get_drvdata(dai); + int ret; + + trace_ssp("log"); + spin_lock(&ssp->lock); + ret = ssp->lbm; + spin_unlock(&ssp->lock); + return ret; +} + /* start the SSP for either playback or capture */ static void ssp_start(struct dai *dai, int direction) { @@ -525,4 +540,5 @@ const struct dai_ops ssp_ops = { .pm_context_restore = ssp_context_restore, .probe = ssp_probe, .set_loopback_mode = ssp_set_loopback_mode, + .get_loopback_mode = ssp_get_loopback_mode, }; From 850d2135bc07a03a5e36d65325cc5e09078a80bd Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Tue, 19 Jun 2018 16:18:37 +0800 Subject: [PATCH 5/5] dai: add dai_cmd support for loopback mode switch use dai_cmd to handle ssp dai loopback mode switch support Signed-off-by: Pan Xiuli --- src/audio/dai.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/audio/dai.c b/src/audio/dai.c index 6ac15d1e7005..20768b5a00e8 100644 --- a/src/audio/dai.c +++ b/src/audio/dai.c @@ -688,6 +688,81 @@ static int dai_config(struct comp_dev *dev, struct sof_ipc_dai_config *config) return 0; } +static int dai_ctrl_set_cmd(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + struct dai_data *dd = comp_get_drvdata(dev); + int ret = 0; + int val; + + /* validate */ + if (cdata->num_elems != 1) { + trace_dai_error("xs0"); + return -EINVAL; + } + + switch (cdata->cmd) { + case SOF_CTRL_CMD_SWITCH: + val = cdata->compv[0].uvalue; + trace_dai("dcs"); + trace_value(cdata->comp_id); + trace_value(val); + dai_set_loopback_mode(dd->dai, val); + break; + + default: + trace_dai_error("gs1"); + return -EINVAL; + } + + return ret; +} + +static int dai_ctrl_get_cmd(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + struct dai_data *dd = comp_get_drvdata(dev); + int val; + + /* validate */ + if (cdata->num_elems != 1) { + trace_dai_error("xg0"); + return -EINVAL; + } + switch (cdata->cmd) { + case SOF_CTRL_CMD_SWITCH: + val = dai_get_loopback_mode(dd->dai); + trace_dai("dcg"); + trace_value(cdata->comp_id); + trace_value(val); + cdata->compv[0].uvalue = val; + break; + + default: + trace_dai_error("xcc"); + return -EINVAL; + } + + return 0; +} + +/* used to pass standard and bespoke commands (with data) to component */ +static int dai_cmd(struct comp_dev *dev, int cmd, void *data) +{ + struct sof_ipc_ctrl_data *cdata = data; + + trace_dai("cmd"); + + switch (cmd) { + case COMP_CMD_SET_VALUE: + return dai_ctrl_set_cmd(dev, cdata); + case COMP_CMD_GET_VALUE: + return dai_ctrl_get_cmd(dev, cdata); + default: + return -EINVAL; + } +} + static struct comp_driver comp_dai = { .type = SOF_COMP_DAI, .ops = { @@ -700,6 +775,7 @@ static struct comp_driver comp_dai = { .reset = dai_reset, .dai_config = dai_config, .position = dai_position, + .cmd = dai_cmd, }, };