sound/soc/fsl/imx-pcm-rpmsg.c

Source file repositories/reference/linux-study-clean/sound/soc/fsl/imx-pcm-rpmsg.c

File Facts

System
Linux kernel
Corpus path
sound/soc/fsl/imx-pcm-rpmsg.c
Extension
.c
Size
24163 bytes
Lines
843
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!rpmsg->force_lpa) {
			if (runtime->info & SNDRV_PCM_INFO_PAUSE)
				ret = imx_rpmsg_pause(component, substream);
			else
				ret = imx_rpmsg_terminate_all(component, substream);
		}
		break;
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		ret = imx_rpmsg_pause(component, substream);
		break;
	case SNDRV_PCM_TRIGGER_STOP:
		ret = imx_rpmsg_terminate_all(component, substream);
		break;
	default:
		return -EINVAL;
	}

	if (ret)
		return ret;

	return 0;
}

/*
 * imx_rpmsg_pcm_ack
 *
 * Send the period index to M core through rpmsg, but not send
 * all the period index to M core, reduce some unnessesary msg
 * to reduce the pressure of rpmsg bandwidth.
 */
static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
			     struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
	struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
	struct rpmsg_info *info = dev_get_drvdata(component->dev);
	snd_pcm_uframes_t period_size = runtime->period_size;
	snd_pcm_sframes_t avail;
	struct timer_list *timer;
	struct rpmsg_msg *msg;
	unsigned long flags;
	int buffer_tail = 0;
	int written_num;

	if (!rpmsg->force_lpa)
		return 0;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
		msg->s_msg.header.cmd = TX_PERIOD_DONE;
	} else {
		msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
		msg->s_msg.header.cmd = RX_PERIOD_DONE;
	}

	msg->s_msg.header.type = MSG_TYPE_C;

	buffer_tail = (frames_to_bytes(runtime, runtime->control->appl_ptr) %
		       snd_pcm_lib_buffer_bytes(substream));
	buffer_tail = buffer_tail / snd_pcm_lib_period_bytes(substream);

	/* There is update for period index */
	if (buffer_tail != msg->s_msg.param.buffer_tail) {
		written_num = buffer_tail - msg->s_msg.param.buffer_tail;
		if (written_num < 0)
			written_num += runtime->periods;

		msg->s_msg.param.buffer_tail = buffer_tail;

		/* The notification message is updated to latest */
		spin_lock_irqsave(&info->lock[substream->stream], flags);
		memcpy(&info->notify[substream->stream], msg,
		       sizeof(struct rpmsg_s_msg));
		info->notify_updated[substream->stream] = true;
		spin_unlock_irqrestore(&info->lock[substream->stream], flags);

		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
			avail = snd_pcm_playback_hw_avail(runtime);
		else
			avail = snd_pcm_capture_hw_avail(runtime);

		timer = &info->stream_timer[substream->stream].timer;
		/*
		 * If the data in the buffer is less than one period before
		 * this fill, which means the data may not enough on M
		 * core side, we need to send message immediately to let
		 * M core know the pointer is updated.
		 * if there is more than one period data in the buffer before

Annotation

Implementation Notes