Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <olivier.moysan@foss.st.com>
Link: https://patch.msgid.link/20241107155143.1340523-3-olivier.moysan@foss.st.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Olivier Moysan and committed by
Mark Brown
2cfe1ff2 8509bb1f

+191 -17
+47 -11
sound/soc/stm/stm32_sai.c
··· 19 19 20 20 #include "stm32_sai.h" 21 21 22 + static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai); 23 + 22 24 static const struct stm32_sai_conf stm32_sai_conf_f4 = { 23 25 .version = STM_SAI_STM32F4, 24 26 .fifo_size = 8, 25 27 .has_spdif_pdm = false, 28 + .get_sai_ck_parent = stm32_sai_get_parent_clk, 26 29 }; 27 30 28 31 /* 29 - * Default settings for stm32 H7 socs and next. 32 + * Default settings for STM32H7x socs and STM32MP1x. 30 33 * These default settings will be overridden if the soc provides 31 34 * support of hardware configuration registers. 35 + * - STM32H7: rely on default settings 36 + * - STM32MP1: retrieve settings from registers 32 37 */ 33 38 static const struct stm32_sai_conf stm32_sai_conf_h7 = { 34 39 .version = STM_SAI_STM32H7, 35 40 .fifo_size = 8, 36 41 .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, 37 52 }; 38 53 39 54 static const struct of_device_id stm32_sai_ids[] = { 40 55 { .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 }, 41 56 { .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 }, 57 + { .compatible = "st,stm32mp25-sai", .data = (void *)&stm32_sai_conf_mp25 }, 42 58 {} 43 59 }; 44 60 ··· 164 148 return ret; 165 149 } 166 150 151 + static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai) 152 + { 153 + struct device *dev = &sai->pdev->dev; 154 + 155 + sai->clk_x8k = devm_clk_get(dev, "x8k"); 156 + if (IS_ERR(sai->clk_x8k)) { 157 + if (PTR_ERR(sai->clk_x8k) != -EPROBE_DEFER) 158 + dev_err(dev, "missing x8k parent clock: %ld\n", 159 + PTR_ERR(sai->clk_x8k)); 160 + return PTR_ERR(sai->clk_x8k); 161 + } 162 + 163 + sai->clk_x11k = devm_clk_get(dev, "x11k"); 164 + if (IS_ERR(sai->clk_x11k)) { 165 + if (PTR_ERR(sai->clk_x11k) != -EPROBE_DEFER) 166 + dev_err(dev, "missing x11k parent clock: %ld\n", 167 + PTR_ERR(sai->clk_x11k)); 168 + return PTR_ERR(sai->clk_x11k); 169 + } 170 + 171 + return 0; 172 + } 173 + 167 174 static int stm32_sai_probe(struct platform_device *pdev) 168 175 { 169 176 struct stm32_sai_data *sai; ··· 198 159 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); 199 160 if (!sai) 200 161 return -ENOMEM; 162 + 163 + sai->pdev = pdev; 201 164 202 165 sai->base = devm_platform_ioremap_resource(pdev, 0); 203 166 if (IS_ERR(sai->base)) ··· 219 178 "missing bus clock pclk\n"); 220 179 } 221 180 222 - sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k"); 223 - if (IS_ERR(sai->clk_x8k)) 224 - return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x8k), 225 - "missing x8k parent clock\n"); 226 - 227 - sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k"); 228 - if (IS_ERR(sai->clk_x11k)) 229 - return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x11k), 230 - "missing x11k parent clock\n"); 181 + if (sai->conf.get_sai_ck_parent) { 182 + ret = sai->conf.get_sai_ck_parent(sai); 183 + if (ret) 184 + return ret; 185 + } 231 186 232 187 /* init irqs */ 233 188 sai->irq = platform_get_irq(pdev, 0); ··· 264 227 } 265 228 clk_disable_unprepare(sai->pclk); 266 229 267 - sai->pdev = pdev; 268 230 sai->set_sync = &stm32_sai_set_sync; 269 231 platform_set_drvdata(pdev, sai); 270 232
+6
sound/soc/stm/stm32_sai.h
··· 264 264 STM_SAI_SYNC_OUT_B, 265 265 }; 266 266 267 + struct stm32_sai_data; 268 + 267 269 /** 268 270 * struct stm32_sai_conf - SAI configuration 271 + * @get_sai_ck_parent: get parent clock of SAI kernel clock 269 272 * @version: SAI version 270 273 * @fifo_size: SAI fifo size as words number 271 274 * @has_spdif_pdm: SAI S/PDIF and PDM features support flag 275 + * @no_dma_burst: Support only DMA single transfers if set 272 276 */ 273 277 struct stm32_sai_conf { 278 + int (*get_sai_ck_parent)(struct stm32_sai_data *sai); 274 279 u32 version; 275 280 u32 fifo_size; 276 281 bool has_spdif_pdm; 282 + bool no_dma_burst; 277 283 }; 278 284 279 285 /**
+138 -6
sound/soc/stm/stm32_sai_sub.c
··· 60 60 61 61 #define SAI_MCLK_NAME_LEN 32 62 62 #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 */ 63 66 64 67 /** 65 68 * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) ··· 83 80 * @dir: SAI block direction (playback or capture). set at init 84 81 * @master: SAI block mode flag. (true=master, false=slave) set at init 85 82 * @spdif: SAI S/PDIF iec60958 mode flag. set at init 83 + * @sai_ck_used: flag set while exclusivity on SAI kernel clock is active 86 84 * @fmt: SAI block format. relevant only for custom protocols. set at init 87 85 * @sync: SAI block synchronization mode. (none, internal or external) 88 86 * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B) ··· 97 93 * @iec958: iec958 data 98 94 * @ctrl_lock: control lock 99 95 * @irq_lock: prevent race condition with IRQ 96 + * @set_sai_ck_rate: set SAI kernel clock rate 97 + * @put_sai_ck_rate: put SAI kernel clock rate 100 98 */ 101 99 struct stm32_sai_sub_data { 102 100 struct platform_device *pdev; ··· 118 112 int dir; 119 113 bool master; 120 114 bool spdif; 115 + bool sai_ck_used; 121 116 int fmt; 122 117 int sync; 123 118 int synco; ··· 132 125 struct snd_aes_iec958 iec958; 133 126 struct mutex ctrl_lock; /* protect resources accessed by controls */ 134 127 spinlock_t irq_lock; /* used to prevent race condition with IRQ */ 128 + int (*set_sai_ck_rate)(struct stm32_sai_sub_data *sai, unsigned int rate); 129 + void (*put_sai_ck_rate)(struct stm32_sai_sub_data *sai); 135 130 }; 136 131 137 132 enum stm32_sai_fifo_th { ··· 360 351 return ret; 361 352 } 362 353 363 - static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai, 364 - unsigned int rate) 354 + static bool stm32_sai_rate_accurate(unsigned int max_rate, unsigned int rate) 355 + { 356 + u64 delta, dividend; 357 + int ratio; 358 + 359 + ratio = DIV_ROUND_CLOSEST(max_rate, rate); 360 + if (!ratio) 361 + return false; 362 + 363 + dividend = mul_u32_u32(1000000, abs(max_rate - (ratio * rate))); 364 + delta = div_u64(dividend, max_rate); 365 + 366 + if (delta <= SAI_CK_RATE_TOLERANCE) 367 + return true; 368 + 369 + return false; 370 + } 371 + 372 + static int stm32_sai_set_parent_clk(struct stm32_sai_sub_data *sai, 373 + unsigned int rate) 365 374 { 366 375 struct platform_device *pdev = sai->pdev; 367 376 struct clk *parent_clk = sai->pdata->clk_x8k; ··· 395 368 "Active stream rates conflict\n" : "\n"); 396 369 397 370 return ret; 371 + } 372 + 373 + static void stm32_sai_put_parent_rate(struct stm32_sai_sub_data *sai) 374 + { 375 + if (sai->sai_ck_used) { 376 + sai->sai_ck_used = false; 377 + clk_rate_exclusive_put(sai->sai_ck); 378 + } 379 + } 380 + 381 + static int stm32_sai_set_parent_rate(struct stm32_sai_sub_data *sai, 382 + unsigned int rate) 383 + { 384 + struct platform_device *pdev = sai->pdev; 385 + unsigned int sai_ck_rate, sai_ck_max_rate, sai_curr_rate, sai_new_rate; 386 + int div, ret; 387 + 388 + /* 389 + * Set maximum expected kernel clock frequency 390 + * - mclk on or spdif: 391 + * f_sai_ck = MCKDIV * mclk-fs * fs 392 + * Here typical 256 ratio is assumed for mclk-fs 393 + * - mclk off: 394 + * f_sai_ck = MCKDIV * FRL * fs 395 + * Where FRL=[8..256], MCKDIV=[1..n] (n depends on SAI version) 396 + * Set constraint MCKDIV * FRL <= 256, to ensure MCKDIV is in available range 397 + * f_sai_ck = sai_ck_max_rate * pow_of_two(FRL) / 256 398 + */ 399 + if (!(rate % SAI_RATE_11K)) 400 + sai_ck_max_rate = SAI_MAX_SAMPLE_RATE_11K * 256; 401 + else 402 + sai_ck_max_rate = SAI_MAX_SAMPLE_RATE_8K * 256; 403 + 404 + if (!sai->sai_mclk && !STM_SAI_PROTOCOL_IS_SPDIF(sai)) 405 + sai_ck_max_rate /= DIV_ROUND_CLOSEST(256, roundup_pow_of_two(sai->fs_length)); 406 + 407 + /* 408 + * Request exclusivity, as the clock is shared by SAI sub-blocks and by 409 + * some SAI instances. This allows to ensure that the rate cannot be 410 + * changed while one or more SAIs are using the clock. 411 + */ 412 + clk_rate_exclusive_get(sai->sai_ck); 413 + sai->sai_ck_used = true; 414 + 415 + /* 416 + * Check current kernel clock rate. If it gives the expected accuracy 417 + * return immediately. 418 + */ 419 + sai_curr_rate = clk_get_rate(sai->sai_ck); 420 + if (stm32_sai_rate_accurate(sai_ck_max_rate, sai_curr_rate)) 421 + return 0; 422 + 423 + /* 424 + * Otherwise try to set the maximum rate and check the new actual rate. 425 + * If the new rate does not give the expected accuracy, try to set 426 + * lower rates for the kernel clock. 427 + */ 428 + sai_ck_rate = sai_ck_max_rate; 429 + div = 1; 430 + do { 431 + /* Check new rate accuracy. Return if ok */ 432 + sai_new_rate = clk_round_rate(sai->sai_ck, sai_ck_rate); 433 + if (stm32_sai_rate_accurate(sai_ck_rate, sai_new_rate)) { 434 + ret = clk_set_rate(sai->sai_ck, sai_ck_rate); 435 + if (ret) { 436 + dev_err(&pdev->dev, "Error %d setting sai_ck rate. %s", 437 + ret, ret == -EBUSY ? 438 + "Active stream rates may be in conflict\n" : "\n"); 439 + goto err; 440 + } 441 + 442 + return 0; 443 + } 444 + 445 + /* Try a lower frequency */ 446 + div++; 447 + sai_ck_rate = sai_ck_max_rate / div; 448 + } while (sai_ck_rate > rate); 449 + 450 + /* No accurate rate found */ 451 + dev_err(&pdev->dev, "Failed to find an accurate rate"); 452 + 453 + err: 454 + stm32_sai_put_parent_rate(sai); 455 + 456 + return -EINVAL; 398 457 } 399 458 400 459 static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate, ··· 678 565 clk_rate_exclusive_put(sai->sai_mclk); 679 566 sai->mclk_rate = 0; 680 567 } 568 + 569 + if (sai->put_sai_ck_rate) 570 + sai->put_sai_ck_rate(sai); 571 + 681 572 return 0; 682 573 } 683 574 684 - /* If master clock is used, set parent clock now */ 685 - ret = stm32_sai_set_parent_clock(sai, freq); 575 + /* If master clock is used, configure SAI kernel clock now */ 576 + ret = sai->set_sai_ck_rate(sai, freq); 686 577 if (ret) 687 578 return ret; 688 579 ··· 1110 993 int ret; 1111 994 1112 995 if (!sai->sai_mclk) { 1113 - ret = stm32_sai_set_parent_clock(sai, rate); 996 + ret = sai->set_sai_ck_rate(sai, rate); 1114 997 if (ret) 1115 998 return ret; 1116 999 } ··· 1271 1154 1272 1155 clk_disable_unprepare(sai->sai_ck); 1273 1156 1157 + /* 1158 + * Release kernel clock if following conditions are fulfilled 1159 + * - Master clock is not used. Kernel clock won't be released trough sysclk 1160 + * - Put handler is defined. Involve that clock is managed exclusively 1161 + */ 1162 + if (!sai->sai_mclk && sai->put_sai_ck_rate) 1163 + sai->put_sai_ck_rate(sai); 1164 + 1274 1165 spin_lock_irqsave(&sai->irq_lock, flags); 1275 1166 sai->substream = NULL; 1276 1167 spin_unlock_irqrestore(&sai->irq_lock, flags); ··· 1313 1188 * constraints). 1314 1189 */ 1315 1190 sai->dma_params.maxburst = 4; 1316 - if (sai->pdata->conf.fifo_size < 8) 1191 + if (sai->pdata->conf.fifo_size < 8 || sai->pdata->conf.no_dma_burst) 1317 1192 sai->dma_params.maxburst = 1; 1318 1193 /* Buswidth will be set by framework at runtime */ 1319 1194 sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; ··· 1649 1524 if (!sai->pdata) { 1650 1525 dev_err(&pdev->dev, "Parent device data not available\n"); 1651 1526 return -EINVAL; 1527 + } 1528 + 1529 + if (sai->pdata->conf.get_sai_ck_parent) { 1530 + sai->set_sai_ck_rate = stm32_sai_set_parent_clk; 1531 + } else { 1532 + sai->set_sai_ck_rate = stm32_sai_set_parent_rate; 1533 + sai->put_sai_ck_rate = stm32_sai_put_parent_rate; 1652 1534 } 1653 1535 1654 1536 ret = stm32_sai_sub_parse_of(pdev, sai);