2 * ALSA I2S Interface for the Broadcom BCM947XX family of SOCs
4 * Copyright (C) 2009, Broadcom Corporation
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>
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)
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__);
65 static void bcm947xx_i2s_shutdown(struct snd_pcm_substream
*substream
)
67 //DBG("%s\n", __FUNCTION__);
71 static int bcm947xx_i2s_probe(struct platform_device
*pdev
)
75 if (snd_bcm
&& snd_bcm
->sih
)
76 if (si_findcoreidx(snd_bcm
->sih
, I2S_CORE_ID
, 0) == BADIDX
)
83 static int bcm947xx_i2s_suspend(struct platform_device
*dev
,
84 struct snd_soc_cpu_dai
*dai
)
86 DBG("%s - TBD\n", __FUNCTION__
);
90 static int bcm947xx_i2s_resume(struct platform_device
*dev
,
91 struct snd_soc_cpu_dai
*dai
)
93 DBG("%s - TBD\n", __FUNCTION__
);
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
);
102 DBG("%s w/cmd %d\n", __FUNCTION__
, 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
);
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
);
124 /* Set I2S DAI format */
125 static int bcm947xx_i2s_set_fmt(struct snd_soc_cpu_dai
*cpu_dai
,
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
;
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
;
146 case SND_SOC_DAIFMT_CBM_CFS
:
147 /* Codec clk master and frame slave */
148 devctrl
|= I2S_DC_BCLKD_IN
;
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
;
156 DBG("%s: unsupported MASTER: 0x%x \n", __FUNCTION__
,
157 fmt
& SND_SOC_DAIFMT_MASTER_MASK
);
161 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
162 case SND_SOC_DAIFMT_I2S
:
163 /* we only support I2S Format */
166 DBG("%s: unsupported FORMAT: 0x%x \n", __FUNCTION__
,
167 fmt
& SND_SOC_DAIFMT_FORMAT_MASK
);
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
);
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
;
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
);
200 uint32 rate
= params_rate(params
);
201 int channels
= params_channels(params
);
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
)) {
215 printk(KERN_ERR
"%s: unsupported audio sample rate %d Hz and mclk %d Hz "
216 "combination\n", __FUNCTION__
, rate
, snd_bcm
->mclk
);
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 */
237 devctrl
&= ~I2S_DC_OPCHSEL_6
;
240 devctrl
|= I2S_DC_OPCHSEL_6
;
243 printk(KERN_ERR
"%s: unsupported number of channels in stream - %d\n"
244 "combination\n", __FUNCTION__
, channels
);
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
:
260 case SNDRV_PCM_FORMAT_S20_3LE
:
264 case SNDRV_PCM_FORMAT_S24_LE
:
265 case SNDRV_PCM_FORMAT_S24_3LE
:
269 case SNDRV_PCM_FORMAT_S32_LE
:
271 /* SPDIF doesn't support 32 bit samples */
272 /* Should we just disable SPDIF rather than putting out garbage? */
276 DBG("unsupported format\n");
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
);
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",
304 .type
= SND_SOC_DAI_I2S
,
305 .probe
= bcm947xx_i2s_probe
,
306 .suspend
= bcm947xx_i2s_suspend
,
307 .resume
= bcm947xx_i2s_resume
,
311 .rates
= BCM947XX_I2S_RATES
,
312 .formats
= BCM947XX_I2S_FORMATS
,},
314 .startup
= bcm947xx_i2s_startup
,
315 .shutdown
= bcm947xx_i2s_shutdown
,
316 .trigger
= bcm947xx_i2s_trigger
,
317 .hw_params
= bcm947xx_i2s_hw_params
,},
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 },
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
,
351 bcm947xx_i2s_info_t
*snd
= NULL
;
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
);
365 /* allocate private info */
366 if ((snd
= (bcm947xx_i2s_info_t
*) MALLOC(osh
, sizeof(bcm947xx_i2s_info_t
))) == NULL
) {
371 bzero(snd
, sizeof(bcm947xx_i2s_info_t
));
374 if ((snd
->regsva
= ioremap_nocache(regs
, PCI_BAR0_WINSZ
)) == NULL
) {
375 DBG("ioremap_nocache() failed\n");
376 osl_detach(snd
->osh
);
382 * Do the hardware portion of the attach.
383 * Also initialize software state that depends on the particular hardware
386 snd
->sih
= si_attach((uint
)device
, snd
->osh
, snd
->regsva
, bustype
, btparam
,
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),
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
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
);
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
));
430 bcm947xx_i2s_pci_probe(struct pci_dev
*pdev
, const struct pci_device_id
*ent
)
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
);
442 err
= pci_enable_device(pdev
);
444 DBG("%s: Cannot enable device %d-%d_%d\n", __FUNCTION__
,
445 pdev
->bus
->number
, PCI_SLOT(pdev
->devfn
), PCI_FUNC(pdev
->devfn
));
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
);
455 pci_set_drvdata(pdev
, snd_bcm
);
456 DBG("%s: snd_bcm @ %p snd_bcm.regs @ %p\n", __FUNCTION__
, snd_bcm
, snd_bcm
.regs
);
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
)