Esempio n. 1
0
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);
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
//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;
}
Esempio n. 8
0
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);
}