static int bcm947xx_pcm_close(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 bcm947xx_runtime_data *brtd = substream->runtime->private_data; DBG("%s %s\n", __FUNCTION__, bcm947xx_direction_str(substream)); 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)); /* #if required because dma_dump is unavailable in non-debug builds. */ #if BCM947XX_DUMP_RING_BUFFER_ON_PCM_CLOSE_ON { /* dump dma rings to console */ #if !defined(FIFOERROR_DUMP_SIZE) #define FIFOERROR_DUMP_SIZE 8192 #endif char *tmp; struct bcmstrbuf b; if (snd_bcm->di[0] && (tmp = MALLOC(snd_bcm->osh, FIFOERROR_DUMP_SIZE))) { bcm_binit(&b, tmp, FIFOERROR_DUMP_SIZE); dma_dump(snd_bcm->di[0], &b, TRUE); printbig(tmp); MFREE(snd_bcm->osh, tmp, FIFOERROR_DUMP_SIZE); } } #endif /* BCM947XX_DUMP_RING_BUFFER_ON_PCM_CLOSE_ON */ /* reclaim all descriptors */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { dma_rxreset(snd_bcm->di[0]); dma_rxreclaim(snd_bcm->di[0]); } else { dma_txreset(snd_bcm->di[0]); dma_txreclaim(snd_bcm->di[0], HNDDMA_RANGE_ALL); } if (brtd) kfree(brtd); else DBG("%s: called with brtd == NULL\n", __FUNCTION__); 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; }
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; }
static void chipreset(struct bcm4xxx *ch) { bcmenetregs_t *regs; uint32 clk, mdc; ET_TRACE(("et%d: chipreset\n", ch->etc->unit)); regs = ch->regs; if (!si_iscoreup(ch->sih)) { if (!ch->etc->nicmode) si_pci_setup(ch->sih, (1 << si_coreidx(ch->sih))); /* power on reset: reset the enet core */ si_core_reset(ch->sih, 0, 0); goto chipinreset; } /* read counters before resetting the chip */ if (ch->mibgood) chipstatsupd(ch); /* reset the tx dma engine */ if (ch->di) dma_txreset(ch->di); /* set emac into loopback mode to ensure no rx traffic */ W_REG(ch->osh, ®s->rxconfig, ERC_LE); OSL_DELAY(1); /* reset the rx dma engine */ if (ch->di) dma_rxreset(ch->di); /* reset core */ si_core_reset(ch->sih, 0, 0); chipinreset: /* must clear mib registers by hand */ W_REG(ch->osh, ®s->mibcontrol, EMC_RZ); (void) R_REG(ch->osh, ®s->mib.tx_broadcast_pkts); (void) R_REG(ch->osh, ®s->mib.tx_multicast_pkts); (void) R_REG(ch->osh, ®s->mib.tx_len_64); (void) R_REG(ch->osh, ®s->mib.tx_len_65_to_127); (void) R_REG(ch->osh, ®s->mib.tx_len_128_to_255); (void) R_REG(ch->osh, ®s->mib.tx_len_256_to_511); (void) R_REG(ch->osh, ®s->mib.tx_len_512_to_1023); (void) R_REG(ch->osh, ®s->mib.tx_len_1024_to_max); (void) R_REG(ch->osh, ®s->mib.tx_jabber_pkts); (void) R_REG(ch->osh, ®s->mib.tx_oversize_pkts); (void) R_REG(ch->osh, ®s->mib.tx_fragment_pkts); (void) R_REG(ch->osh, ®s->mib.tx_underruns); (void) R_REG(ch->osh, ®s->mib.tx_total_cols); (void) R_REG(ch->osh, ®s->mib.tx_single_cols); (void) R_REG(ch->osh, ®s->mib.tx_multiple_cols); (void) R_REG(ch->osh, ®s->mib.tx_excessive_cols); (void) R_REG(ch->osh, ®s->mib.tx_late_cols); (void) R_REG(ch->osh, ®s->mib.tx_defered); (void) R_REG(ch->osh, ®s->mib.tx_carrier_lost); (void) R_REG(ch->osh, ®s->mib.tx_pause_pkts); (void) R_REG(ch->osh, ®s->mib.rx_broadcast_pkts); (void) R_REG(ch->osh, ®s->mib.rx_multicast_pkts); (void) R_REG(ch->osh, ®s->mib.rx_len_64); (void) R_REG(ch->osh, ®s->mib.rx_len_65_to_127); (void) R_REG(ch->osh, ®s->mib.rx_len_128_to_255); (void) R_REG(ch->osh, ®s->mib.rx_len_256_to_511); (void) R_REG(ch->osh, ®s->mib.rx_len_512_to_1023); (void) R_REG(ch->osh, ®s->mib.rx_len_1024_to_max); (void) R_REG(ch->osh, ®s->mib.rx_jabber_pkts); (void) R_REG(ch->osh, ®s->mib.rx_oversize_pkts); (void) R_REG(ch->osh, ®s->mib.rx_fragment_pkts); (void) R_REG(ch->osh, ®s->mib.rx_missed_pkts); (void) R_REG(ch->osh, ®s->mib.rx_crc_align_errs); (void) R_REG(ch->osh, ®s->mib.rx_undersize); (void) R_REG(ch->osh, ®s->mib.rx_crc_errs); (void) R_REG(ch->osh, ®s->mib.rx_align_errs); (void) R_REG(ch->osh, ®s->mib.rx_symbol_errs); (void) R_REG(ch->osh, ®s->mib.rx_pause_pkts); (void) R_REG(ch->osh, ®s->mib.rx_nonpause_pkts); ch->mibgood = TRUE; /* * We want the phy registers to be accessible even when * the driver is "downed" so initialize MDC preamble, frequency, * and whether internal or external phy here. */ /* default: 100Mhz SI clock and external phy */ W_REG(ch->osh, ®s->mdiocontrol, 0x94); if (ch->etc->deviceid == BCM47XX_ENET_ID) { /* 47xx chips: find out the clock */ if ((clk = si_clock(ch->sih)) != 0) { mdc = 0x80 | ((clk + (MDC_RATIO / 2)) / MDC_RATIO); W_REG(ch->osh, ®s->mdiocontrol, mdc); } else { ET_ERROR(("et%d: chipreset: Could not figure out backplane clock, " "using 100Mhz\n", ch->etc->unit)); } } /* some chips have internal phy, some don't */ if (!(R_REG(ch->osh, ®s->devcontrol) & DC_IP)) { W_REG(ch->osh, ®s->enetcontrol, EC_EP); } else if (R_REG(ch->osh, ®s->devcontrol) & DC_ER) { AND_REG(ch->osh, ®s->devcontrol, ~DC_ER); OSL_DELAY(100); chipphyinit(ch, ch->etc->phyaddr); } /* clear persistent sw intstatus */ ch->intstatus = 0; }