1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // AMD ALSA SoC PCM Driver 4 // 5 // Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved. 6 7 #include <linux/platform_device.h> 8 #include <linux/module.h> 9 #include <linux/err.h> 10 #include <linux/io.h> 11 #include <sound/pcm_params.h> 12 #include <sound/soc.h> 13 #include <sound/soc-dai.h> 14 #include <linux/dma-mapping.h> 15 16 #include "acp5x.h" 17 18 #define DRV_NAME "acp5x_i2s_playcap" 19 20 static int acp5x_i2s_set_fmt(struct snd_soc_dai *cpu_dai, 21 unsigned int fmt) 22 { 23 struct i2s_dev_data *adata; 24 int mode; 25 26 adata = snd_soc_dai_get_drvdata(cpu_dai); 27 mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; 28 switch (mode) { 29 case SND_SOC_DAIFMT_I2S: 30 adata->tdm_mode = TDM_DISABLE; 31 break; 32 case SND_SOC_DAIFMT_DSP_A: 33 adata->tdm_mode = TDM_ENABLE; 34 break; 35 default: 36 return -EINVAL; 37 } 38 mode = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; 39 switch (mode) { 40 case SND_SOC_DAIFMT_CBC_CFC: 41 adata->master_mode = I2S_MASTER_MODE_ENABLE; 42 break; 43 case SND_SOC_DAIFMT_CBP_CFP: 44 adata->master_mode = I2S_MASTER_MODE_DISABLE; 45 break; 46 } 47 return 0; 48 } 49 50 static int acp5x_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, 51 u32 tx_mask, u32 rx_mask, 52 int slots, int slot_width) 53 { 54 struct i2s_dev_data *adata; 55 u32 frm_len; 56 u16 slot_len; 57 58 adata = snd_soc_dai_get_drvdata(cpu_dai); 59 60 /* These values are as per Hardware Spec */ 61 switch (slot_width) { 62 case SLOT_WIDTH_8: 63 slot_len = 8; 64 break; 65 case SLOT_WIDTH_16: 66 slot_len = 16; 67 break; 68 case SLOT_WIDTH_24: 69 slot_len = 24; 70 break; 71 case SLOT_WIDTH_32: 72 slot_len = 0; 73 break; 74 default: 75 return -EINVAL; 76 } 77 frm_len = FRM_LEN | (slots << 15) | (slot_len << 18); 78 adata->tdm_fmt = frm_len; 79 return 0; 80 } 81 82 static int acp5x_i2s_hwparams(struct snd_pcm_substream *substream, 83 struct snd_pcm_hw_params *params, 84 struct snd_soc_dai *dai) 85 { 86 struct i2s_stream_instance *rtd; 87 struct snd_soc_pcm_runtime *prtd; 88 struct snd_soc_card *card; 89 struct acp5x_platform_info *pinfo; 90 struct i2s_dev_data *adata; 91 union acp_i2stdm_mstrclkgen mclkgen; 92 93 u32 val; 94 u32 reg_val, frmt_reg, master_reg; 95 u32 lrclk_div_val, bclk_div_val; 96 97 lrclk_div_val = 0; 98 bclk_div_val = 0; 99 prtd = asoc_substream_to_rtd(substream); 100 rtd = substream->runtime->private_data; 101 card = prtd->card; 102 adata = snd_soc_dai_get_drvdata(dai); 103 pinfo = snd_soc_card_get_drvdata(card); 104 if (pinfo) { 105 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 106 rtd->i2s_instance = pinfo->play_i2s_instance; 107 else 108 rtd->i2s_instance = pinfo->cap_i2s_instance; 109 } 110 111 /* These values are as per Hardware Spec */ 112 switch (params_format(params)) { 113 case SNDRV_PCM_FORMAT_U8: 114 case SNDRV_PCM_FORMAT_S8: 115 rtd->xfer_resolution = 0x0; 116 break; 117 case SNDRV_PCM_FORMAT_S16_LE: 118 rtd->xfer_resolution = 0x02; 119 break; 120 case SNDRV_PCM_FORMAT_S24_LE: 121 rtd->xfer_resolution = 0x04; 122 break; 123 case SNDRV_PCM_FORMAT_S32_LE: 124 rtd->xfer_resolution = 0x05; 125 break; 126 default: 127 return -EINVAL; 128 } 129 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 130 switch (rtd->i2s_instance) { 131 case I2S_HS_INSTANCE: 132 reg_val = ACP_HSTDM_ITER; 133 frmt_reg = ACP_HSTDM_TXFRMT; 134 break; 135 case I2S_SP_INSTANCE: 136 default: 137 reg_val = ACP_I2STDM_ITER; 138 frmt_reg = ACP_I2STDM_TXFRMT; 139 } 140 } else { 141 switch (rtd->i2s_instance) { 142 case I2S_HS_INSTANCE: 143 reg_val = ACP_HSTDM_IRER; 144 frmt_reg = ACP_HSTDM_RXFRMT; 145 break; 146 case I2S_SP_INSTANCE: 147 default: 148 reg_val = ACP_I2STDM_IRER; 149 frmt_reg = ACP_I2STDM_RXFRMT; 150 } 151 } 152 if (adata->tdm_mode) { 153 val = acp_readl(rtd->acp5x_base + reg_val); 154 acp_writel(val | 0x2, rtd->acp5x_base + reg_val); 155 acp_writel(adata->tdm_fmt, rtd->acp5x_base + frmt_reg); 156 } 157 val = acp_readl(rtd->acp5x_base + reg_val); 158 val &= ~ACP5x_ITER_IRER_SAMP_LEN_MASK; 159 val = val | (rtd->xfer_resolution << 3); 160 acp_writel(val, rtd->acp5x_base + reg_val); 161 162 if (adata->master_mode) { 163 switch (rtd->i2s_instance) { 164 case I2S_HS_INSTANCE: 165 master_reg = ACP_I2STDM2_MSTRCLKGEN; 166 break; 167 case I2S_SP_INSTANCE: 168 default: 169 master_reg = ACP_I2STDM0_MSTRCLKGEN; 170 break; 171 } 172 mclkgen.bits.i2stdm_master_mode = 0x1; 173 if (adata->tdm_mode) 174 mclkgen.bits.i2stdm_format_mode = 0x01; 175 else 176 mclkgen.bits.i2stdm_format_mode = 0x0; 177 switch (params_format(params)) { 178 case SNDRV_PCM_FORMAT_S16_LE: 179 switch (params_rate(params)) { 180 case 8000: 181 bclk_div_val = 768; 182 break; 183 case 16000: 184 bclk_div_val = 384; 185 break; 186 case 24000: 187 bclk_div_val = 256; 188 break; 189 case 32000: 190 bclk_div_val = 192; 191 break; 192 case 44100: 193 case 48000: 194 bclk_div_val = 128; 195 break; 196 case 88200: 197 case 96000: 198 bclk_div_val = 64; 199 break; 200 case 192000: 201 bclk_div_val = 32; 202 break; 203 default: 204 return -EINVAL; 205 } 206 lrclk_div_val = 32; 207 break; 208 case SNDRV_PCM_FORMAT_S32_LE: 209 switch (params_rate(params)) { 210 case 8000: 211 bclk_div_val = 384; 212 break; 213 case 16000: 214 bclk_div_val = 192; 215 break; 216 case 24000: 217 bclk_div_val = 128; 218 break; 219 case 32000: 220 bclk_div_val = 96; 221 break; 222 case 44100: 223 case 48000: 224 bclk_div_val = 64; 225 break; 226 case 88200: 227 case 96000: 228 bclk_div_val = 32; 229 break; 230 case 192000: 231 bclk_div_val = 16; 232 break; 233 default: 234 return -EINVAL; 235 } 236 lrclk_div_val = 64; 237 break; 238 default: 239 return -EINVAL; 240 } 241 mclkgen.bits.i2stdm_bclk_div_val = bclk_div_val; 242 mclkgen.bits.i2stdm_lrclk_div_val = lrclk_div_val; 243 acp_writel(mclkgen.u32_all, rtd->acp5x_base + master_reg); 244 } 245 return 0; 246 } 247 248 static int acp5x_i2s_trigger(struct snd_pcm_substream *substream, 249 int cmd, struct snd_soc_dai *dai) 250 { 251 struct i2s_stream_instance *rtd; 252 u32 ret, val, period_bytes, reg_val, ier_val, water_val; 253 u32 buf_size, buf_reg; 254 255 rtd = substream->runtime->private_data; 256 period_bytes = frames_to_bytes(substream->runtime, 257 substream->runtime->period_size); 258 buf_size = frames_to_bytes(substream->runtime, 259 substream->runtime->buffer_size); 260 switch (cmd) { 261 case SNDRV_PCM_TRIGGER_START: 262 case SNDRV_PCM_TRIGGER_RESUME: 263 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 264 rtd->bytescount = acp_get_byte_count(rtd, 265 substream->stream); 266 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 267 switch (rtd->i2s_instance) { 268 case I2S_HS_INSTANCE: 269 water_val = 270 ACP_HS_TX_INTR_WATERMARK_SIZE; 271 reg_val = ACP_HSTDM_ITER; 272 ier_val = ACP_HSTDM_IER; 273 buf_reg = ACP_HS_TX_RINGBUFSIZE; 274 break; 275 case I2S_SP_INSTANCE: 276 default: 277 water_val = 278 ACP_I2S_TX_INTR_WATERMARK_SIZE; 279 reg_val = ACP_I2STDM_ITER; 280 ier_val = ACP_I2STDM_IER; 281 buf_reg = ACP_I2S_TX_RINGBUFSIZE; 282 } 283 } else { 284 switch (rtd->i2s_instance) { 285 case I2S_HS_INSTANCE: 286 water_val = 287 ACP_HS_RX_INTR_WATERMARK_SIZE; 288 reg_val = ACP_HSTDM_IRER; 289 ier_val = ACP_HSTDM_IER; 290 buf_reg = ACP_HS_RX_RINGBUFSIZE; 291 break; 292 case I2S_SP_INSTANCE: 293 default: 294 water_val = 295 ACP_I2S_RX_INTR_WATERMARK_SIZE; 296 reg_val = ACP_I2STDM_IRER; 297 ier_val = ACP_I2STDM_IER; 298 buf_reg = ACP_I2S_RX_RINGBUFSIZE; 299 } 300 } 301 acp_writel(period_bytes, rtd->acp5x_base + water_val); 302 acp_writel(buf_size, rtd->acp5x_base + buf_reg); 303 val = acp_readl(rtd->acp5x_base + reg_val); 304 val = val | BIT(0); 305 acp_writel(val, rtd->acp5x_base + reg_val); 306 acp_writel(1, rtd->acp5x_base + ier_val); 307 ret = 0; 308 break; 309 case SNDRV_PCM_TRIGGER_STOP: 310 case SNDRV_PCM_TRIGGER_SUSPEND: 311 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 312 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 313 switch (rtd->i2s_instance) { 314 case I2S_HS_INSTANCE: 315 reg_val = ACP_HSTDM_ITER; 316 break; 317 case I2S_SP_INSTANCE: 318 default: 319 reg_val = ACP_I2STDM_ITER; 320 } 321 322 } else { 323 switch (rtd->i2s_instance) { 324 case I2S_HS_INSTANCE: 325 reg_val = ACP_HSTDM_IRER; 326 break; 327 case I2S_SP_INSTANCE: 328 default: 329 reg_val = ACP_I2STDM_IRER; 330 } 331 } 332 val = acp_readl(rtd->acp5x_base + reg_val); 333 val = val & ~BIT(0); 334 acp_writel(val, rtd->acp5x_base + reg_val); 335 336 if (!(acp_readl(rtd->acp5x_base + ACP_HSTDM_ITER) & BIT(0)) && 337 !(acp_readl(rtd->acp5x_base + ACP_HSTDM_IRER) & BIT(0))) 338 acp_writel(0, rtd->acp5x_base + ACP_HSTDM_IER); 339 if (!(acp_readl(rtd->acp5x_base + ACP_I2STDM_ITER) & BIT(0)) && 340 !(acp_readl(rtd->acp5x_base + ACP_I2STDM_IRER) & BIT(0))) 341 acp_writel(0, rtd->acp5x_base + ACP_I2STDM_IER); 342 ret = 0; 343 break; 344 default: 345 ret = -EINVAL; 346 break; 347 } 348 return ret; 349 } 350 351 static const struct snd_soc_dai_ops acp5x_i2s_dai_ops = { 352 .hw_params = acp5x_i2s_hwparams, 353 .trigger = acp5x_i2s_trigger, 354 .set_fmt = acp5x_i2s_set_fmt, 355 .set_tdm_slot = acp5x_i2s_set_tdm_slot, 356 }; 357 358 static const struct snd_soc_component_driver acp5x_dai_component = { 359 .name = "acp5x-i2s", 360 }; 361 362 static struct snd_soc_dai_driver acp5x_i2s_dai = { 363 .playback = { 364 .rates = SNDRV_PCM_RATE_8000_96000, 365 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 366 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 367 .channels_min = 2, 368 .channels_max = 2, 369 .rate_min = 8000, 370 .rate_max = 96000, 371 }, 372 .capture = { 373 .rates = SNDRV_PCM_RATE_8000_96000, 374 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 375 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 376 .channels_min = 2, 377 .channels_max = 2, 378 .rate_min = 8000, 379 .rate_max = 96000, 380 }, 381 .ops = &acp5x_i2s_dai_ops, 382 }; 383 384 static int acp5x_dai_probe(struct platform_device *pdev) 385 { 386 struct resource *res; 387 struct i2s_dev_data *adata; 388 int ret; 389 390 adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data), 391 GFP_KERNEL); 392 if (!adata) 393 return -ENOMEM; 394 395 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 396 if (!res) { 397 dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); 398 return -ENOMEM; 399 } 400 adata->acp5x_base = devm_ioremap(&pdev->dev, res->start, 401 resource_size(res)); 402 if (!adata->acp5x_base) 403 return -ENOMEM; 404 405 adata->master_mode = I2S_MASTER_MODE_ENABLE; 406 dev_set_drvdata(&pdev->dev, adata); 407 ret = devm_snd_soc_register_component(&pdev->dev, 408 &acp5x_dai_component, 409 &acp5x_i2s_dai, 1); 410 if (ret) 411 dev_err(&pdev->dev, "Fail to register acp i2s dai\n"); 412 return ret; 413 } 414 415 static struct platform_driver acp5x_dai_driver = { 416 .probe = acp5x_dai_probe, 417 .driver = { 418 .name = "acp5x_i2s_playcap", 419 }, 420 }; 421 422 module_platform_driver(acp5x_dai_driver); 423 424 MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); 425 MODULE_DESCRIPTION("AMD ACP5.x CPU DAI Driver"); 426 MODULE_ALIAS("platform:" DRV_NAME); 427 MODULE_LICENSE("GPL v2"); 428