linux/sound/soc/stm/stm32_spdifrx.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * STM32 ALSA SoC Digital Audio Interface (SPDIF-rx) driver.
 *
 * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
 * Author(s): Olivier Moysan <[email protected]> for STMicroelectronics.
 */

#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>

#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>

/* SPDIF-rx Register Map */
#define STM32_SPDIFRX_CR
#define STM32_SPDIFRX_IMR
#define STM32_SPDIFRX_SR
#define STM32_SPDIFRX_IFCR
#define STM32_SPDIFRX_DR
#define STM32_SPDIFRX_CSR
#define STM32_SPDIFRX_DIR
#define STM32_SPDIFRX_VERR
#define STM32_SPDIFRX_IDR
#define STM32_SPDIFRX_SIDR

/* Bit definition for SPDIF_CR register */
#define SPDIFRX_CR_SPDIFEN_SHIFT
#define SPDIFRX_CR_SPDIFEN_MASK
#define SPDIFRX_CR_SPDIFENSET(x)

#define SPDIFRX_CR_RXDMAEN
#define SPDIFRX_CR_RXSTEO

#define SPDIFRX_CR_DRFMT_SHIFT
#define SPDIFRX_CR_DRFMT_MASK
#define SPDIFRX_CR_DRFMTSET(x)

#define SPDIFRX_CR_PMSK
#define SPDIFRX_CR_VMSK
#define SPDIFRX_CR_CUMSK
#define SPDIFRX_CR_PTMSK
#define SPDIFRX_CR_CBDMAEN
#define SPDIFRX_CR_CHSEL_SHIFT
#define SPDIFRX_CR_CHSEL

#define SPDIFRX_CR_NBTR_SHIFT
#define SPDIFRX_CR_NBTR_MASK
#define SPDIFRX_CR_NBTRSET(x)

#define SPDIFRX_CR_WFA

#define SPDIFRX_CR_INSEL_SHIFT
#define SPDIFRX_CR_INSEL_MASK
#define SPDIFRX_CR_INSELSET(x)

#define SPDIFRX_CR_CKSEN_SHIFT
#define SPDIFRX_CR_CKSEN
#define SPDIFRX_CR_CKSBKPEN

/* Bit definition for SPDIFRX_IMR register */
#define SPDIFRX_IMR_RXNEI
#define SPDIFRX_IMR_CSRNEIE
#define SPDIFRX_IMR_PERRIE
#define SPDIFRX_IMR_OVRIE
#define SPDIFRX_IMR_SBLKIE
#define SPDIFRX_IMR_SYNCDIE
#define SPDIFRX_IMR_IFEIE

#define SPDIFRX_XIMR_MASK

/* Bit definition for SPDIFRX_SR register */
#define SPDIFRX_SR_RXNE
#define SPDIFRX_SR_CSRNE
#define SPDIFRX_SR_PERR
#define SPDIFRX_SR_OVR
#define SPDIFRX_SR_SBD
#define SPDIFRX_SR_SYNCD
#define SPDIFRX_SR_FERR
#define SPDIFRX_SR_SERR
#define SPDIFRX_SR_TERR

#define SPDIFRX_SR_WIDTH5_SHIFT
#define SPDIFRX_SR_WIDTH5_MASK
#define SPDIFRX_SR_WIDTH5SET(x)

/* Bit definition for SPDIFRX_IFCR register */
#define SPDIFRX_IFCR_PERRCF
#define SPDIFRX_IFCR_OVRCF
#define SPDIFRX_IFCR_SBDCF
#define SPDIFRX_IFCR_SYNCDCF

#define SPDIFRX_XIFCR_MASK

/* Bit definition for SPDIFRX_DR register (DRFMT = 0b00) */
#define SPDIFRX_DR0_DR_SHIFT
#define SPDIFRX_DR0_DR_MASK
#define SPDIFRX_DR0_DRSET(x)

#define SPDIFRX_DR0_PE

#define SPDIFRX_DR0_V
#define SPDIFRX_DR0_U
#define SPDIFRX_DR0_C

#define SPDIFRX_DR0_PT_SHIFT
#define SPDIFRX_DR0_PT_MASK
#define SPDIFRX_DR0_PTSET(x)

/* Bit definition for SPDIFRX_DR register (DRFMT = 0b01) */
#define SPDIFRX_DR1_PE
#define SPDIFRX_DR1_V
#define SPDIFRX_DR1_U
#define SPDIFRX_DR1_C

#define SPDIFRX_DR1_PT_SHIFT
#define SPDIFRX_DR1_PT_MASK
#define SPDIFRX_DR1_PTSET(x)

#define SPDIFRX_DR1_DR_SHIFT
#define SPDIFRX_DR1_DR_MASK
#define SPDIFRX_DR1_DRSET(x)

/* Bit definition for SPDIFRX_DR register (DRFMT = 0b10) */
#define SPDIFRX_DR1_DRNL1_SHIFT
#define SPDIFRX_DR1_DRNL1_MASK
#define SPDIFRX_DR1_DRNL1SET(x)

#define SPDIFRX_DR1_DRNL2_SHIFT
#define SPDIFRX_DR1_DRNL2_MASK
#define SPDIFRX_DR1_DRNL2SET(x)

/* Bit definition for SPDIFRX_CSR register */
#define SPDIFRX_CSR_USR_SHIFT
#define SPDIFRX_CSR_USR_MASK
#define SPDIFRX_CSR_USRGET(x)

#define SPDIFRX_CSR_CS_SHIFT
#define SPDIFRX_CSR_CS_MASK
#define SPDIFRX_CSR_CSGET(x)

#define SPDIFRX_CSR_SOB

/* Bit definition for SPDIFRX_DIR register */
#define SPDIFRX_DIR_THI_SHIFT
#define SPDIFRX_DIR_THI_MASK
#define SPDIFRX_DIR_THI_SET(x)

#define SPDIFRX_DIR_TLO_SHIFT
#define SPDIFRX_DIR_TLO_MASK
#define SPDIFRX_DIR_TLO_SET(x)

#define SPDIFRX_SPDIFEN_DISABLE
#define SPDIFRX_SPDIFEN_SYNC
#define SPDIFRX_SPDIFEN_ENABLE

/* Bit definition for SPDIFRX_VERR register */
#define SPDIFRX_VERR_MIN_MASK
#define SPDIFRX_VERR_MAJ_MASK

/* Bit definition for SPDIFRX_IDR register */
#define SPDIFRX_IDR_ID_MASK

/* Bit definition for SPDIFRX_SIDR register */
#define SPDIFRX_SIDR_SID_MASK

#define SPDIFRX_IPIDR_NUMBER

#define SPDIFRX_IN1
#define SPDIFRX_IN2
#define SPDIFRX_IN3
#define SPDIFRX_IN4
#define SPDIFRX_IN5
#define SPDIFRX_IN6
#define SPDIFRX_IN7
#define SPDIFRX_IN8

#define SPDIFRX_NBTR_NONE
#define SPDIFRX_NBTR_3
#define SPDIFRX_NBTR_15
#define SPDIFRX_NBTR_63

#define SPDIFRX_DRFMT_RIGHT
#define SPDIFRX_DRFMT_LEFT
#define SPDIFRX_DRFMT_PACKED

/* 192 CS bits in S/PDIF frame. i.e 24 CS bytes */
#define SPDIFRX_CS_BYTES_NB
#define SPDIFRX_UB_BYTES_NB

/*
 * CSR register is retrieved as a 32 bits word
 * It contains 1 channel status byte and 2 user data bytes
 * 2 S/PDIF frames are acquired to get all CS/UB bits
 */
#define SPDIFRX_CSR_BUF_LENGTH

/**
 * struct stm32_spdifrx_data - private data of SPDIFRX
 * @pdev: device data pointer
 * @base: mmio register base virtual address
 * @regmap: SPDIFRX register map pointer
 * @regmap_conf: SPDIFRX register map configuration pointer
 * @cs_completion: channel status retrieving completion
 * @kclk: kernel clock feeding the SPDIFRX clock generator
 * @dma_params: dma configuration data for rx channel
 * @substream: PCM substream data pointer
 * @dmab: dma buffer info pointer
 * @ctrl_chan: dma channel for S/PDIF control bits
 * @desc:dma async transaction descriptor
 * @slave_config: dma slave channel runtime config pointer
 * @phys_addr: SPDIFRX registers physical base address
 * @lock: synchronization enabling lock
 * @irq_lock: prevent race condition with IRQ on stream state
 * @cs: channel status buffer
 * @ub: user data buffer
 * @irq: SPDIFRX interrupt line
 * @refcount: keep count of opened DMA channels
 */
struct stm32_spdifrx_data {};

static void stm32_spdifrx_dma_complete(void *data)
{}

static int stm32_spdifrx_dma_ctrl_start(struct stm32_spdifrx_data *spdifrx)
{}

static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx)
{}

static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx)
{}

static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx)
{}

static int stm32_spdifrx_dma_ctrl_register(struct device *dev,
					   struct stm32_spdifrx_data *spdifrx)
{
	int ret;

	spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl");
	if (IS_ERR(spdifrx->ctrl_chan))
		return dev_err_probe(dev, PTR_ERR(spdifrx->ctrl_chan),
				     "dma_request_slave_channel error\n");

	spdifrx->dmab = devm_kzalloc(dev, sizeof(struct snd_dma_buffer),
				     GFP_KERNEL);
	if (!spdifrx->dmab)
		return -ENOMEM;

	spdifrx->dmab->dev.type = SNDRV_DMA_TYPE_DEV_IRAM;
	spdifrx->dmab->dev.dev = dev;
	ret = snd_dma_alloc_pages(spdifrx->dmab->dev.type, dev,
				  SPDIFRX_CSR_BUF_LENGTH, spdifrx->dmab);
	if (ret < 0) {
		dev_err(dev, "snd_dma_alloc_pages returned error %d\n", ret);
		return ret;
	}

	spdifrx->slave_config.direction = DMA_DEV_TO_MEM;
	spdifrx->slave_config.src_addr = (dma_addr_t)(spdifrx->phys_addr +
					 STM32_SPDIFRX_CSR);
	spdifrx->slave_config.dst_addr = spdifrx->dmab->addr;
	spdifrx->slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
	spdifrx->slave_config.src_maxburst = 1;

	ret = dmaengine_slave_config(spdifrx->ctrl_chan,
				     &spdifrx->slave_config);
	if (ret < 0) {
		dev_err(dev, "dmaengine_slave_config returned error %d\n", ret);
		spdifrx->ctrl_chan = NULL;
	}

	return ret;
};

static const char * const spdifrx_enum_input[] =;

/*  By default CS bits are retrieved from channel A */
static const char * const spdifrx_enum_cs_channel[] =;

static SOC_ENUM_SINGLE_DECL(ctrl_enum_input,
			    STM32_SPDIFRX_CR, SPDIFRX_CR_INSEL_SHIFT,
			    spdifrx_enum_input);

static SOC_ENUM_SINGLE_DECL(ctrl_enum_cs_channel,
			    STM32_SPDIFRX_CR, SPDIFRX_CR_CHSEL_SHIFT,
			    spdifrx_enum_cs_channel);

static int stm32_spdifrx_info(struct snd_kcontrol *kcontrol,
			      struct snd_ctl_elem_info *uinfo)
{}

static int stm32_spdifrx_ub_info(struct snd_kcontrol *kcontrol,
				 struct snd_ctl_elem_info *uinfo)
{}

static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx)
{}

static int stm32_spdifrx_capture_get(struct snd_kcontrol *kcontrol,
				     struct snd_ctl_elem_value *ucontrol)
{}

static int stm32_spdif_user_bits_get(struct snd_kcontrol *kcontrol,
				     struct snd_ctl_elem_value *ucontrol)
{}

static struct snd_kcontrol_new stm32_spdifrx_iec_ctrls[] =;

static struct snd_kcontrol_new stm32_spdifrx_ctrls[] =;

static int stm32_spdifrx_dai_register_ctrls(struct snd_soc_dai *cpu_dai)
{}

static int stm32_spdifrx_dai_probe(struct snd_soc_dai *cpu_dai)
{}

static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg)
{}

static bool stm32_spdifrx_volatile_reg(struct device *dev, unsigned int reg)
{}

static bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg)
{}

static const struct regmap_config stm32_h7_spdifrx_regmap_conf =;

static irqreturn_t stm32_spdifrx_isr(int irq, void *devid)
{}

static int stm32_spdifrx_startup(struct snd_pcm_substream *substream,
				 struct snd_soc_dai *cpu_dai)
{}

static int stm32_spdifrx_hw_params(struct snd_pcm_substream *substream,
				   struct snd_pcm_hw_params *params,
				   struct snd_soc_dai *cpu_dai)
{}

static int stm32_spdifrx_trigger(struct snd_pcm_substream *substream, int cmd,
				 struct snd_soc_dai *cpu_dai)
{}

static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream,
				   struct snd_soc_dai *cpu_dai)
{}

static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops =;

static struct snd_soc_dai_driver stm32_spdifrx_dai[] =;

static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw =;

static const struct snd_soc_component_driver stm32_spdifrx_component =;

static const struct snd_dmaengine_pcm_config stm32_spdifrx_pcm_config =;

static const struct of_device_id stm32_spdifrx_ids[] =;

static int stm32_spdifrx_parse_of(struct platform_device *pdev,
				  struct stm32_spdifrx_data *spdifrx)
{}

static void stm32_spdifrx_remove(struct platform_device *pdev)
{}

static int stm32_spdifrx_probe(struct platform_device *pdev)
{}

MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids);

#ifdef CONFIG_PM_SLEEP
static int stm32_spdifrx_suspend(struct device *dev)
{}

static int stm32_spdifrx_resume(struct device *dev)
{}
#endif /* CONFIG_PM_SLEEP */

static const struct dev_pm_ops stm32_spdifrx_pm_ops =;

static struct platform_driver stm32_spdifrx_driver =;

module_platform_driver();

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