1/* 2 * omap-mcbsp.c -- OMAP ALSA SoC DAI driver using McBSP port 3 * 4 * Copyright (C) 2008 Nokia Corporation 5 * 6 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> 7 * Peter Ujfalusi <peter.ujfalusi@ti.com> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * version 2 as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 * 02110-1301 USA 22 * 23 */ 24 25#include <linux/init.h> 26#include <linux/module.h> 27#include <linux/device.h> 28#include <linux/pm_runtime.h> 29#include <linux/of.h> 30#include <linux/of_device.h> 31#include <sound/core.h> 32#include <sound/pcm.h> 33#include <sound/pcm_params.h> 34#include <sound/initval.h> 35#include <sound/soc.h> 36#include <sound/dmaengine_pcm.h> 37#include <sound/omap-pcm.h> 38 39#include <linux/platform_data/asoc-ti-mcbsp.h> 40#include "mcbsp.h" 41#include "omap-mcbsp.h" 42 43#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) 44 45#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \ 46 xhandler_get, xhandler_put) \ 47{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 48 .info = omap_mcbsp_st_info_volsw, \ 49 .get = xhandler_get, .put = xhandler_put, \ 50 .private_value = (unsigned long) &(struct soc_mixer_control) \ 51 {.min = xmin, .max = xmax} } 52 53enum { 54 OMAP_MCBSP_WORD_8 = 0, 55 OMAP_MCBSP_WORD_12, 56 OMAP_MCBSP_WORD_16, 57 OMAP_MCBSP_WORD_20, 58 OMAP_MCBSP_WORD_24, 59 OMAP_MCBSP_WORD_32, 60}; 61 62/* 63 * Stream DMA parameters. DMA request line and port address are set runtime 64 * since they are different between OMAP1 and later OMAPs 65 */ 66static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream, 67 unsigned int packet_size) 68{ 69 struct snd_soc_pcm_runtime *rtd = substream->private_data; 70 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 71 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 72 int words; 73 74 /* 75 * Configure McBSP threshold based on either: 76 * packet_size, when the sDMA is in packet mode, or based on the 77 * period size in THRESHOLD mode, otherwise use McBSP threshold = 1 78 * for mono streams. 79 */ 80 if (packet_size) 81 words = packet_size; 82 else 83 words = 1; 84 85 /* Configure McBSP internal buffer usage */ 86 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 87 omap_mcbsp_set_tx_threshold(mcbsp, words); 88 else 89 omap_mcbsp_set_rx_threshold(mcbsp, words); 90} 91 92static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, 93 struct snd_pcm_hw_rule *rule) 94{ 95 struct snd_interval *buffer_size = hw_param_interval(params, 96 SNDRV_PCM_HW_PARAM_BUFFER_SIZE); 97 struct snd_interval *channels = hw_param_interval(params, 98 SNDRV_PCM_HW_PARAM_CHANNELS); 99 struct omap_mcbsp *mcbsp = rule->private; 100 struct snd_interval frames; 101 int size; 102 103 snd_interval_any(&frames); 104 size = mcbsp->pdata->buffer_size; 105 106 frames.min = size / channels->min; 107 frames.integer = 1; 108 return snd_interval_refine(buffer_size, &frames); 109} 110 111static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, 112 struct snd_soc_dai *cpu_dai) 113{ 114 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 115 int err = 0; 116 117 if (!cpu_dai->active) 118 err = omap_mcbsp_request(mcbsp); 119 120 /* 121 * OMAP3 McBSP FIFO is word structured. 122 * McBSP2 has 1024 + 256 = 1280 word long buffer, 123 * McBSP1,3,4,5 has 128 word long buffer 124 * This means that the size of the FIFO depends on the sample format. 125 * For example on McBSP3: 126 * 16bit samples: size is 128 * 2 = 256 bytes 127 * 32bit samples: size is 128 * 4 = 512 bytes 128 * It is simpler to place constraint for buffer and period based on 129 * channels. 130 * McBSP3 as example again (16 or 32 bit samples): 131 * 1 channel (mono): size is 128 frames (128 words) 132 * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words) 133 * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words) 134 */ 135 if (mcbsp->pdata->buffer_size) { 136 /* 137 * Rule for the buffer size. We should not allow 138 * smaller buffer than the FIFO size to avoid underruns. 139 * This applies only for the playback stream. 140 */ 141 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 142 snd_pcm_hw_rule_add(substream->runtime, 0, 143 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 144 omap_mcbsp_hwrule_min_buffersize, 145 mcbsp, 146 SNDRV_PCM_HW_PARAM_CHANNELS, -1); 147 148 /* Make sure, that the period size is always even */ 149 snd_pcm_hw_constraint_step(substream->runtime, 0, 150 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2); 151 } 152 153 return err; 154} 155 156static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, 157 struct snd_soc_dai *cpu_dai) 158{ 159 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 160 161 if (!cpu_dai->active) { 162 omap_mcbsp_free(mcbsp); 163 mcbsp->configured = 0; 164 } 165} 166 167static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, 168 struct snd_soc_dai *cpu_dai) 169{ 170 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 171 int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 172 173 switch (cmd) { 174 case SNDRV_PCM_TRIGGER_START: 175 case SNDRV_PCM_TRIGGER_RESUME: 176 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 177 mcbsp->active++; 178 omap_mcbsp_start(mcbsp, play, !play); 179 break; 180 181 case SNDRV_PCM_TRIGGER_STOP: 182 case SNDRV_PCM_TRIGGER_SUSPEND: 183 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 184 omap_mcbsp_stop(mcbsp, play, !play); 185 mcbsp->active--; 186 break; 187 default: 188 err = -EINVAL; 189 } 190 191 return err; 192} 193 194static snd_pcm_sframes_t omap_mcbsp_dai_delay( 195 struct snd_pcm_substream *substream, 196 struct snd_soc_dai *dai) 197{ 198 struct snd_soc_pcm_runtime *rtd = substream->private_data; 199 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 200 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 201 u16 fifo_use; 202 snd_pcm_sframes_t delay; 203 204 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 205 fifo_use = omap_mcbsp_get_tx_delay(mcbsp); 206 else 207 fifo_use = omap_mcbsp_get_rx_delay(mcbsp); 208 209 /* 210 * Divide the used locations with the channel count to get the 211 * FIFO usage in samples (don't care about partial samples in the 212 * buffer). 213 */ 214 delay = fifo_use / substream->runtime->channels; 215 216 return delay; 217} 218 219static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, 220 struct snd_pcm_hw_params *params, 221 struct snd_soc_dai *cpu_dai) 222{ 223 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 224 struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; 225 struct snd_dmaengine_dai_dma_data *dma_data; 226 int wlen, channels, wpf; 227 int pkt_size = 0; 228 unsigned int format, div, framesize, master; 229 230 dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream); 231 channels = params_channels(params); 232 233 switch (params_format(params)) { 234 case SNDRV_PCM_FORMAT_S16_LE: 235 wlen = 16; 236 break; 237 case SNDRV_PCM_FORMAT_S32_LE: 238 wlen = 32; 239 break; 240 default: 241 return -EINVAL; 242 } 243 if (mcbsp->pdata->buffer_size) { 244 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { 245 int period_words, max_thrsh; 246 int divider = 0; 247 248 period_words = params_period_bytes(params) / (wlen / 8); 249 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 250 max_thrsh = mcbsp->max_tx_thres; 251 else 252 max_thrsh = mcbsp->max_rx_thres; 253 /* 254 * Use sDMA packet mode if McBSP is in threshold mode: 255 * If period words less than the FIFO size the packet 256 * size is set to the number of period words, otherwise 257 * Look for the biggest threshold value which divides 258 * the period size evenly. 259 */ 260 divider = period_words / max_thrsh; 261 if (period_words % max_thrsh) 262 divider++; 263 while (period_words % divider && 264 divider < period_words) 265 divider++; 266 if (divider == period_words) 267 return -EINVAL; 268 269 pkt_size = period_words / divider; 270 } else if (channels > 1) { 271 /* Use packet mode for non mono streams */ 272 pkt_size = channels; 273 } 274 omap_mcbsp_set_threshold(substream, pkt_size); 275 } 276 277 dma_data->maxburst = pkt_size; 278 279 if (mcbsp->configured) { 280 /* McBSP already configured by another stream */ 281 return 0; 282 } 283 284 regs->rcr2 &= ~(RPHASE | RFRLEN2(0x7f) | RWDLEN2(7)); 285 regs->xcr2 &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7)); 286 regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7)); 287 regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7)); 288 format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK; 289 wpf = channels; 290 if (channels == 2 && (format == SND_SOC_DAIFMT_I2S || 291 format == SND_SOC_DAIFMT_LEFT_J)) { 292 /* Use dual-phase frames */ 293 regs->rcr2 |= RPHASE; 294 regs->xcr2 |= XPHASE; 295 /* Set 1 word per (McBSP) frame for phase1 and phase2 */ 296 wpf--; 297 regs->rcr2 |= RFRLEN2(wpf - 1); 298 regs->xcr2 |= XFRLEN2(wpf - 1); 299 } 300 301 regs->rcr1 |= RFRLEN1(wpf - 1); 302 regs->xcr1 |= XFRLEN1(wpf - 1); 303 304 switch (params_format(params)) { 305 case SNDRV_PCM_FORMAT_S16_LE: 306 /* Set word lengths */ 307 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); 308 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); 309 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); 310 regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16); 311 break; 312 case SNDRV_PCM_FORMAT_S32_LE: 313 /* Set word lengths */ 314 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32); 315 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32); 316 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32); 317 regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_32); 318 break; 319 default: 320 /* Unsupported PCM format */ 321 return -EINVAL; 322 } 323 324 /* In McBSP master modes, FRAME (i.e. sample rate) is generated 325 * by _counting_ BCLKs. Calculate frame size in BCLKs */ 326 master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK; 327 if (master == SND_SOC_DAIFMT_CBS_CFS) { 328 div = mcbsp->clk_div ? mcbsp->clk_div : 1; 329 framesize = (mcbsp->in_freq / div) / params_rate(params); 330 331 if (framesize < wlen * channels) { 332 printk(KERN_ERR "%s: not enough bandwidth for desired rate and " 333 "channels\n", __func__); 334 return -EINVAL; 335 } 336 } else 337 framesize = wlen * channels; 338 339 /* Set FS period and length in terms of bit clock periods */ 340 regs->srgr2 &= ~FPER(0xfff); 341 regs->srgr1 &= ~FWID(0xff); 342 switch (format) { 343 case SND_SOC_DAIFMT_I2S: 344 case SND_SOC_DAIFMT_LEFT_J: 345 regs->srgr2 |= FPER(framesize - 1); 346 regs->srgr1 |= FWID((framesize >> 1) - 1); 347 break; 348 case SND_SOC_DAIFMT_DSP_A: 349 case SND_SOC_DAIFMT_DSP_B: 350 regs->srgr2 |= FPER(framesize - 1); 351 regs->srgr1 |= FWID(0); 352 break; 353 } 354 355 omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs); 356 mcbsp->wlen = wlen; 357 mcbsp->configured = 1; 358 359 return 0; 360} 361 362/* 363 * This must be called before _set_clkdiv and _set_sysclk since McBSP register 364 * cache is initialized here 365 */ 366static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, 367 unsigned int fmt) 368{ 369 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 370 struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; 371 bool inv_fs = false; 372 373 if (mcbsp->configured) 374 return 0; 375 376 mcbsp->fmt = fmt; 377 memset(regs, 0, sizeof(*regs)); 378 /* Generic McBSP register settings */ 379 regs->spcr2 |= XINTM(3) | FREE; 380 regs->spcr1 |= RINTM(3); 381 /* RFIG and XFIG are not defined in 2430 and on OMAP3+ */ 382 if (!mcbsp->pdata->has_ccr) { 383 regs->rcr2 |= RFIG; 384 regs->xcr2 |= XFIG; 385 } 386 387 /* Configure XCCR/RCCR only for revisions which have ccr registers */ 388 if (mcbsp->pdata->has_ccr) { 389 regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE; 390 regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE; 391 } 392 393 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 394 case SND_SOC_DAIFMT_I2S: 395 /* 1-bit data delay */ 396 regs->rcr2 |= RDATDLY(1); 397 regs->xcr2 |= XDATDLY(1); 398 break; 399 case SND_SOC_DAIFMT_LEFT_J: 400 /* 0-bit data delay */ 401 regs->rcr2 |= RDATDLY(0); 402 regs->xcr2 |= XDATDLY(0); 403 regs->spcr1 |= RJUST(2); 404 /* Invert FS polarity configuration */ 405 inv_fs = true; 406 break; 407 case SND_SOC_DAIFMT_DSP_A: 408 /* 1-bit data delay */ 409 regs->rcr2 |= RDATDLY(1); 410 regs->xcr2 |= XDATDLY(1); 411 /* Invert FS polarity configuration */ 412 inv_fs = true; 413 break; 414 case SND_SOC_DAIFMT_DSP_B: 415 /* 0-bit data delay */ 416 regs->rcr2 |= RDATDLY(0); 417 regs->xcr2 |= XDATDLY(0); 418 /* Invert FS polarity configuration */ 419 inv_fs = true; 420 break; 421 default: 422 /* Unsupported data format */ 423 return -EINVAL; 424 } 425 426 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 427 case SND_SOC_DAIFMT_CBS_CFS: 428 /* McBSP master. Set FS and bit clocks as outputs */ 429 regs->pcr0 |= FSXM | FSRM | 430 CLKXM | CLKRM; 431 /* Sample rate generator drives the FS */ 432 regs->srgr2 |= FSGM; 433 break; 434 case SND_SOC_DAIFMT_CBM_CFS: 435 /* McBSP slave. FS clock as output */ 436 regs->srgr2 |= FSGM; 437 regs->pcr0 |= FSXM | FSRM; 438 break; 439 case SND_SOC_DAIFMT_CBM_CFM: 440 /* McBSP slave */ 441 break; 442 default: 443 /* Unsupported master/slave configuration */ 444 return -EINVAL; 445 } 446 447 /* Set bit clock (CLKX/CLKR) and FS polarities */ 448 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 449 case SND_SOC_DAIFMT_NB_NF: 450 /* 451 * Normal BCLK + FS. 452 * FS active low. TX data driven on falling edge of bit clock 453 * and RX data sampled on rising edge of bit clock. 454 */ 455 regs->pcr0 |= FSXP | FSRP | 456 CLKXP | CLKRP; 457 break; 458 case SND_SOC_DAIFMT_NB_IF: 459 regs->pcr0 |= CLKXP | CLKRP; 460 break; 461 case SND_SOC_DAIFMT_IB_NF: 462 regs->pcr0 |= FSXP | FSRP; 463 break; 464 case SND_SOC_DAIFMT_IB_IF: 465 break; 466 default: 467 return -EINVAL; 468 } 469 if (inv_fs == true) 470 regs->pcr0 ^= FSXP | FSRP; 471 472 return 0; 473} 474 475static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, 476 int div_id, int div) 477{ 478 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 479 struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; 480 481 if (div_id != OMAP_MCBSP_CLKGDV) 482 return -ENODEV; 483 484 mcbsp->clk_div = div; 485 regs->srgr1 &= ~CLKGDV(0xff); 486 regs->srgr1 |= CLKGDV(div - 1); 487 488 return 0; 489} 490 491static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, 492 int clk_id, unsigned int freq, 493 int dir) 494{ 495 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 496 struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; 497 int err = 0; 498 499 if (mcbsp->active) { 500 if (freq == mcbsp->in_freq) 501 return 0; 502 else 503 return -EBUSY; 504 } 505 506 mcbsp->in_freq = freq; 507 regs->srgr2 &= ~CLKSM; 508 regs->pcr0 &= ~SCLKME; 509 510 switch (clk_id) { 511 case OMAP_MCBSP_SYSCLK_CLK: 512 regs->srgr2 |= CLKSM; 513 break; 514 case OMAP_MCBSP_SYSCLK_CLKS_FCLK: 515 if (mcbsp_omap1()) { 516 err = -EINVAL; 517 break; 518 } 519 err = omap2_mcbsp_set_clks_src(mcbsp, 520 MCBSP_CLKS_PRCM_SRC); 521 break; 522 case OMAP_MCBSP_SYSCLK_CLKS_EXT: 523 if (mcbsp_omap1()) { 524 err = 0; 525 break; 526 } 527 err = omap2_mcbsp_set_clks_src(mcbsp, 528 MCBSP_CLKS_PAD_SRC); 529 break; 530 531 case OMAP_MCBSP_SYSCLK_CLKX_EXT: 532 regs->srgr2 |= CLKSM; 533 regs->pcr0 |= SCLKME; 534 /* 535 * If McBSP is master but yet the CLKX/CLKR pin drives the SRG, 536 * disable output on those pins. This enables to inject the 537 * reference clock through CLKX/CLKR. For this to work 538 * set_dai_sysclk() _needs_ to be called after set_dai_fmt(). 539 */ 540 regs->pcr0 &= ~CLKXM; 541 break; 542 case OMAP_MCBSP_SYSCLK_CLKR_EXT: 543 regs->pcr0 |= SCLKME; 544 /* Disable ouput on CLKR pin in master mode */ 545 regs->pcr0 &= ~CLKRM; 546 break; 547 default: 548 err = -ENODEV; 549 } 550 551 return err; 552} 553 554static const struct snd_soc_dai_ops mcbsp_dai_ops = { 555 .startup = omap_mcbsp_dai_startup, 556 .shutdown = omap_mcbsp_dai_shutdown, 557 .trigger = omap_mcbsp_dai_trigger, 558 .delay = omap_mcbsp_dai_delay, 559 .hw_params = omap_mcbsp_dai_hw_params, 560 .set_fmt = omap_mcbsp_dai_set_dai_fmt, 561 .set_clkdiv = omap_mcbsp_dai_set_clkdiv, 562 .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, 563}; 564 565static int omap_mcbsp_probe(struct snd_soc_dai *dai) 566{ 567 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); 568 569 pm_runtime_enable(mcbsp->dev); 570 571 snd_soc_dai_init_dma_data(dai, 572 &mcbsp->dma_data[SNDRV_PCM_STREAM_PLAYBACK], 573 &mcbsp->dma_data[SNDRV_PCM_STREAM_CAPTURE]); 574 575 return 0; 576} 577 578static int omap_mcbsp_remove(struct snd_soc_dai *dai) 579{ 580 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); 581 582 pm_runtime_disable(mcbsp->dev); 583 584 return 0; 585} 586 587static struct snd_soc_dai_driver omap_mcbsp_dai = { 588 .probe = omap_mcbsp_probe, 589 .remove = omap_mcbsp_remove, 590 .playback = { 591 .channels_min = 1, 592 .channels_max = 16, 593 .rates = OMAP_MCBSP_RATES, 594 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, 595 }, 596 .capture = { 597 .channels_min = 1, 598 .channels_max = 16, 599 .rates = OMAP_MCBSP_RATES, 600 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, 601 }, 602 .ops = &mcbsp_dai_ops, 603}; 604 605static const struct snd_soc_component_driver omap_mcbsp_component = { 606 .name = "omap-mcbsp", 607}; 608 609static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, 610 struct snd_ctl_elem_info *uinfo) 611{ 612 struct soc_mixer_control *mc = 613 (struct soc_mixer_control *)kcontrol->private_value; 614 int max = mc->max; 615 int min = mc->min; 616 617 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 618 uinfo->count = 1; 619 uinfo->value.integer.min = min; 620 uinfo->value.integer.max = max; 621 return 0; 622} 623 624#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \ 625static int \ 626omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ 627 struct snd_ctl_elem_value *uc) \ 628{ \ 629 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ 630 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ 631 struct soc_mixer_control *mc = \ 632 (struct soc_mixer_control *)kc->private_value; \ 633 int max = mc->max; \ 634 int min = mc->min; \ 635 int val = uc->value.integer.value[0]; \ 636 \ 637 if (val < min || val > max) \ 638 return -EINVAL; \ 639 \ 640 /* OMAP McBSP implementation uses index values 0..4 */ \ 641 return omap_st_set_chgain(mcbsp, channel, val); \ 642} \ 643 \ 644static int \ 645omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \ 646 struct snd_ctl_elem_value *uc) \ 647{ \ 648 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ 649 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ 650 s16 chgain; \ 651 \ 652 if (omap_st_get_chgain(mcbsp, channel, &chgain)) \ 653 return -EAGAIN; \ 654 \ 655 uc->value.integer.value[0] = chgain; \ 656 return 0; \ 657} 658 659OMAP_MCBSP_ST_CHANNEL_VOLUME(0) 660OMAP_MCBSP_ST_CHANNEL_VOLUME(1) 661 662static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol, 663 struct snd_ctl_elem_value *ucontrol) 664{ 665 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 666 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 667 u8 value = ucontrol->value.integer.value[0]; 668 669 if (value == omap_st_is_enabled(mcbsp)) 670 return 0; 671 672 if (value) 673 omap_st_enable(mcbsp); 674 else 675 omap_st_disable(mcbsp); 676 677 return 1; 678} 679 680static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol, 681 struct snd_ctl_elem_value *ucontrol) 682{ 683 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 684 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 685 686 ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp); 687 return 0; 688} 689 690#define OMAP_MCBSP_ST_CONTROLS(port) \ 691static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \ 692SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \ 693 omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \ 694OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \ 695 -32768, 32767, \ 696 omap_mcbsp_get_st_ch0_volume, \ 697 omap_mcbsp_set_st_ch0_volume), \ 698OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \ 699 -32768, 32767, \ 700 omap_mcbsp_get_st_ch1_volume, \ 701 omap_mcbsp_set_st_ch1_volume), \ 702} 703 704OMAP_MCBSP_ST_CONTROLS(2); 705OMAP_MCBSP_ST_CONTROLS(3); 706 707int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id) 708{ 709 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 710 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 711 712 if (!mcbsp->st_data) { 713 dev_warn(mcbsp->dev, "No sidetone data for port\n"); 714 return 0; 715 } 716 717 switch (port_id) { 718 case 2: /* McBSP 2 */ 719 return snd_soc_add_dai_controls(cpu_dai, 720 omap_mcbsp2_st_controls, 721 ARRAY_SIZE(omap_mcbsp2_st_controls)); 722 case 3: /* McBSP 3 */ 723 return snd_soc_add_dai_controls(cpu_dai, 724 omap_mcbsp3_st_controls, 725 ARRAY_SIZE(omap_mcbsp3_st_controls)); 726 default: 727 dev_err(mcbsp->dev, "Port %d not supported\n", port_id); 728 break; 729 } 730 731 return -EINVAL; 732} 733EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls); 734 735static struct omap_mcbsp_platform_data omap2420_pdata = { 736 .reg_step = 4, 737 .reg_size = 2, 738}; 739 740static struct omap_mcbsp_platform_data omap2430_pdata = { 741 .reg_step = 4, 742 .reg_size = 4, 743 .has_ccr = true, 744}; 745 746static struct omap_mcbsp_platform_data omap3_pdata = { 747 .reg_step = 4, 748 .reg_size = 4, 749 .has_ccr = true, 750 .has_wakeup = true, 751}; 752 753static struct omap_mcbsp_platform_data omap4_pdata = { 754 .reg_step = 4, 755 .reg_size = 4, 756 .has_ccr = true, 757 .has_wakeup = true, 758}; 759 760static const struct of_device_id omap_mcbsp_of_match[] = { 761 { 762 .compatible = "ti,omap2420-mcbsp", 763 .data = &omap2420_pdata, 764 }, 765 { 766 .compatible = "ti,omap2430-mcbsp", 767 .data = &omap2430_pdata, 768 }, 769 { 770 .compatible = "ti,omap3-mcbsp", 771 .data = &omap3_pdata, 772 }, 773 { 774 .compatible = "ti,omap4-mcbsp", 775 .data = &omap4_pdata, 776 }, 777 { }, 778}; 779MODULE_DEVICE_TABLE(of, omap_mcbsp_of_match); 780 781static int asoc_mcbsp_probe(struct platform_device *pdev) 782{ 783 struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev); 784 struct omap_mcbsp *mcbsp; 785 const struct of_device_id *match; 786 int ret; 787 788 match = of_match_device(omap_mcbsp_of_match, &pdev->dev); 789 if (match) { 790 struct device_node *node = pdev->dev.of_node; 791 int buffer_size; 792 793 pdata = devm_kzalloc(&pdev->dev, 794 sizeof(struct omap_mcbsp_platform_data), 795 GFP_KERNEL); 796 if (!pdata) 797 return -ENOMEM; 798 799 memcpy(pdata, match->data, sizeof(*pdata)); 800 if (!of_property_read_u32(node, "ti,buffer-size", &buffer_size)) 801 pdata->buffer_size = buffer_size; 802 } else if (!pdata) { 803 dev_err(&pdev->dev, "missing platform data.\n"); 804 return -EINVAL; 805 } 806 mcbsp = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcbsp), GFP_KERNEL); 807 if (!mcbsp) 808 return -ENOMEM; 809 810 mcbsp->id = pdev->id; 811 mcbsp->pdata = pdata; 812 mcbsp->dev = &pdev->dev; 813 platform_set_drvdata(pdev, mcbsp); 814 815 ret = omap_mcbsp_init(pdev); 816 if (ret) 817 return ret; 818 819 ret = devm_snd_soc_register_component(&pdev->dev, 820 &omap_mcbsp_component, 821 &omap_mcbsp_dai, 1); 822 if (ret) 823 return ret; 824 825 return omap_pcm_platform_register(&pdev->dev); 826} 827 828static int asoc_mcbsp_remove(struct platform_device *pdev) 829{ 830 struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); 831 832 if (mcbsp->pdata->ops && mcbsp->pdata->ops->free) 833 mcbsp->pdata->ops->free(mcbsp->id); 834 835 omap_mcbsp_sysfs_remove(mcbsp); 836 837 clk_put(mcbsp->fclk); 838 839 return 0; 840} 841 842static struct platform_driver asoc_mcbsp_driver = { 843 .driver = { 844 .name = "omap-mcbsp", 845 .of_match_table = omap_mcbsp_of_match, 846 }, 847 848 .probe = asoc_mcbsp_probe, 849 .remove = asoc_mcbsp_remove, 850}; 851 852module_platform_driver(asoc_mcbsp_driver); 853 854MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>"); 855MODULE_DESCRIPTION("OMAP I2S SoC Interface"); 856MODULE_LICENSE("GPL"); 857MODULE_ALIAS("platform:omap-mcbsp"); 858