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

ASoC: mxs-saif: support usage with simple-audio-card

Add support for enabling MCLK output when using the simple-audio-card
driver. In the sound/soc/mxs/mxs-sgtl5000.c use case, that driver
handles MCLK enable/disable by calling mxs_saif_get_mclk() and
mxs_saif_put_mclk() at probe/remove. This does not happen when the
simple-audio-card driver is used. Extend the mxs-saif driver to enable
MCLK output in that scenario.

Co-developed-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
Link: https://patch.msgid.link/20250924130749.3012071-1-dario.binacchi@amarulasolutions.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Dario Binacchi and committed by
Mark Brown
1e570e77 6621b0f1

+90 -33
+90 -33
sound/soc/mxs/mxs-saif.c
··· 24 24 #define MXS_SET_ADDR 0x4 25 25 #define MXS_CLR_ADDR 0x8 26 26 27 + #define MXS_SAIF_BUSY_TIMEOUT_US 10000 28 + 27 29 static struct mxs_saif *mxs_saif[2]; 30 + 31 + /* 32 + * Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK 33 + * is provided by other SAIF, we provide a interface here to get its master 34 + * from its master_id. 35 + * Note that the master could be itself. 36 + */ 37 + static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif *saif) 38 + { 39 + return mxs_saif[saif->master_id]; 40 + } 41 + 42 + static int __mxs_saif_put_mclk(struct mxs_saif *saif) 43 + { 44 + u32 stat; 45 + int ret; 46 + 47 + ret = readx_poll_timeout(__raw_readl, saif->base + SAIF_STAT, stat, 48 + (stat & BM_SAIF_STAT_BUSY) == 0, 49 + MXS_SAIF_BUSY_TIMEOUT_US, 50 + USEC_PER_SEC); 51 + if (ret) { 52 + dev_err(saif->dev, "error: busy\n"); 53 + return -EBUSY; 54 + } 55 + 56 + /* disable MCLK output */ 57 + __raw_writel(BM_SAIF_CTRL_CLKGATE, 58 + saif->base + SAIF_CTRL + MXS_SET_ADDR); 59 + __raw_writel(BM_SAIF_CTRL_RUN, 60 + saif->base + SAIF_CTRL + MXS_CLR_ADDR); 61 + 62 + saif->mclk_in_use = 0; 63 + 64 + return 0; 65 + } 66 + 67 + static int __mxs_saif_get_mclk(struct mxs_saif *saif) 68 + { 69 + u32 stat; 70 + struct mxs_saif *master_saif; 71 + 72 + if (!saif) 73 + return -EINVAL; 74 + 75 + /* Clear Reset */ 76 + __raw_writel(BM_SAIF_CTRL_SFTRST, 77 + saif->base + SAIF_CTRL + MXS_CLR_ADDR); 78 + 79 + /* FIXME: need clear clk gate for register r/w */ 80 + __raw_writel(BM_SAIF_CTRL_CLKGATE, 81 + saif->base + SAIF_CTRL + MXS_CLR_ADDR); 82 + 83 + master_saif = mxs_saif_get_master(saif); 84 + if (saif != master_saif) { 85 + dev_err(saif->dev, "can not get mclk from a non-master saif\n"); 86 + return -EINVAL; 87 + } 88 + 89 + stat = __raw_readl(saif->base + SAIF_STAT); 90 + if (stat & BM_SAIF_STAT_BUSY) { 91 + dev_err(saif->dev, "error: busy\n"); 92 + return -EBUSY; 93 + } 94 + 95 + saif->mclk_in_use = 1; 96 + 97 + return 0; 98 + } 28 99 29 100 /* 30 101 * SAIF is a little different with other normal SOC DAIs on clock using. ··· 119 48 int clk_id, unsigned int freq, int dir) 120 49 { 121 50 struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); 51 + int ret; 122 52 123 53 switch (clk_id) { 124 54 case MXS_SAIF_MCLK: ··· 128 56 default: 129 57 return -EINVAL; 130 58 } 131 - return 0; 132 - } 133 59 134 - /* 135 - * Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK 136 - * is provided by other SAIF, we provide a interface here to get its master 137 - * from its master_id. 138 - * Note that the master could be itself. 139 - */ 140 - static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif * saif) 141 - { 142 - return mxs_saif[saif->master_id]; 60 + if (!saif->mclk_in_use && freq) { 61 + ret = __mxs_saif_get_mclk(saif); 62 + if (ret) 63 + return ret; 64 + 65 + /* enable MCLK output */ 66 + __raw_writel(BM_SAIF_CTRL_RUN, 67 + saif->base + SAIF_CTRL + MXS_SET_ADDR); 68 + } else if (saif->mclk_in_use && freq == 0) { 69 + ret = __mxs_saif_put_mclk(saif); 70 + if (ret) 71 + return ret; 72 + } 73 + 74 + return 0; 143 75 } 144 76 145 77 /* ··· 314 238 unsigned int rate) 315 239 { 316 240 struct mxs_saif *saif = mxs_saif[saif_id]; 317 - u32 stat; 318 241 int ret; 319 - struct mxs_saif *master_saif; 320 242 321 243 if (!saif) 322 244 return -EINVAL; 323 245 324 - /* Clear Reset */ 325 - __raw_writel(BM_SAIF_CTRL_SFTRST, 326 - saif->base + SAIF_CTRL + MXS_CLR_ADDR); 246 + ret = __mxs_saif_get_mclk(saif); 247 + if (ret) 248 + return ret; 327 249 328 - /* FIXME: need clear clk gate for register r/w */ 329 - __raw_writel(BM_SAIF_CTRL_CLKGATE, 330 - saif->base + SAIF_CTRL + MXS_CLR_ADDR); 331 - 332 - master_saif = mxs_saif_get_master(saif); 333 - if (saif != master_saif) { 334 - dev_err(saif->dev, "can not get mclk from a non-master saif\n"); 335 - return -EINVAL; 336 - } 337 - 338 - stat = __raw_readl(saif->base + SAIF_STAT); 339 - if (stat & BM_SAIF_STAT_BUSY) { 340 - dev_err(saif->dev, "error: busy\n"); 341 - return -EBUSY; 342 - } 343 - 344 - saif->mclk_in_use = 1; 345 250 ret = mxs_saif_set_clk(saif, mclk, rate); 346 251 if (ret) 347 252 return ret;