Skip to content

Commit e819f50

Browse files
bardliaomwasko
authored andcommitted
intel: ssp: introduce ssp_set/release_mclk/bclk helpers to set/release mclk/bclk
MCLK and BCLK can be set/release separately. We can set/release mclk/bclk more flexible with these helpers. The helpers are defined after the Linux ones, 'prepare_enable' will first select the relevant resources then enable the clock output. Conversely 'disable_unprepare' will stop the clock output then release the clock resources. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Signed-off-by: Brent Lu <brent.lu@intel.com>
1 parent f2aa411 commit e819f50

2 files changed

Lines changed: 123 additions & 73 deletions

File tree

src/drivers/intel/ssp/ssp.c

Lines changed: 119 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,112 @@ static int ssp_context_restore(struct dai *dai)
125125
return 0;
126126
}
127127

128+
static int ssp_mclk_prepare_enable(struct dai *dai)
129+
{
130+
struct ssp_pdata *ssp = dai_get_drvdata(dai);
131+
struct sof_ipc_dai_config *config = &ssp->config;
132+
int ret;
133+
134+
if (ssp->clk_active & SSP_CLK_MCLK_ACTIVE)
135+
return 0;
136+
137+
/* MCLK config */
138+
ret = mn_set_mclk(config->ssp.mclk_id, config->ssp.mclk_rate);
139+
if (ret < 0)
140+
dai_err(dai, "ssp_mclk_prepare_enable(): invalid mclk_rate = %d for mclk_id = %d",
141+
config->ssp.mclk_rate, config->ssp.mclk_id);
142+
else
143+
ssp->clk_active |= SSP_CLK_MCLK_ACTIVE;
144+
145+
return ret;
146+
}
147+
148+
static void ssp_mclk_disable_unprepare(struct dai *dai)
149+
{
150+
struct ssp_pdata *ssp = dai_get_drvdata(dai);
151+
152+
if (!(ssp->clk_active & SSP_CLK_MCLK_ACTIVE))
153+
return;
154+
155+
mn_release_mclk(ssp->config.ssp.mclk_id);
156+
157+
ssp->clk_active &= ~SSP_CLK_MCLK_ACTIVE;
158+
}
159+
160+
static int ssp_bclk_prepare_enable(struct dai *dai)
161+
{
162+
struct ssp_pdata *ssp = dai_get_drvdata(dai);
163+
struct sof_ipc_dai_config *config = &ssp->config;
164+
uint32_t sscr0;
165+
uint32_t mdiv;
166+
bool need_ecs = false;
167+
int ret = 0;
168+
169+
if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE)
170+
return 0;
171+
172+
sscr0 = ssp_read(dai, SSCR0);
173+
174+
#if CONFIG_INTEL_MN
175+
/* BCLK config */
176+
ret = mn_set_bclk(config->dai_index, config->ssp.bclk_rate,
177+
&mdiv, &need_ecs);
178+
if (ret < 0) {
179+
dai_err(dai, "ssp_bclk_prepare_enable(): invalid bclk_rate = %d for dai_index = %d",
180+
config->ssp.bclk_rate, config->dai_index);
181+
goto out;
182+
}
183+
#else
184+
if (ssp_freq[SSP_DEFAULT_IDX].freq % config->ssp.bclk_rate != 0) {
185+
dai_err(dai, "ssp_bclk_prepare_enable(): invalid bclk_rate = %d for dai_index = %d",
186+
config->ssp.bclk_rate, config->dai_index);
187+
ret = -EINVAL;
188+
goto out;
189+
}
190+
191+
mdiv = ssp_freq[SSP_DEFAULT_IDX].freq / config->ssp.bclk_rate;
192+
#endif
193+
194+
if (need_ecs)
195+
sscr0 |= SSCR0_ECS;
196+
197+
/* clock divisor is SCR + 1 */
198+
mdiv -= 1;
199+
200+
/* divisor must be within SCR range */
201+
if (mdiv > (SSCR0_SCR_MASK >> 8)) {
202+
dai_err(dai, "ssp_bclk_prepare_enable(): divisor %d is not within SCR range",
203+
mdiv);
204+
ret = -EINVAL;
205+
goto out;
206+
}
207+
208+
/* set the SCR divisor */
209+
sscr0 &= ~SSCR0_SCR_MASK;
210+
sscr0 |= SSCR0_SCR(mdiv);
211+
212+
ssp_write(dai, SSCR0, sscr0);
213+
214+
dai_info(dai, "ssp_bclk_prepare_enable(): sscr0 = 0x%08x", sscr0);
215+
out:
216+
if (!ret)
217+
ssp->clk_active |= SSP_CLK_BCLK_ACTIVE;
218+
219+
return ret;
220+
}
221+
222+
static void ssp_bclk_disable_unprepare(struct dai *dai)
223+
{
224+
struct ssp_pdata *ssp = dai_get_drvdata(dai);
225+
226+
if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE))
227+
return;
228+
#if CONFIG_INTEL_MN
229+
mn_release_bclk(dai->index);
230+
#endif
231+
ssp->clk_active &= ~SSP_CLK_BCLK_ACTIVE;
232+
}
233+
128234
/* Digital Audio interface formatting */
129235
static int ssp_set_config(struct dai *dai,
130236
struct sof_ipc_dai_config *config)
@@ -619,75 +725,21 @@ static int ssp_set_config(struct dai *dai,
619725
*/
620726
static int ssp_pre_start(struct dai *dai)
621727
{
622-
struct ssp_pdata *ssp = dai_get_drvdata(dai);
623-
struct sof_ipc_dai_config *config = &ssp->config;
624-
uint32_t sscr0;
625-
uint32_t mdiv;
626-
bool need_ecs = false;
627-
628-
int ret = 0;
728+
int ret;
629729

630730
dai_info(dai, "ssp_pre_start()");
631731

632-
/* SSP active means bclk already configured. */
633-
if (ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_ACTIVE ||
634-
ssp->state[SOF_IPC_STREAM_CAPTURE] == COMP_STATE_ACTIVE)
635-
return 0;
732+
/*
733+
* We will test if mclk/bclk is configured in
734+
* ssp_mclk/bclk_prepare_enable/disable functions
735+
*/
636736

637737
/* MCLK config */
638-
ret = mn_set_mclk(config->ssp.mclk_id, config->ssp.mclk_rate);
639-
if (ret < 0) {
640-
dai_err(dai, "invalid mclk_rate = %d for mclk_id = %d",
641-
config->ssp.mclk_rate, config->ssp.mclk_id);
642-
goto out;
643-
}
644-
645-
sscr0 = ssp_read(dai, SSCR0);
738+
ret = ssp_mclk_prepare_enable(dai);
739+
if (ret < 0)
740+
return ret;
646741

647-
#if CONFIG_INTEL_MN
648-
/* BCLK config */
649-
ret = mn_set_bclk(config->dai_index, config->ssp.bclk_rate,
650-
&mdiv, &need_ecs);
651-
if (ret < 0) {
652-
dai_err(dai, "invalid bclk_rate = %d for dai_index = %d",
653-
config->ssp.bclk_rate, config->dai_index);
654-
goto out;
655-
}
656-
#else
657-
if (ssp_freq[SSP_DEFAULT_IDX].freq % config->ssp.bclk_rate != 0) {
658-
dai_err(dai, "invalid bclk_rate = %d for dai_index = %d",
659-
config->ssp.bclk_rate, config->dai_index);
660-
ret = -EINVAL;
661-
goto out;
662-
}
663-
664-
mdiv = ssp_freq[SSP_DEFAULT_IDX].freq / config->ssp.bclk_rate;
665-
#endif
666-
667-
if (need_ecs)
668-
sscr0 |= SSCR0_ECS;
669-
670-
/* clock divisor is SCR + 1 */
671-
mdiv -= 1;
672-
673-
/* divisor must be within SCR range */
674-
if (mdiv > (SSCR0_SCR_MASK >> 8)) {
675-
dai_err(dai, "ssp_pre_start(): divisor %d is not within SCR range",
676-
mdiv);
677-
ret = -EINVAL;
678-
goto out;
679-
}
680-
681-
/* set the SCR divisor */
682-
sscr0 &= ~SSCR0_SCR_MASK;
683-
sscr0 |= SSCR0_SCR(mdiv);
684-
685-
ssp_write(dai, SSCR0, sscr0);
686-
687-
dai_info(dai, "ssp_set_config(), sscr0 = 0x%08x", sscr0);
688-
out:
689-
690-
return ret;
742+
return ssp_bclk_prepare_enable(dai);
691743
}
692744

693745
/*
@@ -703,10 +755,8 @@ static void ssp_post_stop(struct dai *dai)
703755
if (ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_ACTIVE &&
704756
ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_ACTIVE) {
705757
dai_info(dai, "releasing BCLK/MCLK clocks for SSP%d...", dai->index);
706-
#if CONFIG_INTEL_MN
707-
mn_release_bclk(dai->index);
708-
#endif
709-
mn_release_mclk(ssp->config.ssp.mclk_id);
758+
ssp_bclk_disable_unprepare(dai);
759+
ssp_mclk_disable_unprepare(dai);
710760
}
711761
}
712762

@@ -907,14 +957,10 @@ static int ssp_probe(struct dai *dai)
907957

908958
static int ssp_remove(struct dai *dai)
909959
{
910-
struct ssp_pdata *ssp = dai_get_drvdata(dai);
911-
912960
pm_runtime_put_sync(SSP_CLK, dai->index);
913961

914-
mn_release_mclk(ssp->config.ssp.mclk_id);
915-
#if CONFIG_INTEL_MN
916-
mn_release_bclk(dai->index);
917-
#endif
962+
ssp_mclk_disable_unprepare(dai);
963+
ssp_bclk_disable_unprepare(dai);
918964

919965
/* Disable SSP power */
920966
pm_runtime_put_sync(SSP_POW, dai->index);

src/include/sof/drivers/ssp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,16 @@ extern const struct dai_driver ssp_driver;
224224
#define ssp_irq(ssp) \
225225
ssp->plat_data.irq
226226

227+
#define SSP_CLK_MCLK_ACTIVE BIT(0)
228+
#define SSP_CLK_BCLK_ACTIVE BIT(1)
229+
227230
/* SSP private data */
228231
struct ssp_pdata {
229232
uint32_t sscr0;
230233
uint32_t sscr1;
231234
uint32_t psp;
232235
uint32_t state[2]; /* SSP_STATE_ for each direction */
236+
uint32_t clk_active;
233237
struct sof_ipc_dai_config config;
234238
struct sof_ipc_dai_ssp_params params;
235239
};

0 commit comments

Comments
 (0)