sound/spi/at73c213.c

Source file repositories/reference/linux-study-clean/sound/spi/at73c213.c

File Facts

System
Linux kernel
Corpus path
sound/spi/at73c213.c
Extension
.c
Size
27693 bytes
Lines
1100
Domain
Driver Families
Bucket
sound/spi
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

struct snd_at73c213 {
	struct snd_card			*card;
	struct snd_pcm			*pcm;
	struct snd_pcm_substream	*substream;
	struct at73c213_board_info	*board;
	int				irq;
	int				period;
	unsigned long			bitrate;
	struct ssc_device		*ssc;
	struct spi_device		*spi;
	u8				spi_wbuffer[2];
	u8				spi_rbuffer[2];
	/* Image of the SPI registers in AT73C213. */
	u8				reg_image[18];
	/* Protect SSC registers against concurrent access. */
	spinlock_t			lock;
	/* Protect mixer registers against concurrent access. */
	struct mutex			mixer_lock;
};

#define get_chip(card) ((struct snd_at73c213 *)card->private_data)

static int
snd_at73c213_write_reg(struct snd_at73c213 *chip, u8 reg, u8 val)
{
	struct spi_message msg;
	struct spi_transfer msg_xfer = {
		.len		= 2,
		.cs_change	= 0,
	};
	int retval;

	spi_message_init(&msg);

	chip->spi_wbuffer[0] = reg;
	chip->spi_wbuffer[1] = val;

	msg_xfer.tx_buf = chip->spi_wbuffer;
	msg_xfer.rx_buf = chip->spi_rbuffer;
	spi_message_add_tail(&msg_xfer, &msg);

	retval = spi_sync(chip->spi, &msg);

	if (!retval)
		chip->reg_image[reg] = val;

	return retval;
}

static struct snd_pcm_hardware snd_at73c213_playback_hw = {
	.info		= SNDRV_PCM_INFO_INTERLEAVED |
			  SNDRV_PCM_INFO_BLOCK_TRANSFER,
	.formats	= SNDRV_PCM_FMTBIT_S16_BE,
	.rates		= SNDRV_PCM_RATE_CONTINUOUS,
	.rate_min	= 8000,  /* Replaced by chip->bitrate later. */
	.rate_max	= 50000, /* Replaced by chip->bitrate later. */
	.channels_min	= 1,
	.channels_max	= 2,
	.buffer_bytes_max = 64 * 1024 - 1,
	.period_bytes_min = 512,
	.period_bytes_max = 64 * 1024 - 1,
	.periods_min	= 4,
	.periods_max	= 1024,
};

/*
 * Calculate and set bitrate and divisions.
 */
static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip)
{
	unsigned long ssc_rate = clk_get_rate(chip->ssc->clk);
	unsigned long dac_rate_new, ssc_div;
	int status;
	unsigned long ssc_div_max, ssc_div_min;
	int max_tries;

	/*
	 * We connect two clocks here, picking divisors so the I2S clocks
	 * out data at the same rate the DAC clocks it in ... and as close
	 * as practical to the desired target rate.
	 *
	 * The DAC master clock (MCLK) is programmable, and is either 256
	 * or (not here) 384 times the I2S output clock (BCLK).
	 */

	/* SSC clock / (bitrate * stereo * 16-bit). */
	ssc_div = ssc_rate / (BITRATE_TARGET * 2 * 16);
	ssc_div_min = ssc_rate / (BITRATE_MAX * 2 * 16);
	ssc_div_max = ssc_rate / (BITRATE_MIN * 2 * 16);
	max_tries = (ssc_div_max - ssc_div_min) / 2;

Annotation

Implementation Notes