Skip to content

Commit 2cfe1ff

Browse files
Olivier Moysanbroonie
authored andcommitted
ASoC: stm32: sai: add stm32mp25 support
Add STM32MP25 support for STM32 SAI. On STM32MP25 the SAI driver does not manage SAI kernel clock rate by chosing its parent clock, dependending on audio stream rate. The driver requests a rate change on SAI kernel clock instead. This rate change is performed with the following guidelines: - Chose highest rate multiple of the audio stream (Try to get clock accuracy within 1000 ppm) - Ensure clock rate compatibility between SAI sub-blocks A&B and between instances sharing the same flexgen. Use clk_rate_exclusive API to fulfill this requirement. The STM32 SAI peripheral does not support the DMA burst mode on STM32MP25. Add a field in compatible structure to manage DMA burst support capability. Signed-off-by: Olivier Moysan <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 8509bb1 commit 2cfe1ff

File tree

3 files changed

+191
-17
lines changed

3 files changed

+191
-17
lines changed

sound/soc/stm/stm32_sai.c

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,42 @@
1919

2020
#include "stm32_sai.h"
2121

22+
static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai);
23+
2224
static const struct stm32_sai_conf stm32_sai_conf_f4 = {
2325
.version = STM_SAI_STM32F4,
2426
.fifo_size = 8,
2527
.has_spdif_pdm = false,
28+
.get_sai_ck_parent = stm32_sai_get_parent_clk,
2629
};
2730

2831
/*
29-
* Default settings for stm32 H7 socs and next.
32+
* Default settings for STM32H7x socs and STM32MP1x.
3033
* These default settings will be overridden if the soc provides
3134
* support of hardware configuration registers.
35+
* - STM32H7: rely on default settings
36+
* - STM32MP1: retrieve settings from registers
3237
*/
3338
static const struct stm32_sai_conf stm32_sai_conf_h7 = {
3439
.version = STM_SAI_STM32H7,
3540
.fifo_size = 8,
3641
.has_spdif_pdm = true,
42+
.get_sai_ck_parent = stm32_sai_get_parent_clk,
43+
};
44+
45+
/*
46+
* STM32MP2x:
47+
* - do not use SAI parent clock source selection
48+
* - do not use DMA burst mode
49+
*/
50+
static const struct stm32_sai_conf stm32_sai_conf_mp25 = {
51+
.no_dma_burst = true,
3752
};
3853

3954
static const struct of_device_id stm32_sai_ids[] = {
4055
{ .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 },
4156
{ .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 },
57+
{ .compatible = "st,stm32mp25-sai", .data = (void *)&stm32_sai_conf_mp25 },
4258
{}
4359
};
4460

@@ -148,6 +164,29 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client,
148164
return ret;
149165
}
150166

167+
static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai)
168+
{
169+
struct device *dev = &sai->pdev->dev;
170+
171+
sai->clk_x8k = devm_clk_get(dev, "x8k");
172+
if (IS_ERR(sai->clk_x8k)) {
173+
if (PTR_ERR(sai->clk_x8k) != -EPROBE_DEFER)
174+
dev_err(dev, "missing x8k parent clock: %ld\n",
175+
PTR_ERR(sai->clk_x8k));
176+
return PTR_ERR(sai->clk_x8k);
177+
}
178+
179+
sai->clk_x11k = devm_clk_get(dev, "x11k");
180+
if (IS_ERR(sai->clk_x11k)) {
181+
if (PTR_ERR(sai->clk_x11k) != -EPROBE_DEFER)
182+
dev_err(dev, "missing x11k parent clock: %ld\n",
183+
PTR_ERR(sai->clk_x11k));
184+
return PTR_ERR(sai->clk_x11k);
185+
}
186+
187+
return 0;
188+
}
189+
151190
static int stm32_sai_probe(struct platform_device *pdev)
152191
{
153192
struct stm32_sai_data *sai;
@@ -160,6 +199,8 @@ static int stm32_sai_probe(struct platform_device *pdev)
160199
if (!sai)
161200
return -ENOMEM;
162201

202+
sai->pdev = pdev;
203+
163204
sai->base = devm_platform_ioremap_resource(pdev, 0);
164205
if (IS_ERR(sai->base))
165206
return PTR_ERR(sai->base);
@@ -178,15 +219,11 @@ static int stm32_sai_probe(struct platform_device *pdev)
178219
"missing bus clock pclk\n");
179220
}
180221

181-
sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
182-
if (IS_ERR(sai->clk_x8k))
183-
return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x8k),
184-
"missing x8k parent clock\n");
185-
186-
sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k");
187-
if (IS_ERR(sai->clk_x11k))
188-
return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x11k),
189-
"missing x11k parent clock\n");
222+
if (sai->conf.get_sai_ck_parent) {
223+
ret = sai->conf.get_sai_ck_parent(sai);
224+
if (ret)
225+
return ret;
226+
}
190227

191228
/* init irqs */
192229
sai->irq = platform_get_irq(pdev, 0);
@@ -227,7 +264,6 @@ static int stm32_sai_probe(struct platform_device *pdev)
227264
}
228265
clk_disable_unprepare(sai->pclk);
229266

230-
sai->pdev = pdev;
231267
sai->set_sync = &stm32_sai_set_sync;
232268
platform_set_drvdata(pdev, sai);
233269

sound/soc/stm/stm32_sai.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,16 +264,22 @@ enum stm32_sai_syncout {
264264
STM_SAI_SYNC_OUT_B,
265265
};
266266

267+
struct stm32_sai_data;
268+
267269
/**
268270
* struct stm32_sai_conf - SAI configuration
271+
* @get_sai_ck_parent: get parent clock of SAI kernel clock
269272
* @version: SAI version
270273
* @fifo_size: SAI fifo size as words number
271274
* @has_spdif_pdm: SAI S/PDIF and PDM features support flag
275+
* @no_dma_burst: Support only DMA single transfers if set
272276
*/
273277
struct stm32_sai_conf {
278+
int (*get_sai_ck_parent)(struct stm32_sai_data *sai);
274279
u32 version;
275280
u32 fifo_size;
276281
bool has_spdif_pdm;
282+
bool no_dma_burst;
277283
};
278284

279285
/**

sound/soc/stm/stm32_sai_sub.c

Lines changed: 138 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@
6060

6161
#define SAI_MCLK_NAME_LEN 32
6262
#define SAI_RATE_11K 11025
63+
#define SAI_MAX_SAMPLE_RATE_8K 192000
64+
#define SAI_MAX_SAMPLE_RATE_11K 176400
65+
#define SAI_CK_RATE_TOLERANCE 1000 /* ppm */
6366

6467
/**
6568
* struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
@@ -80,6 +83,7 @@
8083
* @dir: SAI block direction (playback or capture). set at init
8184
* @master: SAI block mode flag. (true=master, false=slave) set at init
8285
* @spdif: SAI S/PDIF iec60958 mode flag. set at init
86+
* @sai_ck_used: flag set while exclusivity on SAI kernel clock is active
8387
* @fmt: SAI block format. relevant only for custom protocols. set at init
8488
* @sync: SAI block synchronization mode. (none, internal or external)
8589
* @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
@@ -93,6 +97,8 @@
9397
* @iec958: iec958 data
9498
* @ctrl_lock: control lock
9599
* @irq_lock: prevent race condition with IRQ
100+
* @set_sai_ck_rate: set SAI kernel clock rate
101+
* @put_sai_ck_rate: put SAI kernel clock rate
96102
*/
97103
struct stm32_sai_sub_data {
98104
struct platform_device *pdev;
@@ -112,6 +118,7 @@ struct stm32_sai_sub_data {
112118
int dir;
113119
bool master;
114120
bool spdif;
121+
bool sai_ck_used;
115122
int fmt;
116123
int sync;
117124
int synco;
@@ -125,6 +132,8 @@ struct stm32_sai_sub_data {
125132
struct snd_aes_iec958 iec958;
126133
struct mutex ctrl_lock; /* protect resources accessed by controls */
127134
spinlock_t irq_lock; /* used to prevent race condition with IRQ */
135+
int (*set_sai_ck_rate)(struct stm32_sai_sub_data *sai, unsigned int rate);
136+
void (*put_sai_ck_rate)(struct stm32_sai_sub_data *sai);
128137
};
129138

130139
enum stm32_sai_fifo_th {
@@ -351,8 +360,26 @@ static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai,
351360
return ret;
352361
}
353362

354-
static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai,
355-
unsigned int rate)
363+
static bool stm32_sai_rate_accurate(unsigned int max_rate, unsigned int rate)
364+
{
365+
u64 delta, dividend;
366+
int ratio;
367+
368+
ratio = DIV_ROUND_CLOSEST(max_rate, rate);
369+
if (!ratio)
370+
return false;
371+
372+
dividend = mul_u32_u32(1000000, abs(max_rate - (ratio * rate)));
373+
delta = div_u64(dividend, max_rate);
374+
375+
if (delta <= SAI_CK_RATE_TOLERANCE)
376+
return true;
377+
378+
return false;
379+
}
380+
381+
static int stm32_sai_set_parent_clk(struct stm32_sai_sub_data *sai,
382+
unsigned int rate)
356383
{
357384
struct platform_device *pdev = sai->pdev;
358385
struct clk *parent_clk = sai->pdata->clk_x8k;
@@ -370,6 +397,92 @@ static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai,
370397
return ret;
371398
}
372399

400+
static void stm32_sai_put_parent_rate(struct stm32_sai_sub_data *sai)
401+
{
402+
if (sai->sai_ck_used) {
403+
sai->sai_ck_used = false;
404+
clk_rate_exclusive_put(sai->sai_ck);
405+
}
406+
}
407+
408+
static int stm32_sai_set_parent_rate(struct stm32_sai_sub_data *sai,
409+
unsigned int rate)
410+
{
411+
struct platform_device *pdev = sai->pdev;
412+
unsigned int sai_ck_rate, sai_ck_max_rate, sai_curr_rate, sai_new_rate;
413+
int div, ret;
414+
415+
/*
416+
* Set maximum expected kernel clock frequency
417+
* - mclk on or spdif:
418+
* f_sai_ck = MCKDIV * mclk-fs * fs
419+
* Here typical 256 ratio is assumed for mclk-fs
420+
* - mclk off:
421+
* f_sai_ck = MCKDIV * FRL * fs
422+
* Where FRL=[8..256], MCKDIV=[1..n] (n depends on SAI version)
423+
* Set constraint MCKDIV * FRL <= 256, to ensure MCKDIV is in available range
424+
* f_sai_ck = sai_ck_max_rate * pow_of_two(FRL) / 256
425+
*/
426+
if (!(rate % SAI_RATE_11K))
427+
sai_ck_max_rate = SAI_MAX_SAMPLE_RATE_11K * 256;
428+
else
429+
sai_ck_max_rate = SAI_MAX_SAMPLE_RATE_8K * 256;
430+
431+
if (!sai->sai_mclk && !STM_SAI_PROTOCOL_IS_SPDIF(sai))
432+
sai_ck_max_rate /= DIV_ROUND_CLOSEST(256, roundup_pow_of_two(sai->fs_length));
433+
434+
/*
435+
* Request exclusivity, as the clock is shared by SAI sub-blocks and by
436+
* some SAI instances. This allows to ensure that the rate cannot be
437+
* changed while one or more SAIs are using the clock.
438+
*/
439+
clk_rate_exclusive_get(sai->sai_ck);
440+
sai->sai_ck_used = true;
441+
442+
/*
443+
* Check current kernel clock rate. If it gives the expected accuracy
444+
* return immediately.
445+
*/
446+
sai_curr_rate = clk_get_rate(sai->sai_ck);
447+
if (stm32_sai_rate_accurate(sai_ck_max_rate, sai_curr_rate))
448+
return 0;
449+
450+
/*
451+
* Otherwise try to set the maximum rate and check the new actual rate.
452+
* If the new rate does not give the expected accuracy, try to set
453+
* lower rates for the kernel clock.
454+
*/
455+
sai_ck_rate = sai_ck_max_rate;
456+
div = 1;
457+
do {
458+
/* Check new rate accuracy. Return if ok */
459+
sai_new_rate = clk_round_rate(sai->sai_ck, sai_ck_rate);
460+
if (stm32_sai_rate_accurate(sai_ck_rate, sai_new_rate)) {
461+
ret = clk_set_rate(sai->sai_ck, sai_ck_rate);
462+
if (ret) {
463+
dev_err(&pdev->dev, "Error %d setting sai_ck rate. %s",
464+
ret, ret == -EBUSY ?
465+
"Active stream rates may be in conflict\n" : "\n");
466+
goto err;
467+
}
468+
469+
return 0;
470+
}
471+
472+
/* Try a lower frequency */
473+
div++;
474+
sai_ck_rate = sai_ck_max_rate / div;
475+
} while (sai_ck_rate > rate);
476+
477+
/* No accurate rate found */
478+
dev_err(&pdev->dev, "Failed to find an accurate rate");
479+
480+
err:
481+
stm32_sai_put_parent_rate(sai);
482+
483+
return -EINVAL;
484+
}
485+
373486
static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate,
374487
unsigned long *prate)
375488
{
@@ -565,11 +678,15 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai,
565678
clk_rate_exclusive_put(sai->sai_mclk);
566679
sai->mclk_rate = 0;
567680
}
681+
682+
if (sai->put_sai_ck_rate)
683+
sai->put_sai_ck_rate(sai);
684+
568685
return 0;
569686
}
570687

571-
/* If master clock is used, set parent clock now */
572-
ret = stm32_sai_set_parent_clock(sai, freq);
688+
/* If master clock is used, configure SAI kernel clock now */
689+
ret = sai->set_sai_ck_rate(sai, freq);
573690
if (ret)
574691
return ret;
575692

@@ -993,7 +1110,7 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
9931110
int ret;
9941111

9951112
if (!sai->sai_mclk) {
996-
ret = stm32_sai_set_parent_clock(sai, rate);
1113+
ret = sai->set_sai_ck_rate(sai, rate);
9971114
if (ret)
9981115
return ret;
9991116
}
@@ -1154,6 +1271,14 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
11541271

11551272
clk_disable_unprepare(sai->sai_ck);
11561273

1274+
/*
1275+
* Release kernel clock if following conditions are fulfilled
1276+
* - Master clock is not used. Kernel clock won't be released trough sysclk
1277+
* - Put handler is defined. Involve that clock is managed exclusively
1278+
*/
1279+
if (!sai->sai_mclk && sai->put_sai_ck_rate)
1280+
sai->put_sai_ck_rate(sai);
1281+
11571282
spin_lock_irqsave(&sai->irq_lock, flags);
11581283
sai->substream = NULL;
11591284
spin_unlock_irqrestore(&sai->irq_lock, flags);
@@ -1188,7 +1313,7 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
11881313
* constraints).
11891314
*/
11901315
sai->dma_params.maxburst = 4;
1191-
if (sai->pdata->conf.fifo_size < 8)
1316+
if (sai->pdata->conf.fifo_size < 8 || sai->pdata->conf.no_dma_burst)
11921317
sai->dma_params.maxburst = 1;
11931318
/* Buswidth will be set by framework at runtime */
11941319
sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
@@ -1526,6 +1651,13 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
15261651
return -EINVAL;
15271652
}
15281653

1654+
if (sai->pdata->conf.get_sai_ck_parent) {
1655+
sai->set_sai_ck_rate = stm32_sai_set_parent_clk;
1656+
} else {
1657+
sai->set_sai_ck_rate = stm32_sai_set_parent_rate;
1658+
sai->put_sai_ck_rate = stm32_sai_put_parent_rate;
1659+
}
1660+
15291661
ret = stm32_sai_sub_parse_of(pdev, sai);
15301662
if (ret)
15311663
return ret;

0 commit comments

Comments
 (0)