sound/aoa/soundbus/i2sbus/pcm.c

Source file repositories/reference/linux-study-clean/sound/aoa/soundbus/i2sbus/pcm.c

File Facts

System
Linux kernel
Corpus path
sound/aoa/soundbus/i2sbus/pcm.c
Extension
.c
Size
27694 bytes
Lines
1042
Domain
Driver Families
Bucket
sound/aoa
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 (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_18MHz / (rate * mclk), out)) {
			*out |= I2S_SF_CLOCK_SOURCE_18MHz;
			return 0;
		}
	}
	if (I2S_CLOCK_SPEED_45MHz % (rate * mclk) == 0) {
		if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_45MHz / (rate * mclk), out)) {
			*out |= I2S_SF_CLOCK_SOURCE_45MHz;
			return 0;
		}
	}
	if (I2S_CLOCK_SPEED_49MHz % (rate * mclk) == 0) {
		if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_49MHz / (rate * mclk), out)) {
			*out |= I2S_SF_CLOCK_SOURCE_49MHz;
			return 0;
		}
	}
	return -1;
}

#define CHECK_RATE(rate)						\
	do { if (rates & SNDRV_PCM_RATE_ ##rate) {			\
		int dummy;						\
		if (clock_and_divisors(sysclock_factor,			\
				       bus_factor, rate, &dummy))	\
			rates &= ~SNDRV_PCM_RATE_ ##rate;		\
	} } while (0)

static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
{
	struct pcm_info *pi, *other;
	struct soundbus_dev *sdev;
	int masks_inited = 0, err;
	struct codec_info_item *cii, *rev;
	struct snd_pcm_hardware *hw;
	u64 formats = 0;
	unsigned int rates = 0;
	struct transfer_info v;
	int bus_factor = 0, sysclock_factor = 0;
	int found_this;

	guard(mutex)(&i2sdev->lock);

	get_pcm_info(i2sdev, in, &pi, &other);

	hw = &pi->substream->runtime->hw;
	sdev = &i2sdev->sound;

	if (pi->active) {
		/* alsa messed up */
		return -EBUSY;
	}

	/* we now need to assign the hw */
	list_for_each_entry(cii, &sdev->codec_list, list) {
		struct transfer_info *ti = cii->codec->transfers;
		bus_factor = cii->codec->bus_factor;
		sysclock_factor = cii->codec->sysclock_factor;
		while (ti->formats && ti->rates) {
			v = *ti;
			if (ti->transfer_in == in
			    && cii->codec->usable(cii, ti, &v)) {
				if (masks_inited) {
					formats &= v.formats;
					rates &= v.rates;
				} else {
					formats = v.formats;
					rates = v.rates;
					masks_inited = 1;
				}
			}
			ti++;
		}
	}
	if (!masks_inited || !bus_factor || !sysclock_factor)
		return -ENODEV;
	/* bus dependent stuff */
	hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
		   SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
		   SNDRV_PCM_INFO_JOINT_DUPLEX;

	CHECK_RATE(5512);
	CHECK_RATE(8000);
	CHECK_RATE(11025);
	CHECK_RATE(16000);
	CHECK_RATE(22050);
	CHECK_RATE(32000);
	CHECK_RATE(44100);
	CHECK_RATE(48000);
	CHECK_RATE(64000);

Annotation

Implementation Notes