1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * omap-dmic.c -- OMAP ASoC DMIC DAI driver 4 * 5 * Copyright (C) 2010 - 2011 Texas Instruments 6 * 7 * Author: David Lambert <dlambert@ti.com> 8 * Misael Lopez Cruz <misael.lopez@ti.com> 9 * Liam Girdwood <lrg@ti.com> 10 * Peter Ujfalusi <peter.ujfalusi@ti.com> 11 */ 12 13 #include <linux/init.h> 14 #include <linux/mod_devicetable.h> 15 #include <linux/module.h> 16 #include <linux/platform_device.h> 17 #include <linux/err.h> 18 #include <linux/clk.h> 19 #include <linux/io.h> 20 #include <linux/slab.h> 21 #include <linux/pm_runtime.h> 22 23 #include <sound/core.h> 24 #include <sound/pcm.h> 25 #include <sound/pcm_params.h> 26 #include <sound/initval.h> 27 #include <sound/soc.h> 28 #include <sound/dmaengine_pcm.h> 29 30 #include "omap-dmic.h" 31 #include "sdma-pcm.h" 32 33 struct omap_dmic { 34 struct device *dev; 35 void __iomem *io_base; 36 struct clk *fclk; 37 struct pm_qos_request pm_qos_req; 38 int latency; 39 int fclk_freq; 40 int out_freq; 41 int clk_div; 42 int sysclk; 43 int threshold; 44 u32 ch_enabled; 45 bool active; 46 struct mutex mutex; 47 48 struct snd_dmaengine_dai_dma_data dma_data; 49 }; 50 51 static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val) 52 { 53 writel_relaxed(val, dmic->io_base + reg); 54 } 55 56 static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg) 57 { 58 return readl_relaxed(dmic->io_base + reg); 59 } 60 61 static inline void omap_dmic_start(struct omap_dmic *dmic) 62 { 63 u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG); 64 65 /* Configure DMA controller */ 66 omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_SET_REG, 67 OMAP_DMIC_DMA_ENABLE); 68 69 omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl | dmic->ch_enabled); 70 } 71 72 static inline void omap_dmic_stop(struct omap_dmic *dmic) 73 { 74 u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG); 75 omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, 76 ctrl & ~OMAP_DMIC_UP_ENABLE_MASK); 77 78 /* Disable DMA request generation */ 79 omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_CLR_REG, 80 OMAP_DMIC_DMA_ENABLE); 81 82 } 83 84 static inline int dmic_is_enabled(struct omap_dmic *dmic) 85 { 86 return omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG) & 87 OMAP_DMIC_UP_ENABLE_MASK; 88 } 89 90 static int omap_dmic_dai_startup(struct snd_pcm_substream *substream, 91 struct snd_soc_dai *dai) 92 { 93 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); 94 95 guard(mutex)(&dmic->mutex); 96 97 if (snd_soc_dai_active(dai)) 98 return -EBUSY; 99 100 dmic->active = 1; 101 return 0; 102 } 103 104 static void omap_dmic_dai_shutdown(struct snd_pcm_substream *substream, 105 struct snd_soc_dai *dai) 106 { 107 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); 108 109 guard(mutex)(&dmic->mutex); 110 111 cpu_latency_qos_remove_request(&dmic->pm_qos_req); 112 113 if (!snd_soc_dai_active(dai)) 114 dmic->active = 0; 115 } 116 117 static int omap_dmic_select_divider(struct omap_dmic *dmic, int sample_rate) 118 { 119 int divider = -EINVAL; 120 121 /* 122 * 192KHz rate is only supported with 19.2MHz/3.84MHz clock 123 * configuration. 124 */ 125 if (sample_rate == 192000) { 126 if (dmic->fclk_freq == 19200000 && dmic->out_freq == 3840000) 127 divider = 0x6; /* Divider: 5 (192KHz sampling rate) */ 128 else 129 dev_err(dmic->dev, 130 "invalid clock configuration for 192KHz\n"); 131 132 return divider; 133 } 134 135 switch (dmic->out_freq) { 136 case 1536000: 137 if (dmic->fclk_freq != 24576000) 138 goto div_err; 139 divider = 0x4; /* Divider: 16 */ 140 break; 141 case 2400000: 142 switch (dmic->fclk_freq) { 143 case 12000000: 144 divider = 0x5; /* Divider: 5 */ 145 break; 146 case 19200000: 147 divider = 0x0; /* Divider: 8 */ 148 break; 149 case 24000000: 150 divider = 0x2; /* Divider: 10 */ 151 break; 152 default: 153 goto div_err; 154 } 155 break; 156 case 3072000: 157 if (dmic->fclk_freq != 24576000) 158 goto div_err; 159 divider = 0x3; /* Divider: 8 */ 160 break; 161 case 3840000: 162 if (dmic->fclk_freq != 19200000) 163 goto div_err; 164 divider = 0x1; /* Divider: 5 (96KHz sampling rate) */ 165 break; 166 default: 167 dev_err(dmic->dev, "invalid out frequency: %dHz\n", 168 dmic->out_freq); 169 break; 170 } 171 172 return divider; 173 174 div_err: 175 dev_err(dmic->dev, "invalid out frequency %dHz for %dHz input\n", 176 dmic->out_freq, dmic->fclk_freq); 177 return -EINVAL; 178 } 179 180 static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream, 181 struct snd_pcm_hw_params *params, 182 struct snd_soc_dai *dai) 183 { 184 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); 185 struct snd_dmaengine_dai_dma_data *dma_data; 186 int channels; 187 188 dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params)); 189 if (dmic->clk_div < 0) { 190 dev_err(dmic->dev, "no valid divider for %dHz from %dHz\n", 191 dmic->out_freq, dmic->fclk_freq); 192 return -EINVAL; 193 } 194 195 dmic->ch_enabled = 0; 196 channels = params_channels(params); 197 switch (channels) { 198 case 6: 199 dmic->ch_enabled |= OMAP_DMIC_UP3_ENABLE; 200 fallthrough; 201 case 4: 202 dmic->ch_enabled |= OMAP_DMIC_UP2_ENABLE; 203 fallthrough; 204 case 2: 205 dmic->ch_enabled |= OMAP_DMIC_UP1_ENABLE; 206 break; 207 default: 208 dev_err(dmic->dev, "invalid number of legacy channels\n"); 209 return -EINVAL; 210 } 211 212 /* packet size is threshold * channels */ 213 dma_data = snd_soc_dai_get_dma_data(dai, substream); 214 dma_data->maxburst = dmic->threshold * channels; 215 dmic->latency = (OMAP_DMIC_THRES_MAX - dmic->threshold) * USEC_PER_SEC / 216 params_rate(params); 217 218 return 0; 219 } 220 221 static int omap_dmic_dai_prepare(struct snd_pcm_substream *substream, 222 struct snd_soc_dai *dai) 223 { 224 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); 225 u32 ctrl; 226 227 if (cpu_latency_qos_request_active(&dmic->pm_qos_req)) 228 cpu_latency_qos_update_request(&dmic->pm_qos_req, 229 dmic->latency); 230 231 /* Configure uplink threshold */ 232 omap_dmic_write(dmic, OMAP_DMIC_FIFO_CTRL_REG, dmic->threshold); 233 234 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG); 235 236 /* Set dmic out format */ 237 ctrl &= ~(OMAP_DMIC_FORMAT | OMAP_DMIC_POLAR_MASK); 238 ctrl |= (OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 | 239 OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3); 240 241 /* Configure dmic clock divider */ 242 ctrl &= ~OMAP_DMIC_CLK_DIV_MASK; 243 ctrl |= OMAP_DMIC_CLK_DIV(dmic->clk_div); 244 245 omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl); 246 247 omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, 248 ctrl | OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 | 249 OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3); 250 251 return 0; 252 } 253 254 static int omap_dmic_dai_trigger(struct snd_pcm_substream *substream, 255 int cmd, struct snd_soc_dai *dai) 256 { 257 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); 258 259 switch (cmd) { 260 case SNDRV_PCM_TRIGGER_START: 261 omap_dmic_start(dmic); 262 break; 263 case SNDRV_PCM_TRIGGER_STOP: 264 omap_dmic_stop(dmic); 265 break; 266 default: 267 break; 268 } 269 270 return 0; 271 } 272 273 static int omap_dmic_select_fclk(struct omap_dmic *dmic, int clk_id, 274 unsigned int freq) 275 { 276 struct clk *parent_clk, *mux; 277 char *parent_clk_name; 278 int ret = 0; 279 280 switch (freq) { 281 case 12000000: 282 case 19200000: 283 case 24000000: 284 case 24576000: 285 break; 286 default: 287 dev_err(dmic->dev, "invalid input frequency: %dHz\n", freq); 288 dmic->fclk_freq = 0; 289 return -EINVAL; 290 } 291 292 if (dmic->sysclk == clk_id) { 293 dmic->fclk_freq = freq; 294 return 0; 295 } 296 297 /* re-parent not allowed if a stream is ongoing */ 298 if (dmic->active && dmic_is_enabled(dmic)) { 299 dev_err(dmic->dev, "can't re-parent when DMIC active\n"); 300 return -EBUSY; 301 } 302 303 switch (clk_id) { 304 case OMAP_DMIC_SYSCLK_PAD_CLKS: 305 parent_clk_name = "pad_clks_ck"; 306 break; 307 case OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS: 308 parent_clk_name = "slimbus_clk"; 309 break; 310 case OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS: 311 parent_clk_name = "dmic_sync_mux_ck"; 312 break; 313 default: 314 dev_err(dmic->dev, "fclk clk_id (%d) not supported\n", clk_id); 315 return -EINVAL; 316 } 317 318 parent_clk = clk_get(dmic->dev, parent_clk_name); 319 if (IS_ERR(parent_clk)) { 320 dev_err(dmic->dev, "can't get %s\n", parent_clk_name); 321 return -ENODEV; 322 } 323 324 mux = clk_get_parent(dmic->fclk); 325 if (!mux) { 326 dev_err(dmic->dev, "can't get fck mux parent\n"); 327 clk_put(parent_clk); 328 return -ENODEV; 329 } 330 331 scoped_guard(mutex, &dmic->mutex) { 332 if (dmic->active) { 333 /* disable clock while reparenting */ 334 pm_runtime_put_sync(dmic->dev); 335 ret = clk_set_parent(mux, parent_clk); 336 pm_runtime_get_sync(dmic->dev); 337 } else { 338 ret = clk_set_parent(mux, parent_clk); 339 } 340 } 341 342 if (ret < 0) { 343 dev_err(dmic->dev, "re-parent failed\n"); 344 } else { 345 dmic->sysclk = clk_id; 346 dmic->fclk_freq = freq; 347 } 348 349 clk_put(mux); 350 clk_put(parent_clk); 351 352 return ret; 353 } 354 355 static int omap_dmic_select_outclk(struct omap_dmic *dmic, int clk_id, 356 unsigned int freq) 357 { 358 int ret = 0; 359 360 if (clk_id != OMAP_DMIC_ABE_DMIC_CLK) { 361 dev_err(dmic->dev, "output clk_id (%d) not supported\n", 362 clk_id); 363 return -EINVAL; 364 } 365 366 switch (freq) { 367 case 1536000: 368 case 2400000: 369 case 3072000: 370 case 3840000: 371 dmic->out_freq = freq; 372 break; 373 default: 374 dev_err(dmic->dev, "invalid out frequency: %dHz\n", freq); 375 dmic->out_freq = 0; 376 ret = -EINVAL; 377 } 378 379 return ret; 380 } 381 382 static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, 383 unsigned int freq, int dir) 384 { 385 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); 386 387 if (dir == SND_SOC_CLOCK_IN) 388 return omap_dmic_select_fclk(dmic, clk_id, freq); 389 else if (dir == SND_SOC_CLOCK_OUT) 390 return omap_dmic_select_outclk(dmic, clk_id, freq); 391 392 dev_err(dmic->dev, "invalid clock direction (%d)\n", dir); 393 return -EINVAL; 394 } 395 396 static int omap_dmic_probe(struct snd_soc_dai *dai) 397 { 398 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); 399 400 pm_runtime_enable(dmic->dev); 401 402 /* Disable lines while request is ongoing */ 403 pm_runtime_get_sync(dmic->dev); 404 omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, 0x00); 405 pm_runtime_put_sync(dmic->dev); 406 407 /* Configure DMIC threshold value */ 408 dmic->threshold = OMAP_DMIC_THRES_MAX - 3; 409 410 snd_soc_dai_init_dma_data(dai, NULL, &dmic->dma_data); 411 412 return 0; 413 } 414 415 static int omap_dmic_remove(struct snd_soc_dai *dai) 416 { 417 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); 418 419 pm_runtime_disable(dmic->dev); 420 421 return 0; 422 } 423 424 static const struct snd_soc_dai_ops omap_dmic_dai_ops = { 425 .probe = omap_dmic_probe, 426 .remove = omap_dmic_remove, 427 .startup = omap_dmic_dai_startup, 428 .shutdown = omap_dmic_dai_shutdown, 429 .hw_params = omap_dmic_dai_hw_params, 430 .prepare = omap_dmic_dai_prepare, 431 .trigger = omap_dmic_dai_trigger, 432 .set_sysclk = omap_dmic_set_dai_sysclk, 433 }; 434 435 static struct snd_soc_dai_driver omap_dmic_dai = { 436 .name = "omap-dmic", 437 .capture = { 438 .channels_min = 2, 439 .channels_max = 6, 440 .rates = SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000, 441 .formats = SNDRV_PCM_FMTBIT_S32_LE, 442 .sig_bits = 24, 443 }, 444 .ops = &omap_dmic_dai_ops, 445 }; 446 447 static const struct snd_soc_component_driver omap_dmic_component = { 448 .name = "omap-dmic", 449 .legacy_dai_naming = 1, 450 }; 451 452 static int asoc_dmic_probe(struct platform_device *pdev) 453 { 454 struct omap_dmic *dmic; 455 struct resource *res; 456 int ret; 457 458 dmic = devm_kzalloc(&pdev->dev, sizeof(struct omap_dmic), GFP_KERNEL); 459 if (!dmic) 460 return -ENOMEM; 461 462 platform_set_drvdata(pdev, dmic); 463 dmic->dev = &pdev->dev; 464 dmic->sysclk = OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS; 465 466 mutex_init(&dmic->mutex); 467 468 dmic->fclk = devm_clk_get(dmic->dev, "fck"); 469 if (IS_ERR(dmic->fclk)) { 470 dev_err(dmic->dev, "can't get fck\n"); 471 return -ENODEV; 472 } 473 474 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); 475 if (!res) { 476 dev_err(dmic->dev, "invalid dma memory resource\n"); 477 return -ENODEV; 478 } 479 dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG; 480 481 dmic->dma_data.filter_data = "up_link"; 482 483 dmic->io_base = devm_platform_ioremap_resource_byname(pdev, "mpu"); 484 if (IS_ERR(dmic->io_base)) 485 return PTR_ERR(dmic->io_base); 486 487 ret = devm_snd_soc_register_component(&pdev->dev, 488 &omap_dmic_component, 489 &omap_dmic_dai, 1); 490 if (ret) 491 return ret; 492 493 ret = sdma_pcm_platform_register(&pdev->dev, NULL, "up_link"); 494 if (ret) 495 return ret; 496 497 return 0; 498 } 499 500 static const struct of_device_id omap_dmic_of_match[] = { 501 { .compatible = "ti,omap4-dmic", }, 502 { } 503 }; 504 MODULE_DEVICE_TABLE(of, omap_dmic_of_match); 505 506 static struct platform_driver asoc_dmic_driver = { 507 .driver = { 508 .name = "omap-dmic", 509 .of_match_table = omap_dmic_of_match, 510 }, 511 .probe = asoc_dmic_probe, 512 }; 513 514 module_platform_driver(asoc_dmic_driver); 515 516 MODULE_ALIAS("platform:omap-dmic"); 517 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); 518 MODULE_DESCRIPTION("OMAP DMIC ASoC Interface"); 519 MODULE_LICENSE("GPL"); 520