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