static int s3c_dma_prepare(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; int ret = 0; pr_debug("Entered %s\n", __func__); if (!prtd->params) return 0; /* channel needs configuring for mem=>device, increment memory addr, * sync to pclk, half-word transfers to the IIS-FIFO. */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_MEM, prtd->params->dma_addr); } else { s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_HW, prtd->params->dma_addr); } s3c2410_dma_config(prtd->params->channel, prtd->params->dma_size); /* flush the DMA channel */ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); prtd->dma_loaded = 0; prtd->dma_pos = prtd->dma_start; /* enqueue dma buffers */ s3c_dma_enqueue(substream); return ret; }
static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, void *dev_id, int size, enum s3c2410_dma_buffresult result) { struct snd_pcm_substream *substream = dev_id; struct s3c24xx_runtime_data *prtd; pr_debug("Entered %s\n", __func__); if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) return; prtd = substream->runtime->private_data; if (substream) snd_pcm_period_elapsed(substream); spin_lock(&prtd->lock); if (prtd->state & ST_RUNNING /*&& !s3c_dma_has_circular()*/) { //sayanta commented..need to check functionality it return FALSE anyway prtd->dma_loaded--; s3c_dma_enqueue(substream); } spin_unlock(&prtd->lock); }
static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, void *dev_id, int size, enum s3c2410_dma_buffresult result) { struct snd_pcm_substream *substream = dev_id; struct s3c24xx_runtime_data *prtd; pr_debug("Entered %s\n", __func__); if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) return; prtd = substream->runtime->private_data; if (substream) snd_pcm_period_elapsed(substream); spin_lock(&prtd->lock); if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { prtd->dma_loaded--; #ifndef NEW_DMA s3c_dma_enqueue(substream); #endif } spin_unlock(&prtd->lock); }
static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, void *dev_id, int size, enum s3c2410_dma_buffresult result) { struct snd_pcm_substream *substream = dev_id; struct s3c24xx_runtime_data *prtd; pr_debug("Entered %s\n", __func__); if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) return; prtd = substream->runtime->private_data; /* By Jung */ prtd->dma_pos += prtd->dma_period; if (prtd->dma_pos >= prtd->dma_end) prtd->dma_pos = prtd->dma_start; //if (substream) //fixed 68937 (REVERSE_INULL) prevent defect snd_pcm_period_elapsed(substream); spin_lock(&prtd->lock); if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { s3c_dma_enqueue(substream); } spin_unlock(&prtd->lock); }
static int s3c_dma_prepare(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; int ret = 0; pr_debug("Entered %s\n", __func__); /* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!prtd->params) return 0; /* channel needs configuring for mem=>device, increment memory addr, * sync to pclk, half-word transfers to the IIS-FIFO. */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_MEM, prtd->params->dma_addr); } else { s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_HW, prtd->params->dma_addr); } s3c2410_dma_config(prtd->params->channel, prtd->params->dma_size); /* To fix the pcm buffer underrun in case of high busy state ( ex. Starting broswer ) 2010.06.22*/ if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ring_buf_index = 0; period_index = 0; } /* flush the DMA channel */ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); prtd->dma_loaded = 0; prtd->dma_pos = prtd->dma_start; /* enqueue dma buffers */ s3c_dma_enqueue(substream); return ret; }
//static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, // void *dev_id, int size, // enum s3c2410_dma_buffresult result) static void audio_buffdone(void *data) { //struct snd_pcm_substream *substream = dev_id; //struct s3c24xx_runtime_data *prtd; struct snd_pcm_substream *substream = data; struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; pr_debug("Entered %s\n", __func__); //if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) // return; // //prtd = substream->runtime->private_data; if (prtd->state & ST_RUNNING) { prtd->dma_pos += prtd->dma_period; if (prtd->dma_pos >= prtd->dma_end) prtd->dma_pos = prtd->dma_start; //if (substream) // snd_pcm_period_elapsed(substream); if (substream) snd_pcm_period_elapsed(substream); //spin_lock(&prtd->lock); //if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { // prtd->dma_loaded--; // s3c_dma_enqueue(substream); //} spin_lock(&prtd->lock); if (!samsung_dma_has_circular()) { prtd->dma_loaded--; s3c_dma_enqueue(substream); } spin_unlock(&prtd->lock); } //spin_unlock(&prtd->lock); }
static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; int ret = 0; pr_debug("Entered %s\n", __func__); spin_lock(&prtd->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: s3c_dma_enqueue(substream); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: prtd->state |= ST_RUNNING; s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); break; case SNDRV_PCM_TRIGGER_SUSPEND: if (prtd->dma_loaded) prtd->dma_loaded--; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: prtd->state &= ~ST_RUNNING; s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP); break; default: ret = -EINVAL; break; } spin_unlock(&prtd->lock); return ret; }
static void s3c_sdi_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct s3c_sdi_host *host = mmc_priv(mmc); u32 sdi_carg, sdi_ccon, sdi_timer, sdi_fsta; u32 sdi_bsize, sdi_dcon = 0, sdi_imsk; u32 dma_dir = 0; unsigned long complete_timeout = msecs_to_jiffies( 1000 ); // 1000 msec timeout on wait for command completion WARN_ON(host->mrq != NULL); DBG("#############request: [CMD] opcode:0x%02x arg:0x%08x flags:%x retries:%u\n", mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags, mrq->cmd->retries); host->mrq = mrq; sdi_ccon = mrq->cmd->opcode & S3C_SDICCON_INDEX; sdi_ccon|= (S3C_SDICCON_SENDERHOST | S3C_SDICCON_CMDSTART); #ifdef CONFIG_S3CMCI_DEBUG { cmd_rec[cmd_idx] = mrq->cmd->opcode; cmd_idx++; cmd_idx %= 40; } #endif sdi_carg = mrq->cmd->arg; /* XXX: Timer value ?! */ /* If the workaround for read is enabled, change the timer value. */ if( host->ena_2410_workaround ) sdi_timer=0xFFFF; else sdi_timer= 0x7fffff; sdi_bsize= 0; /* enable interrupts for transmission errors */ sdi_imsk = (S3C_SDIIMSK_RESPONSEND | S3C_SDIIMSK_CRCSTATUS); host->complete_what = COMPLETION_CMDSENT; if (RSP_TYPE(mmc_resp_type(mrq->cmd))) { host->complete_what = COMPLETION_RSPFIN; sdi_ccon |= S3C_SDICCON_WAITRSP; sdi_imsk |= S3C_SDIIMSK_CMDTIMEOUT; } else { /* We need the CMDSENT-Interrupt only if we want are not waiting * for a response */ sdi_imsk |= S3C_SDIIMSK_CMDSENT; } if (mrq->cmd->flags & MMC_RSP_136) { sdi_ccon|= S3C_SDICCON_LONGRSP; } if (mrq->cmd->flags & MMC_RSP_CRC) { sdi_imsk |= S3C_SDIIMSK_RESPONSECRC; } if (mrq->data) { host->complete_what = COMPLETION_XFERFINISH_RSPFIN; sdi_ccon|= S3C_SDICCON_WITHDATA; sdi_bsize = mrq->data->blksz; sdi_dcon = (mrq->data->blocks & S3C_SDIDCON_BLKNUM_MASK); sdi_dcon |= S3C_SDIDCON_DMAEN; if( !host->ena_2410_workaround ) sdi_dcon |= S3C_SDIDCON_WORDTX; if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) { sdi_dcon |= S3C_SDIDCON_WIDEBUS; } sdi_imsk |= 0xFFFFFFE0; DBG(PFX "request: [DAT] bsize:%u blocks:%u bytes:%u\n", sdi_bsize, mrq->data->blocks, mrq->data->blocks * sdi_bsize); if (!(mrq->data->flags & MMC_DATA_STREAM)) { sdi_dcon |= S3C_SDIDCON_BLOCKMODE; } if (mrq->data->flags & MMC_DATA_WRITE) { sdi_dcon |= S3C_SDIDCON_TXAFTERRESP; sdi_dcon |= S3C_SDIDCON_XFER_TX; if( !host->ena_2410_workaround ) sdi_dcon |= S3C_SDIDCON_DSTART; s3c_sdi_dma_setup(host, DMAP_WRITE); dma_dir = DMA_TO_DEVICE; } else { sdi_dcon |= S3C_SDIDCON_RXAFTERCMD; sdi_dcon |= S3C_SDIDCON_XFER_RX; if( !host->ena_2410_workaround ) sdi_dcon |= S3C_SDIDCON_DSTART; s3c_sdi_dma_setup(host, DMAP_READ); dma_dir = DMA_FROM_DEVICE; } /* Clear FAIL bits also for the fifo. */ sdi_fsta = S3C_SDIFSTA_FRST | S3C_SDIFSTA_FIFOFAIL; __raw_writel(sdi_fsta,host->base + S3C_SDIFSTA); /* start DMA */ dma_map_sg(mmc_dev(mmc), mrq->data->sg, mrq->data->sg_len, dma_dir); #ifdef CONFIG_ARCH_MDIRAC3 s3c_dma_enqueue(host->dma,host->subchannel,(void *) host, sg_dma_address(mrq->data->sg), (mrq->data->blocks * mrq->data->blksz) ); #else s3c_dma_enqueue(host->dma, (void *) host, sg_dma_address(mrq->data->sg), (mrq->data->blocks * mrq->data->blksz) ); #endif /* Check if we should enable the workaround for timeouts in the 2410 soc. */ /* Since we want to go as fast as possible, don't use the maximum divider.*/ /* dividing by 90 will give a clock of roughly 553MHz. This should be safe*/ /* enough. */ host->prescaler=readl( host->base + S3C_SDIPRE ); if( host->ena_2410_workaround && (mrq->data->flags & MMC_DATA_READ) ) writel( (clk_get_rate( host->clk )/533000), host->base + S3C_SDIPRE ); } host->mrq = mrq; init_completion(&host->complete_request); init_completion(&host->complete_dma); /* Clear command and data status registers */ writel(0xFFFFFFFF, host->base + S3C_SDICSTA); writel(0xFFFFFFFF, host->base + S3C_SDIDSTA); /* Setup SDI controller */ writel(sdi_bsize,host->base + S3C_SDIBSIZE); writel(sdi_timer,host->base + S3C_SDITIMER); writel(sdi_imsk,host->base + S3C_SDIIMSK); /* Setup SDI command argument and data control */ writel(sdi_carg, host->base + S3C_SDICARG); writel(sdi_dcon, host->base + S3C_SDIDCON); /* This initiates transfer */ writel(sdi_ccon, host->base + S3C_SDICCON); /* Workaround for S3C2410. When the receive transfer has started we can write the */ /* original prescaler back to transfer at maximum speed. Talk about a dirty hack...*/ if( host->ena_2410_workaround && (mrq->data != NULL) && (mrq->data->flags & MMC_DATA_READ) ) { /* Start polling if the receive transfer has started.... */ while( ((readl( host->base + S3C_SDIFSTA ) & 0x7F) == 0) && ((readl( host->base + S3C_SDIDSTA ) & 0x30) == 0) ) { /* Ensure that if an error occurs, we can still exit. */ if( readl( host->base + S3C_SDIDSTA ) & (S3C_SDIDSTA_FIFOFAIL | S3C_SDIDSTA_CRCFAIL | S3C_SDIDSTA_RXCRCFAIL | S3C_SDIDSTA_DATATIMEOUT | S3C_SDIDSTA_SBITERR) ) break; } writel( host->prescaler, host->base + S3C_SDIPRE ); } /* this wait is very important to sd/mmc run correctly. * Without this blocking code, operation sequence may be crashed. * by scsuh. */ /* Wait for transfer to complete */ wait_for_completion_timeout(&host->complete_request, complete_timeout); if (mrq->data && (host->mrq->data->error == MMC_ERR_NONE)) { if (wait_for_completion_timeout(&host->complete_dma, complete_timeout) == 0) { #ifdef CONFIG_ARCH_MDIRAC3 s3c_dma_ctrl(host->dma,host->subchannel, S3C_DMAOP_FLUSH); #else s3c_dma_ctrl(host->dma, S3C_DMAOP_FLUSH); #endif } DBG("[DAT] DMA complete.\n"); sdi_fsta = readl(host->base + S3C_SDIFSTA); writel(sdi_fsta,host->base + S3C_SDIFSTA); } /* Cleanup controller */ writel(0, host->base + S3C_SDICARG); writel(0, host->base + S3C_SDIDCON); writel(0, host->base + S3C_SDICCON); writel(0, host->base + S3C_SDIIMSK); /* Read response */ mrq->cmd->resp[0] = readl(host->base + S3C_SDIRSP0); mrq->cmd->resp[1] = readl(host->base + S3C_SDIRSP1); mrq->cmd->resp[2] = readl(host->base + S3C_SDIRSP2); mrq->cmd->resp[3] = readl(host->base + S3C_SDIRSP3); host->mrq = NULL; DBG(PFX "request done.\n"); if (mrq->data) { dma_unmap_sg(mmc_dev(mmc), mrq->data->sg, mrq->data->sg_len, dma_dir); /* Calculate the about of bytes transfer, but only if there was * no error */ if (mrq->data->error == MMC_ERR_NONE) mrq->data->bytes_xfered = (mrq->data->blocks * mrq->data->blksz); else mrq->data->bytes_xfered = 0; /* If we had an error while transferring data we flush the * DMA channel to clear out any garbage */ if (mrq->data->error != MMC_ERR_NONE) { #ifdef CONFIG_ARCH_MDIRAC3 s3c_dma_ctrl(host->dma,host->subchannel, S3C_DMAOP_FLUSH); #else s3c_dma_ctrl(host->dma, S3C_DMAOP_FLUSH); #endif DBG(PFX "flushing DMA.\n"); } /* Issue stop command */ if (mrq->data->stop) mmc_wait_for_cmd(mmc, mrq->data->stop, 3); } mrq->done(mrq); }