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, }, }; 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/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 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, }; 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) { 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;