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