linux/sound/soc/google/chv3-i2s.c

// SPDX-License-Identifier: GPL-2.0-only
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>

#include <sound/soc.h>

/*
 * The I2S interface consists of two ring buffers - one for RX and one for
 * TX.  A ring buffer has a producer index and a consumer index. Depending
 * on which way the data is flowing, either the software or the hardware
 * writes data and updates the producer index, and the other end reads data
 * and updates the consumer index.
 *
 * The pointer managed by software is updated using the .ack callback
 * (see chv3_dma_ack). This seems to be the only way to reliably obtain
 * the appl_ptr from within the driver and pass it to hardware.
 *
 * Because of the two pointer design, the ring buffer can never be full. With
 * capture this isn't a problem, because the hardware being the producer
 * will wait for the consumer index to move out of the way.  With playback,
 * however, this is problematic, because ALSA wants to fill up the buffer
 * completely when waiting for hardware. In the .ack callback, the driver
 * would have to wait for the consumer index to move out of the way by
 * busy-waiting, which would keep stalling the kernel for quite a long time.
 *
 * The workaround to this problem is to "lie" to ALSA that the hw_pointer
 * is one frame behind what it actually is (see chv3_dma_pointer). This
 * way, ALSA will not try to fill up the entire buffer, and all callbacks
 * are wait-free.
 */

#define I2S_TX_ENABLE
#define I2S_TX_BASE_ADDR
#define I2S_TX_BUFFER_SIZE
#define I2S_TX_PRODUCER_IDX
#define I2S_TX_CONSUMER_IDX
#define I2S_RX_ENABLE
#define I2S_RX_BASE_ADDR
#define I2S_RX_BUFFER_SIZE
#define I2S_RX_PRODUCER_IDX
#define I2S_RX_CONSUMER_IDX

#define I2S_SOFT_RESET
#define I2S_SOFT_RESET_RX_BIT
#define I2S_SOFT_RESET_TX_BIT

#define I2S_RX_IRQ
#define I2S_RX_IRQ_CONST
#define I2S_TX_IRQ
#define I2S_TX_IRQ_CONST

#define I2S_IRQ_MASK
#define I2S_IRQ_CLR
#define I2S_IRQ_RX_BIT
#define I2S_IRQ_TX_BIT

#define I2S_MAX_BUFFER_SIZE

struct chv3_i2s_dev {};

static struct snd_soc_dai_driver chv3_i2s_dai =;

static const struct snd_pcm_hardware chv3_dma_hw =;

static inline void chv3_i2s_wr(struct chv3_i2s_dev *i2s, int offset, u32 val)
{}

static inline u32 chv3_i2s_rd(struct chv3_i2s_dev *i2s, int offset)
{}

static irqreturn_t chv3_i2s_isr(int irq, void *data)
{}

static int chv3_dma_open(struct snd_soc_component *component,
			 struct snd_pcm_substream *substream)
{}
static int chv3_dma_close(struct snd_soc_component *component,
			  struct snd_pcm_substream *substream)
{}

static int chv3_dma_pcm_construct(struct snd_soc_component *component,
				  struct snd_soc_pcm_runtime *rtd)
{}

static int chv3_dma_hw_params(struct snd_soc_component *component,
			      struct snd_pcm_substream *substream,
			      struct snd_pcm_hw_params *params)
{}

static int chv3_dma_prepare(struct snd_soc_component *component,
			    struct snd_pcm_substream *substream)
{}

static snd_pcm_uframes_t chv3_dma_pointer(struct snd_soc_component *component,
					  struct snd_pcm_substream *substream)
{}

static int chv3_dma_ack(struct snd_soc_component *component,
			struct snd_pcm_substream *substream)
{}

static const struct snd_soc_component_driver chv3_i2s_comp =;

static int chv3_i2s_probe(struct platform_device *pdev)
{}

static const struct of_device_id chv3_i2s_of_match[] =;

static struct platform_driver chv3_i2s_driver =;

module_platform_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();