1/* 2 * ALSA I2S Interface for the Broadcom BCM947XX family of SOCs 3 * 4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: bcm947xx-i2s.c,v 1.3 2010/05/14 00:36:48 Exp $ 19 */ 20 21#include <linux/init.h> 22#include <linux/module.h> 23#include <linux/device.h> 24#include <linux/delay.h> 25 26#include <sound/driver.h> 27#include <sound/core.h> 28#include <sound/pcm.h> 29#include <sound/pcm_params.h> 30#include <sound/initval.h> 31#include <sound/soc.h> 32 33#include <typedefs.h> 34#include <bcmdevs.h> 35#include <pcicfg.h> 36#include <hndsoc.h> 37#include <osl.h> 38#include <bcmutils.h> 39#include <siutils.h> 40#include <sbhnddma.h> 41#include <hnddma.h> 42#include <sbchipc.h> 43#include <i2s_core.h> 44#include <hndpmu.h> 45 46#include "bcm947xx-i2s.h" 47 48/* Be careful here... turning on prints can break everything, if you start seeing FIFO underflows 49 * then it might be due to excessive printing 50 */ 51#define BCM947XX_I2S_DEBUG 0 52#if BCM947XX_I2S_DEBUG 53#define DBG(x...) printk(KERN_ERR x) 54#else 55#define DBG(x...) 56#endif 57 58 59#define BCM947XX_SND "bcm947xx i2s sound" 60 61bcm947xx_i2s_info_t *snd_bcm = NULL; 62EXPORT_SYMBOL_GPL(snd_bcm); 63 64 65 66static int bcm947xx_i2s_startup(struct snd_pcm_substream *substream) 67{ 68 //DBG("%s\n", __FUNCTION__); 69 return 0; 70} 71 72static void bcm947xx_i2s_shutdown(struct snd_pcm_substream *substream) 73{ 74 //DBG("%s\n", __FUNCTION__); 75 return; 76} 77 78static int bcm947xx_i2s_probe(struct platform_device *pdev) 79{ 80 int ret = 0; 81 82 if (snd_bcm && snd_bcm->sih) 83 if (si_findcoreidx(snd_bcm->sih, I2S_CORE_ID, 0) == BADIDX) 84 ret = -EINVAL; 85 86 return ret; 87} 88 89 90static int bcm947xx_i2s_suspend(struct platform_device *dev, 91 struct snd_soc_cpu_dai *dai) 92{ 93 DBG("%s - TBD\n", __FUNCTION__); 94 return 0; 95} 96 97static int bcm947xx_i2s_resume(struct platform_device *dev, 98 struct snd_soc_cpu_dai *dai) 99{ 100 DBG("%s - TBD\n", __FUNCTION__); 101 return 0; 102} 103 104static int bcm947xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) 105{ 106 uint32 i2scontrol = R_REG(snd_bcm.osh, &snd_bcm->regs->i2scontrol); 107 int ret = 0; 108 109 DBG("%s w/cmd %d\n", __FUNCTION__, cmd); 110 111 switch (cmd) { 112 case SNDRV_PCM_TRIGGER_START: 113 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 114 case SNDRV_PCM_TRIGGER_RESUME: 115 i2scontrol |= I2S_CTRL_PLAYEN; 116 W_REG(snd_bcm.osh, &snd_bcm->regs->i2scontrol, i2scontrol); 117 break; 118 case SNDRV_PCM_TRIGGER_STOP: 119 case SNDRV_PCM_TRIGGER_SUSPEND: 120 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 121 i2scontrol &= ~I2S_CTRL_PLAYEN; 122 W_REG(snd_bcm.osh, &snd_bcm->regs->i2scontrol, i2scontrol); 123 break; 124 default: 125 ret = -EINVAL; 126 } 127 128 return ret; 129} 130 131/* Set I2S DAI format */ 132static int bcm947xx_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai, 133 unsigned int fmt) 134{ 135 u32 devctrl = R_REG(snd_bcm.osh, &snd_bcm->regs->devcontrol); 136 137 DBG("%s: format 0x%x\n", __FUNCTION__, fmt); 138 139 /* We always want this core to be in I2S mode */ 140 devctrl &= ~I2S_DC_MODE_TDM; 141 142 /* See include/sound/soc.h for DAIFMT */ 143 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 144 case SND_SOC_DAIFMT_CBM_CFM: 145 /* Codec clk master and frame master */ 146 devctrl |= I2S_DC_BCLKD_IN; 147 break; 148 case SND_SOC_DAIFMT_CBS_CFM: 149 /* Codec clk slave and frame master */ 150 /* BCM SOC is the master */ 151 devctrl &= ~I2S_DC_BCLKD_IN; 152 break; 153 case SND_SOC_DAIFMT_CBM_CFS: 154 /* Codec clk master and frame slave */ 155 devctrl |= I2S_DC_BCLKD_IN; 156 break; 157 case SND_SOC_DAIFMT_CBS_CFS: 158 /* Codec clk slave and frame slave */ 159 /* BCM SOC is the master */ 160 devctrl &= ~I2S_DC_BCLKD_IN; 161 break; 162 default: 163 DBG("%s: unsupported MASTER: 0x%x \n", __FUNCTION__, 164 fmt & SND_SOC_DAIFMT_MASTER_MASK ); 165 return -EINVAL; 166 } 167 168 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 169 case SND_SOC_DAIFMT_I2S: 170 /* we only support I2S Format */ 171 break; 172 default: 173 DBG("%s: unsupported FORMAT: 0x%x \n", __FUNCTION__, 174 fmt & SND_SOC_DAIFMT_FORMAT_MASK ); 175 return -EINVAL; 176 } 177 178 //DBG("%s: I2S setting devctrl to 0x%x\n", __FUNCTION__, devctrl); 179 /* Write I2S devcontrol reg */ 180 W_REG(snd_bcm.osh, &snd_bcm->regs->devcontrol, devctrl); 181 182 return 0; 183} 184 185 186/* 187 * Set Clock source 188 */ 189static int bcm947xx_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, 190 int clk_id, unsigned int freq, int dir) 191{ 192 /* Stash the MCLK rate that we're using, we can use it to help us to pick 193 * the right clkdiv settings later. 194 */ 195 snd_bcm->mclk = freq; 196 DBG("%s: mclk %d Hz\n", __FUNCTION__, snd_bcm->mclk); 197 198 return 0; 199} 200 201static int bcm947xx_i2s_hw_params(struct snd_pcm_substream *substream, 202 struct snd_pcm_hw_params *params) 203{ 204 u32 devctrl = R_REG(snd_bcm.osh, &snd_bcm->regs->devcontrol); 205 u32 clkdiv = R_REG(snd_bcm.osh, &snd_bcm->regs->clkdivider); 206 u32 stxctrl = R_REG(snd_bcm.osh, &snd_bcm->regs->stxctrl); 207 uint32 srate = 0; 208 uint32 rate = params_rate(params); 209 int channels = params_channels(params); 210 int ii = 0; 211 bool found = FALSE; 212 213 /* Set up our ClockDivider register with audio sample rate */ 214 for (ii = 0; ii < ARRAY_SIZE(i2s_clkdiv_coeffs); ii++) { 215 if ((i2s_clkdiv_coeffs[ii].rate == rate) && 216 (i2s_clkdiv_coeffs[ii].mclk == snd_bcm->mclk)) { 217 found = TRUE; 218 break; 219 } 220 } 221 222 if (found != TRUE) { 223 printk(KERN_ERR "%s: unsupported audio sample rate %d Hz and mclk %d Hz " 224 "combination\n", __FUNCTION__, rate, snd_bcm->mclk); 225 return -EINVAL; 226 } else { 227 /* Write the new SRATE into the clock divider register */ 228 srate = (i2s_clkdiv_coeffs[ii].srate << I2S_CLKDIV_SRATE_SHIFT); 229 clkdiv &= ~I2S_CLKDIV_SRATE_MASK; 230 W_REG(snd_bcm.osh, &snd_bcm->regs->clkdivider, clkdiv | srate); 231 232 DBG("%s: i2s clkdivider 0x%x txplayth 0x%x\n", __FUNCTION__, 233 R_REG(snd_bcm.osh, &snd_bcm->regs->clkdivider), 234 R_REG(snd_bcm.osh, &snd_bcm->regs->txplayth)); 235 DBG("%s: audio sample rate %d Hz and mclk %d Hz\n", 236 __FUNCTION__, rate, snd_bcm->mclk); 237 } 238 239 DBG("%s: %d channels in this stream\n", __FUNCTION__, channels); 240 241 /* Set up for the # of channels in this stream */ 242 /* For I2S/SPDIF we support 2 channel -OR- 6 (5.1) channels */ 243 switch (channels) { 244 case 2: 245 devctrl &= ~I2S_DC_OPCHSEL_6; 246 break; 247 case 6: 248 devctrl |= I2S_DC_OPCHSEL_6; 249 break; 250 default: 251 printk(KERN_ERR "%s: unsupported number of channels in stream - %d\n" 252 "combination\n", __FUNCTION__, channels); 253 return -EINVAL; 254 } 255 256 DBG("%s: access 0x%x\n", __FUNCTION__, params_access(params)); 257 DBG("%s: format 0x%x\n", __FUNCTION__, params_format(params)); 258 DBG("%s: subformat 0x%x\n", __FUNCTION__, params_subformat(params)); 259 260 /* clear TX word length bits then Set the # of bits per sample in this stream */ 261 devctrl &= ~I2S_DC_WL_TX_MASK; 262 stxctrl &= ~I2S_STXC_WL_MASK; 263 switch (params_format(params)) { 264 case SNDRV_PCM_FORMAT_U8: 265 devctrl |= 0x4000; 266 stxctrl |= 0x1000; 267 break; 268 case SNDRV_PCM_FORMAT_S16_LE: 269 devctrl |= 0x0; 270 stxctrl |= 0x0; 271 break; 272 case SNDRV_PCM_FORMAT_S20_3LE: 273 devctrl |= 0x400; 274 stxctrl |= 0x01; 275 break; 276 case SNDRV_PCM_FORMAT_S24_LE: 277 case SNDRV_PCM_FORMAT_S24_3LE: 278 devctrl |= 0x800; 279 stxctrl |= 0x02; 280 break; 281 case SNDRV_PCM_FORMAT_S32_LE: 282 devctrl |= 0xC00; 283 /* SPDIF doesn't support 32 bit samples */ 284 /* Should we just disable SPDIF rather than putting out garbage? */ 285 stxctrl |= 0x03; 286 break; 287 default: 288 DBG("unsupported format\n"); 289 break; 290 } 291 292 /* For now, we're only interested in Tx so we'll set up half-duplex Tx-only */ 293 devctrl &= ~I2S_DC_DPX_MASK; 294 295 /* Write I2S devcontrol reg */ 296 W_REG(snd_bcm.osh, &snd_bcm->regs->devcontrol, devctrl); 297 devctrl |= I2S_DC_I2SCFG; /* Set up core's SRAM for Half duplex Tx */ 298 W_REG(snd_bcm.osh, &snd_bcm->regs->devcontrol, devctrl); 299 W_REG(snd_bcm.osh, &snd_bcm->regs->stxctrl, stxctrl); 300 DBG("%s: set devctrl 0x%x && stxctrl 0x%x\n", __FUNCTION__, devctrl, stxctrl); 301 302 DBG("%s: read devctrl 0x%x stxctrl 0x%x\n", __FUNCTION__, 303 R_REG(snd_bcm.osh, &snd_bcm->regs->devcontrol), 304 R_REG(snd_bcm.osh, &snd_bcm->regs->stxctrl)); 305 return 0; 306} 307 308#define BCM947XX_I2S_RATES \ 309 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \ 310 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | \ 311 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) 312 313#define BCM947XX_I2S_FORMATS \ 314 (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ 315 SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 | \ 316 SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 | \ 317 SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32) 318 319struct snd_soc_cpu_dai bcm947xx_i2s_dai = { 320 .name = "bcm947xx-i2s", 321 .id = 0, 322 .type = SND_SOC_DAI_I2S, 323 .probe = bcm947xx_i2s_probe, 324 .suspend = bcm947xx_i2s_suspend, 325 .resume = bcm947xx_i2s_resume, 326 .playback = { 327 .channels_min = 2, 328 .channels_max = 2, 329 .rates = BCM947XX_I2S_RATES, 330 .formats = BCM947XX_I2S_FORMATS,}, 331 .ops = { 332 .startup = bcm947xx_i2s_startup, 333 .shutdown = bcm947xx_i2s_shutdown, 334 .trigger = bcm947xx_i2s_trigger, 335 .hw_params = bcm947xx_i2s_hw_params,}, 336 .dai_ops = { 337 .set_fmt = bcm947xx_i2s_set_fmt, 338 .set_sysclk = bcm947xx_i2s_set_sysclk, 339 }, 340}; 341 342EXPORT_SYMBOL_GPL(bcm947xx_i2s_dai); 343 344 345MODULE_LICENSE("GPL"); 346/* MODULE_AUTHOR(""); */ 347MODULE_DESCRIPTION("BCM947XX I2S module"); 348 349 350/************************************************************************************************/ 351 352#define DMAREG(a, direction, fifonum) ( \ 353 (direction == DMA_TX) ? \ 354 (void *)(uintptr)&(a->regs->dmaregs[fifonum].dmaxmt) : \ 355 (void *)(uintptr)&(a->regs->dmaregs[fifonum].dmarcv)) 356 357static struct pci_device_id bcm947xx_i2s_pci_id_table[] = { 358 { PCI_VENDOR_ID_BROADCOM, BCM47XX_AUDIO_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 359 {0,} 360}; 361 362MODULE_DEVICE_TABLE(pci, bcm947xx_i2s_pci_id_table); 363 364static bcm947xx_i2s_info_t * 365bcm947xx_i2s_pci_attach(uint16 vendor, uint16 device, ulong regs, uint bustype, void *btparam, 366 uint irq) 367{ 368 osl_t *osh = NULL; 369 bcm947xx_i2s_info_t *snd = NULL; 370 int ret; 371 372 int dma_attach_err = 0; 373 374 375 DBG("%s: vendor 0x%x device 0x%x regs 0x%lx bustype 0x%x btparam %p irq 0x%x\n", 376 __FUNCTION__, vendor, device, regs, bustype, btparam, irq); 377 378 379 osh = osl_attach(btparam, bustype, FALSE); 380 ASSERT(osh); 381 382 /* allocate private info */ 383 if ((snd = (bcm947xx_i2s_info_t *) MALLOC(osh, sizeof(bcm947xx_i2s_info_t))) == NULL) { 384 osl_detach(osh); 385 return NULL; 386 } 387 388 bzero(snd, sizeof(bcm947xx_i2s_info_t)); 389 snd->osh = osh; 390 391 if ((snd->regsva = ioremap_nocache(regs, PCI_BAR0_WINSZ)) == NULL) { 392 DBG("ioremap_nocache() failed\n"); 393 osl_detach(snd->osh); 394 return NULL; 395 } 396 snd->irq = irq; 397 398 /* 399 * Do the hardware portion of the attach. 400 * Also initialize software state that depends on the particular hardware 401 * we are running. 402 */ 403 snd->sih = si_attach((uint)device, snd->osh, snd->regsva, bustype, btparam, 404 NULL, NULL); 405 406 snd->regs = (i2sregs_t *)si_setcore(snd->sih, I2S_CORE_ID, 0); 407 si_core_reset(snd->sih, 0, 0); 408 409 snd->di[0] = dma_attach(snd->osh, "i2s_dma", snd->sih, 410 DMAREG(snd, DMA_TX, 0), 411 NULL, 64, 0, 412 0, -1, 0, 0, NULL); 413 414 dma_attach_err |= (NULL == snd->di[0]); 415 416 /* Tell DMA that we're not using framed/packet data */ 417 dma_ctrlflags(snd->di[0], DMA_CTRL_UNFRAMED /* mask */, DMA_CTRL_UNFRAMED /* value */); 418 419 if (CHIPID(snd->sih->chip) == BCM4716_CHIP_ID) { 420 /* for 471X chips, Turn on I2S pins. They're MUX'd with PFLASH pins, and PFLASH 421 * is ON by default 422 */ 423 ret = si_corereg(snd->sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol), 424 CCTRL_471X_I2S_PINS_ENABLE, CCTRL_471X_I2S_PINS_ENABLE); 425 } else if (CHIPID(snd->sih->chip) == BCM5357_CHIP_ID) { 426 /* Write to the 2nd chipcontrol reg. to turn on I2S pins */ 427 ret = si_pmu_chipcontrol(snd->sih, PMU1_PLL0_CHIPCTL1, CCTRL_5357_I2S_PINS_ENABLE, 428 CCTRL_5357_I2S_PINS_ENABLE); 429 /* Write to the 2nd chipcontrol reg. to turn on I2C-via-gpio pins */ 430 ret = si_pmu_chipcontrol(snd->sih, PMU1_PLL0_CHIPCTL1, 431 CCTRL_5357_I2CSPI_PINS_ENABLE, 0); 432 } 433 434 return snd; 435} 436 437static void 438bcm947xx_i2s_free(bcm947xx_i2s_info_t *sndbcm) 439{ 440 osl_t *osh = sndbcm->osh; 441 442 dma_detach(sndbcm->di[0]); 443 444 si_detach(sndbcm->sih); 445 446 MFREE(osh, sndbcm, sizeof(bcm947xx_i2s_info_t)); 447 448 osl_detach(osh); 449} 450 451 452static int __devinit 453bcm947xx_i2s_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 454{ 455 int err = 0; 456 457 DBG("%s: for pdev 0x%x w/irq %d.\n", __FUNCTION__, pdev->device, pdev->irq); 458 459 if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) || (pdev->device != BCM47XX_AUDIO_ID)) { 460 DBG("%s: early bailout pcideviceid mismatch - 0x%x.\n", 461 __FUNCTION__, pdev->device); 462 return (-ENODEV); 463 } 464 465 err = pci_enable_device(pdev); 466 if (err) { 467 DBG("%s: Cannot enable device %d-%d_%d\n", __FUNCTION__, 468 pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); 469 return (-ENODEV); 470 } 471 pci_set_master(pdev); 472 473 snd_bcm = bcm947xx_i2s_pci_attach(pdev->vendor, pdev->device, pci_resource_start(pdev, 0), 474 PCI_BUS, pdev, pdev->irq); 475 if (!snd_bcm) 476 return -ENODEV; 477 478 pci_set_drvdata(pdev, snd_bcm); 479 480 return err; 481} 482 483static void __devexit bcm947xx_i2s_pci_remove(struct pci_dev *pdev) 484{ 485 bcm947xx_i2s_info_t *sndbcm = (bcm947xx_i2s_info_t *) pci_get_drvdata(pdev); 486 487 bcm947xx_i2s_free(sndbcm); 488 snd_bcm = (bcm947xx_i2s_info_t *)NULL; 489 pci_set_drvdata(pdev, NULL); 490} 491 492 493static struct pci_driver bcm947xx_i2s_pci_driver = { 494 .name = BCM947XX_SND, 495 .id_table = bcm947xx_i2s_pci_id_table, 496 .probe = bcm947xx_i2s_pci_probe, 497 .remove = __devexit_p(bcm947xx_i2s_pci_remove), 498}; 499 500static int __init bcm947xx_i2s_pci_init(void) 501{ 502 return pci_register_driver(&bcm947xx_i2s_pci_driver); 503} 504 505static void __exit bcm947xx_i2s_pci_exit(void) 506{ 507 pci_unregister_driver(&bcm947xx_i2s_pci_driver); 508} 509 510module_init(bcm947xx_i2s_pci_init) 511module_exit(bcm947xx_i2s_pci_exit) 512