static int bcm947xx_pcm_open(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	bcm947xx_i2s_info_t *snd_bcm = rtd->dai->cpu_dai->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct bcm947xx_runtime_data *brtd;
	int ret;

	DBG("%s %s\n", __FUNCTION__, bcm947xx_direction_str(substream));

	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
		snd_soc_set_runtime_hwparams(substream, &bcm947xx_pcm_hardware_capture);
	} else {
		snd_soc_set_runtime_hwparams(substream, &bcm947xx_pcm_hardware_playback);
	}

	if (snd_bcm->in_use & ~(1 << substream->stream)) {
		/* Another stream is in-use; set our constraints to match. */
		if ((ret = bcm947xx_pcm_set_constraints(runtime, snd_bcm)) < 0)
			return ret;
	}
	
	brtd = kzalloc(sizeof(struct bcm947xx_runtime_data), GFP_KERNEL);
	if (brtd == NULL) {
		return -ENOMEM;
	}

	spin_lock_init(&brtd->lock);

	runtime->private_data = brtd;

	/* probably should put this somewhere else, after setting up isr ??? */
	/* Enable appropriate channel. */
	/* Channel dma_XXXinit needs to be called before descriptors can be
	 * posted to the DMA.  Posting currently occurs in the copy operator,
	 * which is called after prepare but before trigger(start).
	*/
	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
		dma_rxreset(snd_bcm->di[0]);
		dma_rxinit(snd_bcm->di[0]);
	} else {
		dma_txreset(snd_bcm->di[0]);
		dma_txinit(snd_bcm->di[0]);
		if (BCM947XX_DMA_LOOPBACK_ENABLED)
			dma_fifoloopbackenable(snd_bcm->di[0]);
//		dma_txsuspend(snd_bcm->di[0]);
	}

	if (BCM947XX_PCM_DEBUG_ON) {
		DBG("%s: i2s devcontrol 0x%x devstatus 0x%x\n", __FUNCTION__,
			R_REG(snd_bcm->osh, &snd_bcm->regs->devcontrol),
			R_REG(snd_bcm->osh, &snd_bcm->regs->devstatus));
		DBG("%s: i2s intstatus 0x%x intmask 0x%x\n", __FUNCTION__,
			R_REG(snd_bcm->osh, &snd_bcm->regs->intstatus),
			R_REG(snd_bcm->osh, &snd_bcm->regs->intmask));
		DBG("%s: i2s control 0x%x\n", __FUNCTION__,
			R_REG(snd_bcm->osh, &snd_bcm->regs->i2scontrol));
		DBG("%s: i2s clkdivider 0x%x txplayth 0x%x\n", __FUNCTION__,
			R_REG(snd_bcm->osh, &snd_bcm->regs->clkdivider),
			R_REG(snd_bcm->osh, &snd_bcm->regs->txplayth));
		DBG("%s: i2s stxctrl 0x%x\n", __FUNCTION__,
			R_REG(snd_bcm->osh, &snd_bcm->regs->stxctrl));

		{
		uint32 temp;
		temp = R_REG(snd_bcm->osh, &snd_bcm->regs->fifocounter);
		DBG("%s: i2s txcnt 0x%x rxcnt 0x%x\n", __FUNCTION__,
			(temp & I2S_FC_TX_CNT_MASK)>> I2S_FC_TX_CNT_SHIFT,
			(temp & I2S_FC_RX_CNT_MASK)>> I2S_FC_RX_CNT_SHIFT);
		}
	}

	return 0;
}
/* Maybe called from snd_period_elapsed. */
static int bcm947xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	bcm947xx_i2s_info_t *snd_bcm = rtd->dai->cpu_dai->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct bcm947xx_runtime_data *brtd = runtime->private_data;
	uint32 intmask = R_REG(snd_bcm->osh, &snd_bcm->regs->intmask);
	int ret = 0;
	
	DBG("%s %s w/cmd=%d\n", __FUNCTION__, bcm947xx_direction_str(substream), cmd);

	spin_lock(&brtd->lock);

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
	case SNDRV_PCM_TRIGGER_RESUME:
		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
			brtd->bytes_pending = snd_pcm_lib_buffer_bytes(substream);
			bcm947xx_pcm_enqueue(substream);
		} else {
//			dma_txresume(snd_bcm->di[0]);
		}
		break;

	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
//			dma_txsuspend(snd_bcm->di[0]);
			break;
		}
		/* fall-thru */

	case SNDRV_PCM_TRIGGER_STOP:
		/* Reset the disable interrupts, DMA RX/TX channel.
		   Might get here as a result of calling snd_pcm_period_elapsed.
		*/
		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
			intmask &= ~intmask_capture;
			W_REG(snd_bcm->osh, &snd_bcm->regs->intmask, intmask);
			dma_rxreset(snd_bcm->di[0]);
			dma_rxreclaim(snd_bcm->di[0]);
			dma_rxinit(snd_bcm->di[0]);
		} else {
			/* Disable transmit interrupts. */
			intmask &= ~intmask_playback;
			W_REG(snd_bcm->osh, &snd_bcm->regs->intmask, intmask);
			dma_txreset(snd_bcm->di[0]);
			dma_txreclaim(snd_bcm->di[0], HNDDMA_RANGE_ALL);
			dma_txinit(snd_bcm->di[0]);
			if (BCM947XX_DMA_LOOPBACK_ENABLED)
				dma_fifoloopbackenable(snd_bcm->di[0]);
//			dma_txsuspend(snd_bcm->di[0]);
		}
		break;
	default:	
		ret = -EINVAL;
	}

	spin_unlock(&brtd->lock);

	DBG("%s: i2s intstatus 0x%x intmask 0x%x\n", __FUNCTION__,
	    R_REG(snd_bcm->osh, &snd_bcm->regs->intstatus),
	    R_REG(snd_bcm->osh, &snd_bcm->regs->intmask));

	return ret;
}
Beispiel #3
0
/*
 * Initialize all the chip registers.  If dma mode, init tx and rx dma engines
 * but leave the devcontrol tx and rx (fifos) disabled.
 */
static void
chipinit(struct bcm4xxx *ch, uint options)
{
	etc_info_t *etc;
	bcmenetregs_t *regs;
	uint idx;
	uint i;

	regs = ch->regs;
	etc = ch->etc;
	idx = 0;

	ET_TRACE(("et%d: chipinit\n", etc->unit));

	/* enable crc32 generation */
	OR_REG(ch->osh, &regs->emaccontrol, EMC_CG);

	/* enable one rx interrupt per received frame */
	W_REG(ch->osh, &regs->intrecvlazy, (1 << IRL_FC_SHIFT));

	/* enable 802.3x tx flow control (honor received PAUSE frames) */
	W_REG(ch->osh, &regs->rxconfig, ERC_FE | ERC_UF);

	/* initialize CAM */
	if (etc->promisc || (R_REG(ch->osh, &regs->rxconfig) & ERC_CA))
		OR_REG(ch->osh, &regs->rxconfig, ERC_PE);
	else {
		/* our local address */
		chipwrcam(ch, &etc->cur_etheraddr, idx++);

		/* allmulti or a list of discrete multicast addresses */
		if (etc->allmulti)
			OR_REG(ch->osh, &regs->rxconfig, ERC_AM);
		else if (etc->nmulticast) {
			for (i = 0; i < etc->nmulticast; i++)
				chipwrcam(ch, &etc->multicast[i], idx++);
		}

		/* enable cam */
		OR_REG(ch->osh, &regs->camcontrol, CC_CE);
	}

	/* optionally enable mac-level loopback */
	if (etc->loopbk)
		OR_REG(ch->osh, &regs->rxconfig, ERC_LE);

	/* set max frame lengths - account for possible vlan tag */
	W_REG(ch->osh, &regs->rxmaxlength, ETHER_MAX_LEN + 32);
	W_REG(ch->osh, &regs->txmaxlength, ETHER_MAX_LEN + 32);

	/* set tx watermark */
	W_REG(ch->osh, &regs->txwatermark, 56);

	/*
	 * Optionally, disable phy autonegotiation and force our speed/duplex
	 * or constrain our advertised capabilities.
	 */
	if (etc->forcespeed != ET_AUTO)
		chipphyforce(ch, etc->phyaddr);
	else if (etc->advertise && etc->needautoneg)
		chipphyadvertise(ch, etc->phyaddr);

	if (options & ET_INIT_FULL) {
		/* initialize the tx and rx dma channels */
		dma_txinit(ch->di);
		dma_rxinit(ch->di);

		/* post dma receive buffers */
		dma_rxfill(ch->di);

		/* lastly, enable interrupts */
		if (options & ET_INIT_INTRON)
			et_intrson(etc->et);
	}
	else
		dma_rxenable(ch->di);

	/* turn on the emac */
	OR_REG(ch->osh, &regs->enetcontrol, EC_EE);
}