Ejemplo n.º 1
0
int esa_compr_send_buffer(const size_t copy_size, struct audio_processor *ap)
{
	int ret;

	/* write mp3 data to firmware */
	spin_lock(&si.compr_lock);
	writel(copy_size, si.mailbox + COMPR_SIZE_OF_FRAGMENT);

	ret = esa_compr_send_cmd(CMD_COMPR_WRITE, ap);
	if (ret) {
		esa_err("%s: can't send CMD_COMPR_WRITE (%d)\n",
			__func__, ret);
		spin_unlock(&si.compr_lock);
		return ret;
	}
	spin_unlock(&si.compr_lock);

	return 0;
}
Ejemplo n.º 2
0
static int compr_trigger(struct snd_compr_stream *cstream, int cmd)
{
    struct snd_compr_runtime *runtime = cstream->runtime;
    struct runtime_data *prtd = runtime->private_data;
    unsigned long flags;
    int ret;

    pr_debug("%s: trigger cmd(%d)\n", __func__, cmd);

    /* platform -> codec -> cpu */
    if (cstream->direction != SND_COMPRESS_PLAYBACK) {
        pr_err("%s: Unsupported stream type\n", __func__);
        return -EINVAL;
    }

    switch (cmd) {
    case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
        pr_info("%s: SNDRV_PCM_TRIGGER_PAUSE_PUSH\n", __func__);

        spin_lock_irqsave(&prtd->lock, flags);
        ret = esa_compr_send_cmd(CMD_COMPR_PAUSE, prtd->ap);
        if (ret) {
            pr_err("%s: pause cmd failed(%d)\n", __func__,
                   ret);
            spin_unlock_irqrestore(&prtd->lock, flags);
            return ret;
        }
        spin_unlock_irqrestore(&prtd->lock, flags);
        atomic_set(&prtd->start, 0);
        break;
    case SNDRV_PCM_TRIGGER_STOP:
        pr_info("%s: SNDRV_PCM_TRIGGER_STOP\n", __func__);

        spin_lock_irqsave(&prtd->lock, flags);

        if (atomic_read(&prtd->eos)) {
            /* ALSA Framework callback to notify drain complete */
            snd_compr_drain_notify(cstream);
            atomic_set(&prtd->eos, 0);
            pr_debug("%s: interrupt drain and eos wait queues", __func__);
        }

        pr_debug("CMD_STOP\n");
        prtd->stop_ack = 0;
        ret = esa_compr_send_cmd(CMD_COMPR_STOP, prtd->ap);
        if (ret) {
            pr_err("%s: stop cmd failed (%d)\n",
                   __func__, ret);
            spin_unlock_irqrestore(&prtd->lock, flags);
            return ret;
        }
        spin_unlock_irqrestore(&prtd->lock, flags);

        ret = wait_event_interruptible_timeout(prtd->flush_wait,
                                               prtd->stop_ack, 1 * HZ);
        if (!ret) {
            pr_err("CMD_STOP cmd timeout(%d)\n", ret);
            ret = -ETIMEDOUT;
        } else
            ret = 0;

        ret = compr_dai_cmd(prtd, cmd);
        if (ret) {
            pr_err("%s: compr_dai_cmd fail(%d)\n", __func__, ret);
            return ret;
        }
        atomic_set(&prtd->start, 0);

        /* reset */
        prtd->stop_ack = 0;
        prtd->byte_offset = 0;
        prtd->app_pointer = 0;
        prtd->copied_total = 0;
        prtd->received_total = 0;
        break;
    case SNDRV_PCM_TRIGGER_START:
    case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
        if (SNDRV_PCM_TRIGGER_START == cmd)
            pr_info("%s: SNDRV_PCM_TRIGGER_START\n", __func__);
        else if (SNDRV_PCM_TRIGGER_PAUSE_RELEASE == cmd)
            pr_info("%s: SNDRV_PCM_TRIGGER_PAUSE_RELEASE\n", __func__);

        ret = compr_dai_cmd(prtd, cmd);
        if (ret) {
            pr_err("%s: compr_dai_cmd fail(%d)\n", __func__, ret);
            return ret;
        }
        atomic_set(&prtd->start, 1);
        spin_lock_irqsave(&prtd->lock, flags);
        ret = esa_compr_send_cmd(CMD_COMPR_START, prtd->ap);
        if (ret) {
            pr_err("%s: start cmd failed\n", __func__);
            spin_unlock_irqrestore(&prtd->lock, flags);
            return ret;
        }
        spin_unlock_irqrestore(&prtd->lock, flags);
        break;
    case SND_COMPR_TRIGGER_NEXT_TRACK:
        pr_info("%s: SND_COMPR_TRIGGER_NEXT_TRACK\n", __func__);
        break;
    case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
        pr_info("%s: SND_COMPR_TRIGGER_PARTIAL_DRAIN\n", __func__);
    case SND_COMPR_TRIGGER_DRAIN:
        if (SND_COMPR_TRIGGER_DRAIN == cmd)
            pr_info("%s: SND_COMPR_TRIGGER_DRAIN\n", __func__);
        /* Make sure all the data is sent to F/W before sending EOS */
        spin_lock_irqsave(&prtd->lock, flags);
#ifdef AUDIO_PERF
        prtd->start_time[DRAIN_T] = sched_clock();
#endif
        if (!atomic_read(&prtd->start)) {
            pr_err("%s: stream is not in started state\n",
                   __func__);
            ret = -EPERM;
            spin_unlock_irqrestore(&prtd->lock, flags);
            break;
        }

        atomic_set(&prtd->eos, 1);
        pr_debug("%s: CMD_EOS\n", __func__);
        ret = esa_compr_send_cmd(CMD_COMPR_EOS, prtd->ap);
        if (ret) {
            pr_err("%s: can't send eos (%d)\n", __func__, ret);
            spin_unlock_irqrestore(&prtd->lock, flags);
            return ret;
        }
        spin_unlock_irqrestore(&prtd->lock, flags);
#ifdef AUDIO_PERF
        prtd->end_time[DRAIN_T] = sched_clock();
        prtd->total_time[DRAIN_T] +=
            prtd->end_time[DRAIN_T] - prtd->start_time[DRAIN_T];
#endif
        pr_info("%s: Out of %s Drain", __func__,
                (cmd == SND_COMPR_TRIGGER_DRAIN ? "Full" : "Partial"));
        break;
    default:
        break;
    }

    return 0;
}
Ejemplo n.º 3
0
static int compr_free(struct snd_compr_stream *cstream)
{
    struct snd_compr_runtime *runtime = cstream->runtime;
    struct runtime_data *prtd = runtime->private_data;
    struct snd_pcm_substream *substream;
    struct snd_soc_dai *cpu_dai;
    struct snd_soc_dai *codec_dai;
    const struct snd_soc_dai_ops *cpu_dai_ops;
    const struct snd_soc_dai_ops *codec_dai_ops;
    unsigned long flags;
    int ret;
#ifdef AUDIO_PERF
    u64 playback_time, total_time = 0;
    int idx;
#endif
    pr_debug("%s\n", __func__);

    if (!prtd) {
        pr_info("compress dai has already freed.\n");
        return 0;
    }

    substream = &prtd->substream;
    cpu_dai = prtd->cpu_dai;
    codec_dai = prtd->codec_dai;
    cpu_dai_ops = cpu_dai->driver->ops;
    codec_dai_ops = codec_dai->driver->ops;

    if (atomic_read(&prtd->eos)) {
        /* ALSA Framework callback to notify drain complete */
        snd_compr_drain_notify(cstream);
        atomic_set(&prtd->eos, 0);
        pr_debug("%s Call Drain notify to wakeup\n", __func__);
    }

    if (atomic_read(&prtd->created)) {
        spin_lock_irqsave(&prtd->lock, flags);
        atomic_set(&prtd->created, 0);
        prtd->exit_ack = 0;
        ret = esa_compr_send_cmd(CMD_COMPR_DESTROY, prtd->ap);
        if (ret) {
            esa_err("%s: can't send CMD_COMPR_DESTROY (%d)\n",
                    __func__, ret);
            spin_unlock_irqrestore(&prtd->lock, flags);
        } else {
            spin_unlock_irqrestore(&prtd->lock, flags);
            ret = wait_event_interruptible_timeout(prtd->exit_wait,
                                                   prtd->exit_ack, 1 * HZ);
            if (!ret)
                pr_err("%s: CMD_DESTROY timed out!!!\n", __func__);
        }
    }

#ifdef CONFIG_SND_ESA_SA_EFFECT
    aud_vol.ap[COMPR_DAI_MULTIMEDIA_1] = NULL;
#endif
    esa_compr_set_state(false);
    /* codec hw_free -> cpu hw_free ->
       cpu shutdown -> codec shutdown */
    if (codec_dai_ops->hw_free)
        (*codec_dai_ops->hw_free)(substream, codec_dai);

    if (cpu_dai_ops->hw_free)
        (*cpu_dai_ops->hw_free)(substream, cpu_dai);

    if (cpu_dai_ops->shutdown)
        (*cpu_dai_ops->shutdown)(substream, cpu_dai);

    if (codec_dai_ops->shutdown)
        (*codec_dai_ops->shutdown)(substream, codec_dai);

    if (substream->runtime)
        kfree(substream->runtime->hw_constraints.rules);
    kfree(substream->runtime);
    esa_compr_close();
#ifdef AUDIO_PERF
    prtd->end_time[OPEN_T] = sched_clock();
    playback_time = prtd->end_time[OPEN_T] - prtd->start_time[OPEN_T];

    for (idx = 0; idx < TOTAL_TIMES; idx++) {
        total_time += prtd->total_time[idx];
    }
    pr_debug("%s: measure the audio waken time : %llu\n", __func__,
             total_time);
    pr_debug("%s: may be the ap sleep time : (%llu/%llu)\n", __func__,
             playback_time - total_time, playback_time);
#endif
    kfree(prtd->ap);
    kfree(prtd);
    return 0;
}
Ejemplo n.º 4
0
int esa_compr_set_param(struct audio_processor* ap, uint8_t **buffer)
{
	unsigned int ip_type;
	unsigned char *ibuf;
	u32 ibuf_ca5_pa;
	u32 ibuf_offset;
	int ret;

	ptr_ap = ap;
	/* initialize in buffer */
	/* use free area in dram */
	ibuf = si.fwarea[1];
	ap->block_num = 1;

	/* calculate the physical address */
	ibuf_offset = ibuf - si.fwarea[ap->block_num];
	ibuf_ca5_pa = ibuf_offset + FWAREA_SIZE * ap->block_num;

	/* set buffer information at mailbox */
	spin_lock(&si.lock);
	writel(ap->buffer_size, si.mailbox + COMPR_SIZE_OF_INBUF);
	writel(ibuf_ca5_pa, si.mailbox + COMPR_PHY_ADDR_INBUF);
	writel(ap->sample_rate, si.mailbox + COMPR_PARAM_SAMPLE);
	writel(ap->num_channels, si.mailbox + COMPR_PARAM_CH);

	ip_type = ap->codec_id << 16;
	writel(ip_type, si.mailbox + COMPR_IP_TYPE);
	spin_unlock(&si.lock);

	si.isr_compr_created = 0;
	ret = esa_compr_send_cmd(CMD_COMPR_SET_PARAM, ap);
	if (ret) {
		esa_err("%s: can't send CMD_COMPR_SET_PARAM (%d)\n",
			__func__, ret);
		return ret;
	}

	/* wait until the parameter is set up */
	ret = wait_event_interruptible_timeout(esa_wq, si.isr_compr_created, HZ * 2);
	if (!ret) {
		esa_err("%s: compress set param timed out!!! (%d)\n",
			__func__, ret);
		writel(0, si.mailbox + COMPR_INTR_ACK);
		esa_dump_fw_log();
		si.fw_use_dram = true;
		ptr_ap = NULL;
		return -EBUSY;
	}

	/* created instance */
	ap->handle_id = readl(si.mailbox + COMPR_IP_ID);
	esa_info("%s: codec id:0x%x, ret_val:0x%x, handle_id:0x%x\n",
		__func__, (unsigned int)ap->codec_id,
		readl(si.mailbox + COMPR_RETURN_CMD),
		(unsigned int)ap->handle_id);

	/* return the buffer address for caller */
	*buffer = ibuf;
	esa_info("%s: allocated buffer address (0x%p), size(0x%x)\n",
		__func__, *buffer, ap->buffer_size);
#ifdef CONFIG_SND_ESA_SA_EFFECT
	si.effect_on = false;
#endif
	return 0;
}