Broadcom SDK and wireless driver: another attempt to update to ver. 5.10.147.0
[tomato.git] / release / src-rt / linux / linux-2.6 / sound / soc / bcm947xx / bcm947xx-i2s.c
blob53d2372278bb8efea811ec15c4ab2e1a575eee55
1 /*
2 * ALSA I2S Interface for the Broadcom BCM947XX family of SOCs
4 * Copyright (C) 2009, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 * $Id: bcm947xx-i2s.c,v 1.2 2009/11/12 22:26:07 Exp $
15 #include <linux/init.h>
16 #include <linux/module.h>
17 #include <linux/device.h>
18 #include <linux/delay.h>
20 #include <sound/driver.h>
21 #include <sound/core.h>
22 #include <sound/pcm.h>
23 #include <sound/pcm_params.h>
24 #include <sound/initval.h>
25 #include <sound/soc.h>
27 #include <typedefs.h>
28 #include <bcmdevs.h>
29 #include <pcicfg.h>
30 #include <hndsoc.h>
31 #include <osl.h>
32 #include <bcmutils.h>
33 #include <siutils.h>
34 #include <sbhnddma.h>
35 #include <hnddma.h>
36 #include <sbchipc.h>
37 #include <i2s_core.h>
39 #include "bcm947xx-i2s.h"
41 /* Be careful here... turning on prints can break everything, if you start seeing FIFO underflows
42 * then it might be due to excessive printing
44 #define BCM947XX_I2S_DEBUG 0
45 #if BCM947XX_I2S_DEBUG
46 #define DBG(x...) printk(KERN_ERR x)
47 #else
48 #define DBG(x...)
49 #endif
52 #define BCM947XX_SND "bcm947xx i2s sound"
54 bcm947xx_i2s_info_t *snd_bcm = NULL;
55 EXPORT_SYMBOL_GPL(snd_bcm);
59 static int bcm947xx_i2s_startup(struct snd_pcm_substream *substream)
61 //DBG("%s\n", __FUNCTION__);
62 return 0;
65 static void bcm947xx_i2s_shutdown(struct snd_pcm_substream *substream)
67 //DBG("%s\n", __FUNCTION__);
68 return;
71 static int bcm947xx_i2s_probe(struct platform_device *pdev)
73 int ret = 0;
75 if (snd_bcm && snd_bcm->sih)
76 if (si_findcoreidx(snd_bcm->sih, I2S_CORE_ID, 0) == BADIDX)
77 ret = -EINVAL;
79 return ret;
83 static int bcm947xx_i2s_suspend(struct platform_device *dev,
84 struct snd_soc_cpu_dai *dai)
86 DBG("%s - TBD\n", __FUNCTION__);
87 return 0;
90 static int bcm947xx_i2s_resume(struct platform_device *dev,
91 struct snd_soc_cpu_dai *dai)
93 DBG("%s - TBD\n", __FUNCTION__);
94 return 0;
97 static int bcm947xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
99 uint32 i2scontrol = R_REG(snd_bcm.osh, &snd_bcm->regs->i2scontrol);
100 int ret = 0;
102 DBG("%s w/cmd %d\n", __FUNCTION__, cmd);
104 switch (cmd) {
105 case SNDRV_PCM_TRIGGER_START:
106 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
107 case SNDRV_PCM_TRIGGER_RESUME:
108 i2scontrol |= I2S_CTRL_PLAYEN;
109 W_REG(snd_bcm.osh, &snd_bcm->regs->i2scontrol, i2scontrol);
110 break;
111 case SNDRV_PCM_TRIGGER_STOP:
112 case SNDRV_PCM_TRIGGER_SUSPEND:
113 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
114 i2scontrol &= ~I2S_CTRL_PLAYEN;
115 W_REG(snd_bcm.osh, &snd_bcm->regs->i2scontrol, i2scontrol);
116 break;
117 default:
118 ret = -EINVAL;
121 return ret;
124 /* Set I2S DAI format */
125 static int bcm947xx_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai,
126 unsigned int fmt)
128 u32 devctrl = R_REG(snd_bcm.osh, &snd_bcm->regs->devcontrol);
130 DBG("%s: format 0x%x\n", __FUNCTION__, fmt);
132 /* We always want this core to be in I2S mode */
133 devctrl &= ~I2S_DC_MODE_TDM;
135 /* See include/sound/soc.h for DAIFMT */
136 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
137 case SND_SOC_DAIFMT_CBM_CFM:
138 /* Codec clk master and frame master */
139 devctrl |= I2S_DC_BCLKD_IN;
140 break;
141 case SND_SOC_DAIFMT_CBS_CFM:
142 /* Codec clk slave and frame master */
143 /* BCM SOC is the master */
144 devctrl &= ~I2S_DC_BCLKD_IN;
145 break;
146 case SND_SOC_DAIFMT_CBM_CFS:
147 /* Codec clk master and frame slave */
148 devctrl |= I2S_DC_BCLKD_IN;
149 break;
150 case SND_SOC_DAIFMT_CBS_CFS:
151 /* Codec clk slave and frame slave */
152 /* BCM SOC is the master */
153 devctrl &= ~I2S_DC_BCLKD_IN;
154 break;
155 default:
156 DBG("%s: unsupported MASTER: 0x%x \n", __FUNCTION__,
157 fmt & SND_SOC_DAIFMT_MASTER_MASK );
158 return -EINVAL;
161 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
162 case SND_SOC_DAIFMT_I2S:
163 /* we only support I2S Format */
164 break;
165 default:
166 DBG("%s: unsupported FORMAT: 0x%x \n", __FUNCTION__,
167 fmt & SND_SOC_DAIFMT_FORMAT_MASK );
168 return -EINVAL;
171 //DBG("%s: I2S setting devctrl to 0x%x\n", __FUNCTION__, devctrl);
172 /* Write I2S devcontrol reg */
173 W_REG(snd_bcm.osh, &snd_bcm->regs->devcontrol, devctrl);
175 return 0;
180 * Set Clock source
182 static int bcm947xx_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
183 int clk_id, unsigned int freq, int dir)
185 /* Stash the MCLK rate that we're using, we can use it to help us to pick
186 * the right clkdiv settings later.
188 snd_bcm->mclk = freq;
190 return 0;
193 static int bcm947xx_i2s_hw_params(struct snd_pcm_substream *substream,
194 struct snd_pcm_hw_params *params)
196 u32 devctrl = R_REG(snd_bcm.osh, &snd_bcm->regs->devcontrol);
197 u32 clkdiv = R_REG(snd_bcm.osh, &snd_bcm->regs->clkdivider);
198 u32 stxctrl = R_REG(snd_bcm.osh, &snd_bcm->regs->stxctrl);
199 uint32 srate = 0;
200 uint32 rate = params_rate(params);
201 int channels = params_channels(params);
202 int ii = 0;
203 bool found = FALSE;
205 /* Set up our ClockDivider register with audio sample rate */
206 for (ii = 0; ii < ARRAY_SIZE(i2s_clkdiv_coeffs); ii++) {
207 if ((i2s_clkdiv_coeffs[ii].rate == rate) &&
208 (i2s_clkdiv_coeffs[ii].mclk == snd_bcm->mclk)) {
209 found = TRUE;
210 break;
214 if (found != TRUE) {
215 printk(KERN_ERR "%s: unsupported audio sample rate %d Hz and mclk %d Hz "
216 "combination\n", __FUNCTION__, rate, snd_bcm->mclk);
217 return -EINVAL;
218 } else {
219 /* Write the new SRATE into the clock divider register */
220 srate = (i2s_clkdiv_coeffs[ii].srate << I2S_CLKDIV_SRATE_SHIFT);
221 clkdiv &= ~I2S_CLKDIV_SRATE_MASK;
222 W_REG(snd_bcm.osh, &snd_bcm->regs->clkdivider, clkdiv | srate);
224 DBG("%s: i2s clkdivider 0x%x txplayth 0x%x\n", __FUNCTION__,
225 R_REG(snd_bcm.osh, &snd_bcm->regs->clkdivider),
226 R_REG(snd_bcm.osh, &snd_bcm->regs->txplayth));
227 DBG("%s: audio sample rate %d Hz and mclk %d Hz\n",
228 __FUNCTION__, rate, snd_bcm.mclk);
231 DBG("%s: %d channels in this stream\n", __FUNCTION__, channels);
233 /* Set up for the # of channels in this stream */
234 /* For I2S/SPDIF we support 2 channel -OR- 6 (5.1) channels */
235 switch (channels) {
236 case 2:
237 devctrl &= ~I2S_DC_OPCHSEL_6;
238 break;
239 case 6:
240 devctrl |= I2S_DC_OPCHSEL_6;
241 break;
242 default:
243 printk(KERN_ERR "%s: unsupported number of channels in stream - %d\n"
244 "combination\n", __FUNCTION__, channels);
245 return -EINVAL;
248 DBG("%s: access 0x%x\n", __FUNCTION__, params_access(params));
249 DBG("%s: format 0x%x\n", __FUNCTION__, params_format(params));
250 DBG("%s: subformat 0x%x\n", __FUNCTION__, params_subformat(params));
252 /* clear TX word length bits then Set the # of bits per sample in this stream */
253 devctrl &= ~I2S_DC_WL_TX_MASK;
254 stxctrl &= ~I2S_STXC_WL_MASK;
255 switch (params_format(params)) {
256 case SNDRV_PCM_FORMAT_S16_LE:
257 devctrl |= 0x0;
258 stxctrl |= 0x0;
259 break;
260 case SNDRV_PCM_FORMAT_S20_3LE:
261 devctrl |= 0x400;
262 stxctrl |= 0x01;
263 break;
264 case SNDRV_PCM_FORMAT_S24_LE:
265 case SNDRV_PCM_FORMAT_S24_3LE:
266 devctrl |= 0x800;
267 stxctrl |= 0x02;
268 break;
269 case SNDRV_PCM_FORMAT_S32_LE:
270 devctrl |= 0xC00;
271 /* SPDIF doesn't support 32 bit samples */
272 /* Should we just disable SPDIF rather than putting out garbage? */
273 stxctrl |= 0x03;
274 break;
275 default:
276 DBG("unsupported format\n");
277 break;
280 /* For now, we're only interested in Tx so we'll set up half-duplex Tx-only */
281 devctrl &= ~I2S_DC_DPX_MASK;
283 /* Write I2S devcontrol reg */
284 W_REG(snd_bcm.osh, &snd_bcm->regs->devcontrol, devctrl);
285 W_REG(snd_bcm.osh, &snd_bcm->regs->stxctrl, stxctrl);
287 return 0;
290 #define BCM947XX_I2S_RATES \
291 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
292 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | \
293 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
295 #define BCM947XX_I2S_FORMATS \
296 (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
297 SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 | \
298 SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 | \
299 SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32)
301 struct snd_soc_cpu_dai bcm947xx_i2s_dai = {
302 .name = "bcm947xx-i2s",
303 .id = 0,
304 .type = SND_SOC_DAI_I2S,
305 .probe = bcm947xx_i2s_probe,
306 .suspend = bcm947xx_i2s_suspend,
307 .resume = bcm947xx_i2s_resume,
308 .playback = {
309 .channels_min = 2,
310 .channels_max = 2,
311 .rates = BCM947XX_I2S_RATES,
312 .formats = BCM947XX_I2S_FORMATS,},
313 .ops = {
314 .startup = bcm947xx_i2s_startup,
315 .shutdown = bcm947xx_i2s_shutdown,
316 .trigger = bcm947xx_i2s_trigger,
317 .hw_params = bcm947xx_i2s_hw_params,},
318 .dai_ops = {
319 .set_fmt = bcm947xx_i2s_set_fmt,
320 .set_sysclk = bcm947xx_i2s_set_sysclk,
324 EXPORT_SYMBOL_GPL(bcm947xx_i2s_dai);
327 MODULE_LICENSE("GPL");
328 /* MODULE_AUTHOR(""); */
329 MODULE_DESCRIPTION("BCM947XX I2S module");
332 /************************************************************************************************/
334 #define DMAREG(a, direction, fifonum) ( \
335 (direction == DMA_TX) ? \
336 (void *)(uintptr)&(a->regs->dmaregs[fifonum].dmaxmt) : \
337 (void *)(uintptr)&(a->regs->dmaregs[fifonum].dmarcv))
339 static struct pci_device_id bcm947xx_i2s_pci_id_table[] = {
340 { PCI_VENDOR_ID_BROADCOM, BCM47XX_AUDIO_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
341 {0,}
344 MODULE_DEVICE_TABLE(pci, bcm947xx_i2s_pci_id_table);
346 static bcm947xx_i2s_info_t *
347 bcm947xx_i2s_pci_attach(uint16 vendor, uint16 device, ulong regs, uint bustype, void *btparam,
348 uint irq)
350 osl_t *osh = NULL;
351 bcm947xx_i2s_info_t *snd = NULL;
352 int ret;
354 uint addrwidth;
355 int dma_attach_err = 0;
358 DBG("%s: vendor 0x%x device 0x%x regs 0x%x bustype 0x%x btparam %p irq 0x%x\n",
359 __FUNCTION__, vendor, device, regs, bustype, btparam, irq);
362 osh = osl_attach(btparam, bustype, FALSE);
363 ASSERT(osh);
365 /* allocate private info */
366 if ((snd = (bcm947xx_i2s_info_t *) MALLOC(osh, sizeof(bcm947xx_i2s_info_t))) == NULL) {
367 osl_detach(osh);
368 return NULL;
371 bzero(snd, sizeof(bcm947xx_i2s_info_t));
372 snd->osh = osh;
374 if ((snd->regsva = ioremap_nocache(regs, PCI_BAR0_WINSZ)) == NULL) {
375 DBG("ioremap_nocache() failed\n");
376 osl_detach(snd->osh);
377 return NULL;
379 snd->irq = irq;
382 * Do the hardware portion of the attach.
383 * Also initialize software state that depends on the particular hardware
384 * we are running.
386 snd->sih = si_attach((uint)device, snd->osh, snd->regsva, bustype, btparam,
387 NULL, NULL);
389 snd->regs = (i2sregs_t *)si_setcore(snd->sih, I2S_CORE_ID, 0);
391 addrwidth = dma_addrwidth(snd->sih, DMAREG(snd, DMA_TX, 0));
393 snd->di[0] = dma_attach(snd->osh, "i2s_dma", snd->sih,
394 DMAREG(snd, DMA_TX, 0),
395 NULL, 64, 0,
396 0, -1, 0, 0, NULL);
398 dma_attach_err |= (NULL == snd->di[0]);
400 /* Tell DMA that we're not using framed/packet data */
401 dma_ctrlflags(snd->di[0], DMA_CTRL_UNFRAMED /* mask */, DMA_CTRL_UNFRAMED /* value */);
403 /* for 471X chips, Turn on I2S pins. They're MUX'd with PFLASH pins, and PFLASH is ON
404 * by default
406 if (CHIPID(snd->sih->chip) == BCM4716_CHIP_ID) {
407 ret = si_corereg(snd->sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol),
408 CCTRL471X_I2S_PINS_ENABLE, CCTRL471X_I2S_PINS_ENABLE);
411 return snd;
414 static void
415 bcm947xx_i2s_free(bcm947xx_i2s_info_t *sndbcm)
417 osl_t *osh = sndbcm->osh;
419 dma_detach(sndbcm->di[0]);
421 si_detach(sndbcm->sih);
423 MFREE(osh, sndbcm, sizeof(bcm947xx_i2s_info_t));
425 osl_detach(osh);
429 static int __devinit
430 bcm947xx_i2s_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
432 int err = 0;
434 DBG("%s: for pdev 0x%x w/irq %d.\n", __FUNCTION__, pdev->device, pdev->irq);
436 if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) || (pdev->device != BCM47XX_AUDIO_ID)) {
437 DBG("%s: early bailout pcideviceid mismatch - 0x%x.\n",
438 __FUNCTION__, pdev->device);
439 return (-ENODEV);
442 err = pci_enable_device(pdev);
443 if (err) {
444 DBG("%s: Cannot enable device %d-%d_%d\n", __FUNCTION__,
445 pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
446 return (-ENODEV);
448 pci_set_master(pdev);
450 snd_bcm = bcm947xx_i2s_pci_attach(pdev->vendor, pdev->device, pci_resource_start(pdev, 0),
451 PCI_BUS, pdev, pdev->irq);
452 if (!snd_bcm)
453 return -ENODEV;
455 pci_set_drvdata(pdev, snd_bcm);
456 DBG("%s: snd_bcm @ %p snd_bcm.regs @ %p\n", __FUNCTION__, snd_bcm, snd_bcm.regs);
458 return err;
461 static void __devexit bcm947xx_i2s_pci_remove(struct pci_dev *pdev)
463 bcm947xx_i2s_info_t *sndbcm = (bcm947xx_i2s_info_t *) pci_get_drvdata(pdev);
465 bcm947xx_i2s_free(sndbcm);
466 snd_bcm = (bcm947xx_i2s_info_t *)NULL;
467 pci_set_drvdata(pdev, NULL);
471 static struct pci_driver bcm947xx_i2s_pci_driver = {
472 .name = BCM947XX_SND,
473 .id_table = bcm947xx_i2s_pci_id_table,
474 .probe = bcm947xx_i2s_pci_probe,
475 .remove = __devexit_p(bcm947xx_i2s_pci_remove),
478 static int __init bcm947xx_i2s_pci_init(void)
480 return pci_register_driver(&bcm947xx_i2s_pci_driver);
483 static void __exit bcm947xx_i2s_pci_exit(void)
485 pci_unregister_driver(&bcm947xx_i2s_pci_driver);
488 module_init(bcm947xx_i2s_pci_init)
489 module_exit(bcm947xx_i2s_pci_exit)