Skip to content

Commit 20bf873

Browse files
Olivier Moysanbroonie
authored andcommitted
ASoC: stm32: i2s: add stm32mp25 support
Add STM32MP25 support for STM32 I2S. On STM32MP25 the I2S driver does not manage I2S kernel clock rate by choosing its parent clock, depending on audio stream rate. The driver requests a rate change on I2S kernel clock instead. It tries to set the higher possible rate, which is a multiple of the audio stream rate and which gives an accuracy of at least 1000 ppm. Signed-off-by: Olivier Moysan <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent c69b7ed commit 20bf873

File tree

1 file changed

+189
-22
lines changed

1 file changed

+189
-22
lines changed

sound/soc/stm/stm32_i2s.c

Lines changed: 189 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,13 @@ enum i2s_datlen {
200200

201201
#define STM32_I2S_NAME_LEN 32
202202
#define STM32_I2S_RATE_11K 11025
203+
#define STM32_I2S_MAX_SAMPLE_RATE_8K 192000
204+
#define STM32_I2S_MAX_SAMPLE_RATE_11K 176400
205+
#define STM32_I2S_CLK_RATE_TOLERANCE 1000 /* ppm */
203206

204207
/**
205208
* struct stm32_i2s_data - private data of I2S
206-
* @regmap_conf: I2S register map configuration pointer
209+
* @conf: I2S configuration pointer
207210
* @regmap: I2S register map pointer
208211
* @pdev: device data pointer
209212
* @dai_drv: DAI driver pointer
@@ -224,11 +227,14 @@ enum i2s_datlen {
224227
* @divider: prescaler division ratio
225228
* @div: prescaler div field
226229
* @odd: prescaler odd field
230+
* @i2s_clk_flg: flag set while exclusivity on I2S kernel clock is active
227231
* @refcount: keep count of opened streams on I2S
228232
* @ms_flg: master mode flag.
233+
* @set_i2s_clk_rate: set I2S kernel clock rate
234+
* @put_i2s_clk_rate: put I2S kernel clock rate
229235
*/
230236
struct stm32_i2s_data {
231-
const struct regmap_config *regmap_conf;
237+
const struct stm32_i2s_conf *conf;
232238
struct regmap *regmap;
233239
struct platform_device *pdev;
234240
struct snd_soc_dai_driver *dai_drv;
@@ -249,8 +255,21 @@ struct stm32_i2s_data {
249255
unsigned int divider;
250256
unsigned int div;
251257
bool odd;
258+
bool i2s_clk_flg;
252259
int refcount;
253260
int ms_flg;
261+
int (*set_i2s_clk_rate)(struct stm32_i2s_data *i2s, unsigned int rate);
262+
void (*put_i2s_clk_rate)(struct stm32_i2s_data *i2s);
263+
};
264+
265+
/**
266+
* struct stm32_i2s_conf - I2S configuration
267+
* @regmap_conf: regmap configuration pointer
268+
* @get_i2s_clk_parent: get parent clock of I2S kernel clock
269+
*/
270+
struct stm32_i2s_conf {
271+
const struct regmap_config *regmap_conf;
272+
int (*get_i2s_clk_parent)(struct stm32_i2s_data *i2s);
254273
};
255274

256275
struct stm32_i2smclk_data {
@@ -261,6 +280,8 @@ struct stm32_i2smclk_data {
261280

262281
#define to_mclk_data(_hw) container_of(_hw, struct stm32_i2smclk_data, hw)
263282

283+
static int stm32_i2s_get_parent_clk(struct stm32_i2s_data *i2s);
284+
264285
static int stm32_i2s_calc_clk_div(struct stm32_i2s_data *i2s,
265286
unsigned long input_rate,
266287
unsigned long output_rate)
@@ -312,6 +333,33 @@ static int stm32_i2s_set_clk_div(struct stm32_i2s_data *i2s)
312333
cgfr_mask, cgfr);
313334
}
314335

336+
static bool stm32_i2s_rate_accurate(struct stm32_i2s_data *i2s,
337+
unsigned int max_rate, unsigned int rate)
338+
{
339+
struct platform_device *pdev = i2s->pdev;
340+
u64 delta, dividend;
341+
int ratio;
342+
343+
if (!rate) {
344+
dev_err(&pdev->dev, "Unexpected null rate\n");
345+
return false;
346+
}
347+
348+
ratio = DIV_ROUND_CLOSEST(max_rate, rate);
349+
if (!ratio)
350+
return false;
351+
352+
dividend = mul_u32_u32(1000000, abs(max_rate - (ratio * rate)));
353+
delta = div_u64(dividend, max_rate);
354+
355+
if (delta <= STM32_I2S_CLK_RATE_TOLERANCE)
356+
return true;
357+
358+
dev_dbg(&pdev->dev, "Rate [%u] not accurate\n", rate);
359+
360+
return false;
361+
}
362+
315363
static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s,
316364
unsigned int rate)
317365
{
@@ -332,6 +380,87 @@ static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s,
332380
return ret;
333381
}
334382

383+
static void stm32_i2s_put_parent_rate(struct stm32_i2s_data *i2s)
384+
{
385+
if (i2s->i2s_clk_flg) {
386+
i2s->i2s_clk_flg = false;
387+
clk_rate_exclusive_put(i2s->i2sclk);
388+
}
389+
}
390+
391+
static int stm32_i2s_set_parent_rate(struct stm32_i2s_data *i2s,
392+
unsigned int rate)
393+
{
394+
struct platform_device *pdev = i2s->pdev;
395+
unsigned int i2s_clk_rate, i2s_clk_max_rate, i2s_curr_rate, i2s_new_rate;
396+
int ret, div;
397+
398+
/*
399+
* Set maximum expected kernel clock frequency
400+
* - mclk on:
401+
* f_i2s_ck = MCKDIV * mclk-fs * fs
402+
* Here typical 256 ratio is assumed for mclk-fs
403+
* - mclk off:
404+
* f_i2s_ck = MCKDIV * FRL * fs
405+
* Where FRL=[16,32], MCKDIV=[1..256]
406+
* f_i2s_ck = i2s_clk_max_rate * 32 / 256
407+
*/
408+
if (!(rate % STM32_I2S_RATE_11K))
409+
i2s_clk_max_rate = STM32_I2S_MAX_SAMPLE_RATE_11K * 256;
410+
else
411+
i2s_clk_max_rate = STM32_I2S_MAX_SAMPLE_RATE_8K * 256;
412+
413+
if (!i2s->i2smclk)
414+
i2s_clk_max_rate /= 8;
415+
416+
/* Request exclusivity, as the clock may be shared by I2S instances */
417+
clk_rate_exclusive_get(i2s->i2sclk);
418+
i2s->i2s_clk_flg = true;
419+
420+
/*
421+
* Check current kernel clock rate. If it gives the expected accuracy
422+
* return immediately.
423+
*/
424+
i2s_curr_rate = clk_get_rate(i2s->i2sclk);
425+
if (stm32_i2s_rate_accurate(i2s, i2s_clk_max_rate, i2s_curr_rate))
426+
return 0;
427+
428+
/*
429+
* Otherwise try to set the maximum rate and check the new actual rate.
430+
* If the new rate does not give the expected accuracy, try to set
431+
* lower rates for the kernel clock.
432+
*/
433+
i2s_clk_rate = i2s_clk_max_rate;
434+
div = 1;
435+
do {
436+
/* Check new rate accuracy. Return if ok */
437+
i2s_new_rate = clk_round_rate(i2s->i2sclk, i2s_clk_rate);
438+
if (stm32_i2s_rate_accurate(i2s, i2s_clk_rate, i2s_new_rate)) {
439+
ret = clk_set_rate(i2s->i2sclk, i2s_clk_rate);
440+
if (ret) {
441+
dev_err(&pdev->dev, "Error %d setting i2s_clk_rate rate. %s",
442+
ret, ret == -EBUSY ?
443+
"Active stream rates may be in conflict\n" : "\n");
444+
goto err;
445+
}
446+
447+
return 0;
448+
}
449+
450+
/* Try a lower frequency */
451+
div++;
452+
i2s_clk_rate = i2s_clk_max_rate / div;
453+
} while (i2s_clk_rate > rate);
454+
455+
/* no accurate rate found */
456+
dev_err(&pdev->dev, "Failed to find an accurate rate");
457+
458+
err:
459+
stm32_i2s_put_parent_rate(i2s);
460+
461+
return -EINVAL;
462+
}
463+
335464
static long stm32_i2smclk_round_rate(struct clk_hw *hw, unsigned long rate,
336465
unsigned long *prate)
337466
{
@@ -635,12 +764,16 @@ static int stm32_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
635764
clk_rate_exclusive_put(i2s->i2smclk);
636765
i2s->mclk_rate = 0;
637766
}
767+
768+
if (i2s->put_i2s_clk_rate)
769+
i2s->put_i2s_clk_rate(i2s);
770+
638771
return regmap_update_bits(i2s->regmap,
639772
STM32_I2S_CGFR_REG,
640773
I2S_CGFR_MCKOE, 0);
641774
}
642775
/* If master clock is used, set parent clock now */
643-
ret = stm32_i2s_set_parent_clock(i2s, freq);
776+
ret = i2s->set_i2s_clk_rate(i2s, freq);
644777
if (ret)
645778
return ret;
646779
ret = clk_set_rate_exclusive(i2s->i2smclk, freq);
@@ -667,10 +800,11 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai,
667800
u32 cgfr;
668801
int ret;
669802

670-
if (!(rate % 11025))
671-
clk_set_parent(i2s->i2sclk, i2s->x11kclk);
672-
else
673-
clk_set_parent(i2s->i2sclk, i2s->x8kclk);
803+
if (!i2s->mclk_rate) {
804+
ret = i2s->set_i2s_clk_rate(i2s, rate);
805+
if (ret)
806+
return ret;
807+
}
674808
i2s_clock_rate = clk_get_rate(i2s->i2sclk);
675809

676810
/*
@@ -915,6 +1049,14 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream,
9151049

9161050
clk_disable_unprepare(i2s->i2sclk);
9171051

1052+
/*
1053+
* Release kernel clock if following conditions are fulfilled
1054+
* - Master clock is not used. Kernel clock won't be released trough sysclk
1055+
* - Put handler is defined. Involve that clock is managed exclusively
1056+
*/
1057+
if (!i2s->i2smclk && i2s->put_i2s_clk_rate)
1058+
i2s->put_i2s_clk_rate(i2s);
1059+
9181060
spin_lock_irqsave(&i2s->irq_lock, flags);
9191061
i2s->substream = NULL;
9201062
spin_unlock_irqrestore(&i2s->irq_lock, flags);
@@ -1012,14 +1154,36 @@ static int stm32_i2s_dais_init(struct platform_device *pdev,
10121154
return 0;
10131155
}
10141156

1157+
static const struct stm32_i2s_conf stm32_i2s_conf_h7 = {
1158+
.regmap_conf = &stm32_h7_i2s_regmap_conf,
1159+
.get_i2s_clk_parent = stm32_i2s_get_parent_clk,
1160+
};
1161+
1162+
static const struct stm32_i2s_conf stm32_i2s_conf_mp25 = {
1163+
.regmap_conf = &stm32_h7_i2s_regmap_conf
1164+
};
1165+
10151166
static const struct of_device_id stm32_i2s_ids[] = {
1016-
{
1017-
.compatible = "st,stm32h7-i2s",
1018-
.data = &stm32_h7_i2s_regmap_conf
1019-
},
1167+
{ .compatible = "st,stm32h7-i2s", .data = &stm32_i2s_conf_h7 },
1168+
{ .compatible = "st,stm32mp25-i2s", .data = &stm32_i2s_conf_mp25 },
10201169
{},
10211170
};
10221171

1172+
static int stm32_i2s_get_parent_clk(struct stm32_i2s_data *i2s)
1173+
{
1174+
struct device *dev = &i2s->pdev->dev;
1175+
1176+
i2s->x8kclk = devm_clk_get(dev, "x8k");
1177+
if (IS_ERR(i2s->x8kclk))
1178+
return dev_err_probe(dev, PTR_ERR(i2s->x8kclk), "Cannot get x8k parent clock\n");
1179+
1180+
i2s->x11kclk = devm_clk_get(dev, "x11k");
1181+
if (IS_ERR(i2s->x11kclk))
1182+
return dev_err_probe(dev, PTR_ERR(i2s->x11kclk), "Cannot get x11k parent clock\n");
1183+
1184+
return 0;
1185+
}
1186+
10231187
static int stm32_i2s_parse_dt(struct platform_device *pdev,
10241188
struct stm32_i2s_data *i2s)
10251189
{
@@ -1031,8 +1195,8 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
10311195
if (!np)
10321196
return -ENODEV;
10331197

1034-
i2s->regmap_conf = device_get_match_data(&pdev->dev);
1035-
if (!i2s->regmap_conf)
1198+
i2s->conf = device_get_match_data(&pdev->dev);
1199+
if (!i2s->conf)
10361200
return -EINVAL;
10371201

10381202
i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
@@ -1052,15 +1216,18 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
10521216
return dev_err_probe(&pdev->dev, PTR_ERR(i2s->i2sclk),
10531217
"Could not get i2sclk\n");
10541218

1055-
i2s->x8kclk = devm_clk_get(&pdev->dev, "x8k");
1056-
if (IS_ERR(i2s->x8kclk))
1057-
return dev_err_probe(&pdev->dev, PTR_ERR(i2s->x8kclk),
1058-
"Could not get x8k parent clock\n");
1219+
if (i2s->conf->get_i2s_clk_parent) {
1220+
i2s->set_i2s_clk_rate = stm32_i2s_set_parent_clock;
1221+
} else {
1222+
i2s->set_i2s_clk_rate = stm32_i2s_set_parent_rate;
1223+
i2s->put_i2s_clk_rate = stm32_i2s_put_parent_rate;
1224+
}
10591225

1060-
i2s->x11kclk = devm_clk_get(&pdev->dev, "x11k");
1061-
if (IS_ERR(i2s->x11kclk))
1062-
return dev_err_probe(&pdev->dev, PTR_ERR(i2s->x11kclk),
1063-
"Could not get x11k parent clock\n");
1226+
if (i2s->conf->get_i2s_clk_parent) {
1227+
ret = i2s->conf->get_i2s_clk_parent(i2s);
1228+
if (ret)
1229+
return ret;
1230+
}
10641231

10651232
/* Register mclk provider if requested */
10661233
if (of_property_present(np, "#clock-cells")) {
@@ -1126,7 +1293,7 @@ static int stm32_i2s_probe(struct platform_device *pdev)
11261293
return ret;
11271294

11281295
i2s->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "pclk",
1129-
i2s->base, i2s->regmap_conf);
1296+
i2s->base, i2s->conf->regmap_conf);
11301297
if (IS_ERR(i2s->regmap))
11311298
return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap),
11321299
"Regmap init error\n");

0 commit comments

Comments
 (0)