103e4d5d5Solivier moysan /* 203e4d5d5Solivier moysan * STM32 ALSA SoC Digital Audio Interface (SPDIF-rx) driver. 303e4d5d5Solivier moysan * 403e4d5d5Solivier moysan * Copyright (C) 2017, STMicroelectronics - All Rights Reserved 503e4d5d5Solivier moysan * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics. 603e4d5d5Solivier moysan * 703e4d5d5Solivier moysan * License terms: GPL V2.0. 803e4d5d5Solivier moysan * 903e4d5d5Solivier moysan * This program is free software; you can redistribute it and/or modify it 1003e4d5d5Solivier moysan * under the terms of the GNU General Public License version 2 as published by 1103e4d5d5Solivier moysan * the Free Software Foundation. 1203e4d5d5Solivier moysan * 1303e4d5d5Solivier moysan * This program is distributed in the hope that it will be useful, but 1403e4d5d5Solivier moysan * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1503e4d5d5Solivier moysan * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 1603e4d5d5Solivier moysan * details. 1703e4d5d5Solivier moysan */ 1803e4d5d5Solivier moysan 1903e4d5d5Solivier moysan #include <linux/clk.h> 2003e4d5d5Solivier moysan #include <linux/completion.h> 2103e4d5d5Solivier moysan #include <linux/delay.h> 2203e4d5d5Solivier moysan #include <linux/module.h> 2303e4d5d5Solivier moysan #include <linux/of_platform.h> 2403e4d5d5Solivier moysan #include <linux/regmap.h> 2503e4d5d5Solivier moysan #include <linux/reset.h> 2603e4d5d5Solivier moysan 2703e4d5d5Solivier moysan #include <sound/dmaengine_pcm.h> 2803e4d5d5Solivier moysan #include <sound/pcm_params.h> 2903e4d5d5Solivier moysan 3003e4d5d5Solivier moysan /* SPDIF-rx Register Map */ 3103e4d5d5Solivier moysan #define STM32_SPDIFRX_CR 0x00 3203e4d5d5Solivier moysan #define STM32_SPDIFRX_IMR 0x04 3303e4d5d5Solivier moysan #define STM32_SPDIFRX_SR 0x08 3403e4d5d5Solivier moysan #define STM32_SPDIFRX_IFCR 0x0C 3503e4d5d5Solivier moysan #define STM32_SPDIFRX_DR 0x10 3603e4d5d5Solivier moysan #define STM32_SPDIFRX_CSR 0x14 3703e4d5d5Solivier moysan #define STM32_SPDIFRX_DIR 0x18 3803e4d5d5Solivier moysan 3903e4d5d5Solivier moysan /* Bit definition for SPDIF_CR register */ 4003e4d5d5Solivier moysan #define SPDIFRX_CR_SPDIFEN_SHIFT 0 4103e4d5d5Solivier moysan #define SPDIFRX_CR_SPDIFEN_MASK GENMASK(1, SPDIFRX_CR_SPDIFEN_SHIFT) 4203e4d5d5Solivier moysan #define SPDIFRX_CR_SPDIFENSET(x) ((x) << SPDIFRX_CR_SPDIFEN_SHIFT) 4303e4d5d5Solivier moysan 4403e4d5d5Solivier moysan #define SPDIFRX_CR_RXDMAEN BIT(2) 4503e4d5d5Solivier moysan #define SPDIFRX_CR_RXSTEO BIT(3) 4603e4d5d5Solivier moysan 4703e4d5d5Solivier moysan #define SPDIFRX_CR_DRFMT_SHIFT 4 4803e4d5d5Solivier moysan #define SPDIFRX_CR_DRFMT_MASK GENMASK(5, SPDIFRX_CR_DRFMT_SHIFT) 4903e4d5d5Solivier moysan #define SPDIFRX_CR_DRFMTSET(x) ((x) << SPDIFRX_CR_DRFMT_SHIFT) 5003e4d5d5Solivier moysan 5103e4d5d5Solivier moysan #define SPDIFRX_CR_PMSK BIT(6) 5203e4d5d5Solivier moysan #define SPDIFRX_CR_VMSK BIT(7) 5303e4d5d5Solivier moysan #define SPDIFRX_CR_CUMSK BIT(8) 5403e4d5d5Solivier moysan #define SPDIFRX_CR_PTMSK BIT(9) 5503e4d5d5Solivier moysan #define SPDIFRX_CR_CBDMAEN BIT(10) 5603e4d5d5Solivier moysan #define SPDIFRX_CR_CHSEL_SHIFT 11 5703e4d5d5Solivier moysan #define SPDIFRX_CR_CHSEL BIT(SPDIFRX_CR_CHSEL_SHIFT) 5803e4d5d5Solivier moysan 5903e4d5d5Solivier moysan #define SPDIFRX_CR_NBTR_SHIFT 12 6003e4d5d5Solivier moysan #define SPDIFRX_CR_NBTR_MASK GENMASK(13, SPDIFRX_CR_NBTR_SHIFT) 6103e4d5d5Solivier moysan #define SPDIFRX_CR_NBTRSET(x) ((x) << SPDIFRX_CR_NBTR_SHIFT) 6203e4d5d5Solivier moysan 6303e4d5d5Solivier moysan #define SPDIFRX_CR_WFA BIT(14) 6403e4d5d5Solivier moysan 6503e4d5d5Solivier moysan #define SPDIFRX_CR_INSEL_SHIFT 16 6603e4d5d5Solivier moysan #define SPDIFRX_CR_INSEL_MASK GENMASK(18, PDIFRX_CR_INSEL_SHIFT) 6703e4d5d5Solivier moysan #define SPDIFRX_CR_INSELSET(x) ((x) << SPDIFRX_CR_INSEL_SHIFT) 6803e4d5d5Solivier moysan 6903e4d5d5Solivier moysan #define SPDIFRX_CR_CKSEN_SHIFT 20 7003e4d5d5Solivier moysan #define SPDIFRX_CR_CKSEN BIT(20) 7103e4d5d5Solivier moysan #define SPDIFRX_CR_CKSBKPEN BIT(21) 7203e4d5d5Solivier moysan 7303e4d5d5Solivier moysan /* Bit definition for SPDIFRX_IMR register */ 7403e4d5d5Solivier moysan #define SPDIFRX_IMR_RXNEI BIT(0) 7503e4d5d5Solivier moysan #define SPDIFRX_IMR_CSRNEIE BIT(1) 7603e4d5d5Solivier moysan #define SPDIFRX_IMR_PERRIE BIT(2) 7703e4d5d5Solivier moysan #define SPDIFRX_IMR_OVRIE BIT(3) 7803e4d5d5Solivier moysan #define SPDIFRX_IMR_SBLKIE BIT(4) 7903e4d5d5Solivier moysan #define SPDIFRX_IMR_SYNCDIE BIT(5) 8003e4d5d5Solivier moysan #define SPDIFRX_IMR_IFEIE BIT(6) 8103e4d5d5Solivier moysan 8203e4d5d5Solivier moysan #define SPDIFRX_XIMR_MASK GENMASK(6, 0) 8303e4d5d5Solivier moysan 8403e4d5d5Solivier moysan /* Bit definition for SPDIFRX_SR register */ 8503e4d5d5Solivier moysan #define SPDIFRX_SR_RXNE BIT(0) 8603e4d5d5Solivier moysan #define SPDIFRX_SR_CSRNE BIT(1) 8703e4d5d5Solivier moysan #define SPDIFRX_SR_PERR BIT(2) 8803e4d5d5Solivier moysan #define SPDIFRX_SR_OVR BIT(3) 8903e4d5d5Solivier moysan #define SPDIFRX_SR_SBD BIT(4) 9003e4d5d5Solivier moysan #define SPDIFRX_SR_SYNCD BIT(5) 9103e4d5d5Solivier moysan #define SPDIFRX_SR_FERR BIT(6) 9203e4d5d5Solivier moysan #define SPDIFRX_SR_SERR BIT(7) 9303e4d5d5Solivier moysan #define SPDIFRX_SR_TERR BIT(8) 9403e4d5d5Solivier moysan 9503e4d5d5Solivier moysan #define SPDIFRX_SR_WIDTH5_SHIFT 16 9603e4d5d5Solivier moysan #define SPDIFRX_SR_WIDTH5_MASK GENMASK(30, PDIFRX_SR_WIDTH5_SHIFT) 9703e4d5d5Solivier moysan #define SPDIFRX_SR_WIDTH5SET(x) ((x) << SPDIFRX_SR_WIDTH5_SHIFT) 9803e4d5d5Solivier moysan 9903e4d5d5Solivier moysan /* Bit definition for SPDIFRX_IFCR register */ 10003e4d5d5Solivier moysan #define SPDIFRX_IFCR_PERRCF BIT(2) 10103e4d5d5Solivier moysan #define SPDIFRX_IFCR_OVRCF BIT(3) 10203e4d5d5Solivier moysan #define SPDIFRX_IFCR_SBDCF BIT(4) 10303e4d5d5Solivier moysan #define SPDIFRX_IFCR_SYNCDCF BIT(5) 10403e4d5d5Solivier moysan 10503e4d5d5Solivier moysan #define SPDIFRX_XIFCR_MASK GENMASK(5, 2) 10603e4d5d5Solivier moysan 10703e4d5d5Solivier moysan /* Bit definition for SPDIFRX_DR register (DRFMT = 0b00) */ 10803e4d5d5Solivier moysan #define SPDIFRX_DR0_DR_SHIFT 0 10903e4d5d5Solivier moysan #define SPDIFRX_DR0_DR_MASK GENMASK(23, SPDIFRX_DR0_DR_SHIFT) 11003e4d5d5Solivier moysan #define SPDIFRX_DR0_DRSET(x) ((x) << SPDIFRX_DR0_DR_SHIFT) 11103e4d5d5Solivier moysan 11203e4d5d5Solivier moysan #define SPDIFRX_DR0_PE BIT(24) 11303e4d5d5Solivier moysan 11403e4d5d5Solivier moysan #define SPDIFRX_DR0_V BIT(25) 11503e4d5d5Solivier moysan #define SPDIFRX_DR0_U BIT(26) 11603e4d5d5Solivier moysan #define SPDIFRX_DR0_C BIT(27) 11703e4d5d5Solivier moysan 11803e4d5d5Solivier moysan #define SPDIFRX_DR0_PT_SHIFT 28 11903e4d5d5Solivier moysan #define SPDIFRX_DR0_PT_MASK GENMASK(29, SPDIFRX_DR0_PT_SHIFT) 12003e4d5d5Solivier moysan #define SPDIFRX_DR0_PTSET(x) ((x) << SPDIFRX_DR0_PT_SHIFT) 12103e4d5d5Solivier moysan 12203e4d5d5Solivier moysan /* Bit definition for SPDIFRX_DR register (DRFMT = 0b01) */ 12303e4d5d5Solivier moysan #define SPDIFRX_DR1_PE BIT(0) 12403e4d5d5Solivier moysan #define SPDIFRX_DR1_V BIT(1) 12503e4d5d5Solivier moysan #define SPDIFRX_DR1_U BIT(2) 12603e4d5d5Solivier moysan #define SPDIFRX_DR1_C BIT(3) 12703e4d5d5Solivier moysan 12803e4d5d5Solivier moysan #define SPDIFRX_DR1_PT_SHIFT 4 12903e4d5d5Solivier moysan #define SPDIFRX_DR1_PT_MASK GENMASK(5, SPDIFRX_DR1_PT_SHIFT) 13003e4d5d5Solivier moysan #define SPDIFRX_DR1_PTSET(x) ((x) << SPDIFRX_DR1_PT_SHIFT) 13103e4d5d5Solivier moysan 13203e4d5d5Solivier moysan #define SPDIFRX_DR1_DR_SHIFT 8 13303e4d5d5Solivier moysan #define SPDIFRX_DR1_DR_MASK GENMASK(31, SPDIFRX_DR1_DR_SHIFT) 13403e4d5d5Solivier moysan #define SPDIFRX_DR1_DRSET(x) ((x) << SPDIFRX_DR1_DR_SHIFT) 13503e4d5d5Solivier moysan 13603e4d5d5Solivier moysan /* Bit definition for SPDIFRX_DR register (DRFMT = 0b10) */ 13703e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL1_SHIFT 0 13803e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL1_MASK GENMASK(15, SPDIFRX_DR1_DRNL1_SHIFT) 13903e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL1SET(x) ((x) << SPDIFRX_DR1_DRNL1_SHIFT) 14003e4d5d5Solivier moysan 14103e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL2_SHIFT 16 14203e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL2_MASK GENMASK(31, SPDIFRX_DR1_DRNL2_SHIFT) 14303e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL2SET(x) ((x) << SPDIFRX_DR1_DRNL2_SHIFT) 14403e4d5d5Solivier moysan 14503e4d5d5Solivier moysan /* Bit definition for SPDIFRX_CSR register */ 14603e4d5d5Solivier moysan #define SPDIFRX_CSR_USR_SHIFT 0 14703e4d5d5Solivier moysan #define SPDIFRX_CSR_USR_MASK GENMASK(15, SPDIFRX_CSR_USR_SHIFT) 14803e4d5d5Solivier moysan #define SPDIFRX_CSR_USRGET(x) (((x) & SPDIFRX_CSR_USR_MASK)\ 14903e4d5d5Solivier moysan >> SPDIFRX_CSR_USR_SHIFT) 15003e4d5d5Solivier moysan 15103e4d5d5Solivier moysan #define SPDIFRX_CSR_CS_SHIFT 16 15203e4d5d5Solivier moysan #define SPDIFRX_CSR_CS_MASK GENMASK(23, SPDIFRX_CSR_CS_SHIFT) 15303e4d5d5Solivier moysan #define SPDIFRX_CSR_CSGET(x) (((x) & SPDIFRX_CSR_CS_MASK)\ 15403e4d5d5Solivier moysan >> SPDIFRX_CSR_CS_SHIFT) 15503e4d5d5Solivier moysan 15603e4d5d5Solivier moysan #define SPDIFRX_CSR_SOB BIT(24) 15703e4d5d5Solivier moysan 15803e4d5d5Solivier moysan /* Bit definition for SPDIFRX_DIR register */ 15903e4d5d5Solivier moysan #define SPDIFRX_DIR_THI_SHIFT 0 16003e4d5d5Solivier moysan #define SPDIFRX_DIR_THI_MASK GENMASK(12, SPDIFRX_DIR_THI_SHIFT) 16103e4d5d5Solivier moysan #define SPDIFRX_DIR_THI_SET(x) ((x) << SPDIFRX_DIR_THI_SHIFT) 16203e4d5d5Solivier moysan 16303e4d5d5Solivier moysan #define SPDIFRX_DIR_TLO_SHIFT 16 16403e4d5d5Solivier moysan #define SPDIFRX_DIR_TLO_MASK GENMASK(28, SPDIFRX_DIR_TLO_SHIFT) 16503e4d5d5Solivier moysan #define SPDIFRX_DIR_TLO_SET(x) ((x) << SPDIFRX_DIR_TLO_SHIFT) 16603e4d5d5Solivier moysan 16703e4d5d5Solivier moysan #define SPDIFRX_SPDIFEN_DISABLE 0x0 16803e4d5d5Solivier moysan #define SPDIFRX_SPDIFEN_SYNC 0x1 16903e4d5d5Solivier moysan #define SPDIFRX_SPDIFEN_ENABLE 0x3 17003e4d5d5Solivier moysan 17103e4d5d5Solivier moysan #define SPDIFRX_IN1 0x1 17203e4d5d5Solivier moysan #define SPDIFRX_IN2 0x2 17303e4d5d5Solivier moysan #define SPDIFRX_IN3 0x3 17403e4d5d5Solivier moysan #define SPDIFRX_IN4 0x4 17503e4d5d5Solivier moysan #define SPDIFRX_IN5 0x5 17603e4d5d5Solivier moysan #define SPDIFRX_IN6 0x6 17703e4d5d5Solivier moysan #define SPDIFRX_IN7 0x7 17803e4d5d5Solivier moysan #define SPDIFRX_IN8 0x8 17903e4d5d5Solivier moysan 18003e4d5d5Solivier moysan #define SPDIFRX_NBTR_NONE 0x0 18103e4d5d5Solivier moysan #define SPDIFRX_NBTR_3 0x1 18203e4d5d5Solivier moysan #define SPDIFRX_NBTR_15 0x2 18303e4d5d5Solivier moysan #define SPDIFRX_NBTR_63 0x3 18403e4d5d5Solivier moysan 18503e4d5d5Solivier moysan #define SPDIFRX_DRFMT_RIGHT 0x0 18603e4d5d5Solivier moysan #define SPDIFRX_DRFMT_LEFT 0x1 18703e4d5d5Solivier moysan #define SPDIFRX_DRFMT_PACKED 0x2 18803e4d5d5Solivier moysan 18903e4d5d5Solivier moysan /* 192 CS bits in S/PDIF frame. i.e 24 CS bytes */ 19003e4d5d5Solivier moysan #define SPDIFRX_CS_BYTES_NB 24 19103e4d5d5Solivier moysan #define SPDIFRX_UB_BYTES_NB 48 19203e4d5d5Solivier moysan 19303e4d5d5Solivier moysan /* 19403e4d5d5Solivier moysan * CSR register is retrieved as a 32 bits word 19503e4d5d5Solivier moysan * It contains 1 channel status byte and 2 user data bytes 19603e4d5d5Solivier moysan * 2 S/PDIF frames are acquired to get all CS/UB bits 19703e4d5d5Solivier moysan */ 19803e4d5d5Solivier moysan #define SPDIFRX_CSR_BUF_LENGTH (SPDIFRX_CS_BYTES_NB * 4 * 2) 19903e4d5d5Solivier moysan 20003e4d5d5Solivier moysan /** 20103e4d5d5Solivier moysan * struct stm32_spdifrx_data - private data of SPDIFRX 20203e4d5d5Solivier moysan * @pdev: device data pointer 20303e4d5d5Solivier moysan * @base: mmio register base virtual address 20403e4d5d5Solivier moysan * @regmap: SPDIFRX register map pointer 20503e4d5d5Solivier moysan * @regmap_conf: SPDIFRX register map configuration pointer 20603e4d5d5Solivier moysan * @cs_completion: channel status retrieving completion 20703e4d5d5Solivier moysan * @kclk: kernel clock feeding the SPDIFRX clock generator 20803e4d5d5Solivier moysan * @dma_params: dma configuration data for rx channel 20903e4d5d5Solivier moysan * @substream: PCM substream data pointer 21003e4d5d5Solivier moysan * @dmab: dma buffer info pointer 21103e4d5d5Solivier moysan * @ctrl_chan: dma channel for S/PDIF control bits 21203e4d5d5Solivier moysan * @desc:dma async transaction descriptor 21303e4d5d5Solivier moysan * @slave_config: dma slave channel runtime config pointer 21403e4d5d5Solivier moysan * @phys_addr: SPDIFRX registers physical base address 21503e4d5d5Solivier moysan * @lock: synchronization enabling lock 21603e4d5d5Solivier moysan * @cs: channel status buffer 21703e4d5d5Solivier moysan * @ub: user data buffer 21803e4d5d5Solivier moysan * @irq: SPDIFRX interrupt line 21903e4d5d5Solivier moysan * @refcount: keep count of opened DMA channels 22003e4d5d5Solivier moysan */ 22103e4d5d5Solivier moysan struct stm32_spdifrx_data { 22203e4d5d5Solivier moysan struct platform_device *pdev; 22303e4d5d5Solivier moysan void __iomem *base; 22403e4d5d5Solivier moysan struct regmap *regmap; 22503e4d5d5Solivier moysan const struct regmap_config *regmap_conf; 22603e4d5d5Solivier moysan struct completion cs_completion; 22703e4d5d5Solivier moysan struct clk *kclk; 22803e4d5d5Solivier moysan struct snd_dmaengine_dai_dma_data dma_params; 22903e4d5d5Solivier moysan struct snd_pcm_substream *substream; 23003e4d5d5Solivier moysan struct snd_dma_buffer *dmab; 23103e4d5d5Solivier moysan struct dma_chan *ctrl_chan; 23203e4d5d5Solivier moysan struct dma_async_tx_descriptor *desc; 23303e4d5d5Solivier moysan struct dma_slave_config slave_config; 23403e4d5d5Solivier moysan dma_addr_t phys_addr; 23503e4d5d5Solivier moysan spinlock_t lock; /* Sync enabling lock */ 23603e4d5d5Solivier moysan unsigned char cs[SPDIFRX_CS_BYTES_NB]; 23703e4d5d5Solivier moysan unsigned char ub[SPDIFRX_UB_BYTES_NB]; 23803e4d5d5Solivier moysan int irq; 23903e4d5d5Solivier moysan int refcount; 24003e4d5d5Solivier moysan }; 24103e4d5d5Solivier moysan 24203e4d5d5Solivier moysan static void stm32_spdifrx_dma_complete(void *data) 24303e4d5d5Solivier moysan { 24403e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)data; 24503e4d5d5Solivier moysan struct platform_device *pdev = spdifrx->pdev; 24603e4d5d5Solivier moysan u32 *p_start = (u32 *)spdifrx->dmab->area; 24703e4d5d5Solivier moysan u32 *p_end = p_start + (2 * SPDIFRX_CS_BYTES_NB) - 1; 24803e4d5d5Solivier moysan u32 *ptr = p_start; 24903e4d5d5Solivier moysan u16 *ub_ptr = (short *)spdifrx->ub; 25003e4d5d5Solivier moysan int i = 0; 25103e4d5d5Solivier moysan 25203e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 25303e4d5d5Solivier moysan SPDIFRX_CR_CBDMAEN, 25403e4d5d5Solivier moysan (unsigned int)~SPDIFRX_CR_CBDMAEN); 25503e4d5d5Solivier moysan 25603e4d5d5Solivier moysan if (!spdifrx->dmab->area) 25703e4d5d5Solivier moysan return; 25803e4d5d5Solivier moysan 25903e4d5d5Solivier moysan while (ptr <= p_end) { 26003e4d5d5Solivier moysan if (*ptr & SPDIFRX_CSR_SOB) 26103e4d5d5Solivier moysan break; 26203e4d5d5Solivier moysan ptr++; 26303e4d5d5Solivier moysan } 26403e4d5d5Solivier moysan 26503e4d5d5Solivier moysan if (ptr > p_end) { 26603e4d5d5Solivier moysan dev_err(&pdev->dev, "Start of S/PDIF block not found\n"); 26703e4d5d5Solivier moysan return; 26803e4d5d5Solivier moysan } 26903e4d5d5Solivier moysan 27003e4d5d5Solivier moysan while (i < SPDIFRX_CS_BYTES_NB) { 27103e4d5d5Solivier moysan spdifrx->cs[i] = (unsigned char)SPDIFRX_CSR_CSGET(*ptr); 27203e4d5d5Solivier moysan *ub_ptr++ = SPDIFRX_CSR_USRGET(*ptr++); 27303e4d5d5Solivier moysan if (ptr > p_end) { 27403e4d5d5Solivier moysan dev_err(&pdev->dev, "Failed to get channel status\n"); 27503e4d5d5Solivier moysan return; 27603e4d5d5Solivier moysan } 27703e4d5d5Solivier moysan i++; 27803e4d5d5Solivier moysan } 27903e4d5d5Solivier moysan 28003e4d5d5Solivier moysan complete(&spdifrx->cs_completion); 28103e4d5d5Solivier moysan } 28203e4d5d5Solivier moysan 28303e4d5d5Solivier moysan static int stm32_spdifrx_dma_ctrl_start(struct stm32_spdifrx_data *spdifrx) 28403e4d5d5Solivier moysan { 28503e4d5d5Solivier moysan dma_cookie_t cookie; 28603e4d5d5Solivier moysan int err; 28703e4d5d5Solivier moysan 28803e4d5d5Solivier moysan spdifrx->desc = dmaengine_prep_slave_single(spdifrx->ctrl_chan, 28903e4d5d5Solivier moysan spdifrx->dmab->addr, 29003e4d5d5Solivier moysan SPDIFRX_CSR_BUF_LENGTH, 29103e4d5d5Solivier moysan DMA_DEV_TO_MEM, 29203e4d5d5Solivier moysan DMA_CTRL_ACK); 29303e4d5d5Solivier moysan if (!spdifrx->desc) 29403e4d5d5Solivier moysan return -EINVAL; 29503e4d5d5Solivier moysan 29603e4d5d5Solivier moysan spdifrx->desc->callback = stm32_spdifrx_dma_complete; 29703e4d5d5Solivier moysan spdifrx->desc->callback_param = spdifrx; 29803e4d5d5Solivier moysan cookie = dmaengine_submit(spdifrx->desc); 29903e4d5d5Solivier moysan err = dma_submit_error(cookie); 30003e4d5d5Solivier moysan if (err) 30103e4d5d5Solivier moysan return -EINVAL; 30203e4d5d5Solivier moysan 30303e4d5d5Solivier moysan dma_async_issue_pending(spdifrx->ctrl_chan); 30403e4d5d5Solivier moysan 30503e4d5d5Solivier moysan return 0; 30603e4d5d5Solivier moysan } 30703e4d5d5Solivier moysan 30803e4d5d5Solivier moysan static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx) 30903e4d5d5Solivier moysan { 31003e4d5d5Solivier moysan dmaengine_terminate_async(spdifrx->ctrl_chan); 31103e4d5d5Solivier moysan } 31203e4d5d5Solivier moysan 31303e4d5d5Solivier moysan static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) 31403e4d5d5Solivier moysan { 31503e4d5d5Solivier moysan int cr, cr_mask, imr, ret; 31603e4d5d5Solivier moysan 31703e4d5d5Solivier moysan /* Enable IRQs */ 31803e4d5d5Solivier moysan imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE; 31903e4d5d5Solivier moysan ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, imr, imr); 32003e4d5d5Solivier moysan if (ret) 32103e4d5d5Solivier moysan return ret; 32203e4d5d5Solivier moysan 32303e4d5d5Solivier moysan spin_lock(&spdifrx->lock); 32403e4d5d5Solivier moysan 32503e4d5d5Solivier moysan spdifrx->refcount++; 32603e4d5d5Solivier moysan 32703e4d5d5Solivier moysan regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr); 32803e4d5d5Solivier moysan 32903e4d5d5Solivier moysan if (!(cr & SPDIFRX_CR_SPDIFEN_MASK)) { 33003e4d5d5Solivier moysan /* 33103e4d5d5Solivier moysan * Start sync if SPDIFRX is still in idle state. 33203e4d5d5Solivier moysan * SPDIFRX reception enabled when sync done 33303e4d5d5Solivier moysan */ 33403e4d5d5Solivier moysan dev_dbg(&spdifrx->pdev->dev, "start synchronization\n"); 33503e4d5d5Solivier moysan 33603e4d5d5Solivier moysan /* 33703e4d5d5Solivier moysan * SPDIFRX configuration: 33803e4d5d5Solivier moysan * Wait for activity before starting sync process. This avoid 33903e4d5d5Solivier moysan * to issue sync errors when spdif signal is missing on input. 34003e4d5d5Solivier moysan * Preamble, CS, user, validity and parity error bits not copied 34103e4d5d5Solivier moysan * to DR register. 34203e4d5d5Solivier moysan */ 34303e4d5d5Solivier moysan cr = SPDIFRX_CR_WFA | SPDIFRX_CR_PMSK | SPDIFRX_CR_VMSK | 34403e4d5d5Solivier moysan SPDIFRX_CR_CUMSK | SPDIFRX_CR_PTMSK | SPDIFRX_CR_RXSTEO; 34503e4d5d5Solivier moysan cr_mask = cr; 34603e4d5d5Solivier moysan 34703e4d5d5Solivier moysan cr |= SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); 34803e4d5d5Solivier moysan cr_mask |= SPDIFRX_CR_SPDIFEN_MASK; 34903e4d5d5Solivier moysan ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 35003e4d5d5Solivier moysan cr_mask, cr); 35103e4d5d5Solivier moysan if (ret < 0) 35203e4d5d5Solivier moysan dev_err(&spdifrx->pdev->dev, 35303e4d5d5Solivier moysan "Failed to start synchronization\n"); 35403e4d5d5Solivier moysan } 35503e4d5d5Solivier moysan 35603e4d5d5Solivier moysan spin_unlock(&spdifrx->lock); 35703e4d5d5Solivier moysan 35803e4d5d5Solivier moysan return ret; 35903e4d5d5Solivier moysan } 36003e4d5d5Solivier moysan 36103e4d5d5Solivier moysan static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) 36203e4d5d5Solivier moysan { 36303e4d5d5Solivier moysan int cr, cr_mask, reg; 36403e4d5d5Solivier moysan 36503e4d5d5Solivier moysan spin_lock(&spdifrx->lock); 36603e4d5d5Solivier moysan 36703e4d5d5Solivier moysan if (--spdifrx->refcount) { 36803e4d5d5Solivier moysan spin_unlock(&spdifrx->lock); 36903e4d5d5Solivier moysan return; 37003e4d5d5Solivier moysan } 37103e4d5d5Solivier moysan 37203e4d5d5Solivier moysan cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); 37303e4d5d5Solivier moysan cr_mask = SPDIFRX_CR_SPDIFEN_MASK | SPDIFRX_CR_RXDMAEN; 37403e4d5d5Solivier moysan 37503e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, cr_mask, cr); 37603e4d5d5Solivier moysan 37703e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, 37803e4d5d5Solivier moysan SPDIFRX_XIMR_MASK, 0); 37903e4d5d5Solivier moysan 38003e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IFCR, 38103e4d5d5Solivier moysan SPDIFRX_XIFCR_MASK, SPDIFRX_XIFCR_MASK); 38203e4d5d5Solivier moysan 38303e4d5d5Solivier moysan /* dummy read to clear CSRNE and RXNE in status register */ 38403e4d5d5Solivier moysan regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, ®); 38503e4d5d5Solivier moysan regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, ®); 38603e4d5d5Solivier moysan 38703e4d5d5Solivier moysan spin_unlock(&spdifrx->lock); 38803e4d5d5Solivier moysan } 38903e4d5d5Solivier moysan 39003e4d5d5Solivier moysan static int stm32_spdifrx_dma_ctrl_register(struct device *dev, 39103e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx) 39203e4d5d5Solivier moysan { 39303e4d5d5Solivier moysan int ret; 39403e4d5d5Solivier moysan 39598c8dc2fSolivier moysan spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl"); 39698c8dc2fSolivier moysan if (IS_ERR(spdifrx->ctrl_chan)) { 39798c8dc2fSolivier moysan dev_err(dev, "dma_request_slave_channel failed\n"); 39898c8dc2fSolivier moysan return PTR_ERR(spdifrx->ctrl_chan); 39998c8dc2fSolivier moysan } 40098c8dc2fSolivier moysan 40103e4d5d5Solivier moysan spdifrx->dmab = devm_kzalloc(dev, sizeof(struct snd_dma_buffer), 40203e4d5d5Solivier moysan GFP_KERNEL); 40303e4d5d5Solivier moysan if (!spdifrx->dmab) 40403e4d5d5Solivier moysan return -ENOMEM; 40503e4d5d5Solivier moysan 40603e4d5d5Solivier moysan spdifrx->dmab->dev.type = SNDRV_DMA_TYPE_DEV_IRAM; 40703e4d5d5Solivier moysan spdifrx->dmab->dev.dev = dev; 40803e4d5d5Solivier moysan ret = snd_dma_alloc_pages(spdifrx->dmab->dev.type, dev, 40903e4d5d5Solivier moysan SPDIFRX_CSR_BUF_LENGTH, spdifrx->dmab); 41003e4d5d5Solivier moysan if (ret < 0) { 41103e4d5d5Solivier moysan dev_err(dev, "snd_dma_alloc_pages returned error %d\n", ret); 41203e4d5d5Solivier moysan return ret; 41303e4d5d5Solivier moysan } 41403e4d5d5Solivier moysan 41503e4d5d5Solivier moysan spdifrx->slave_config.direction = DMA_DEV_TO_MEM; 41603e4d5d5Solivier moysan spdifrx->slave_config.src_addr = (dma_addr_t)(spdifrx->phys_addr + 41703e4d5d5Solivier moysan STM32_SPDIFRX_CSR); 41803e4d5d5Solivier moysan spdifrx->slave_config.dst_addr = spdifrx->dmab->addr; 41903e4d5d5Solivier moysan spdifrx->slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 42003e4d5d5Solivier moysan spdifrx->slave_config.src_maxburst = 1; 42103e4d5d5Solivier moysan 42203e4d5d5Solivier moysan ret = dmaengine_slave_config(spdifrx->ctrl_chan, 42303e4d5d5Solivier moysan &spdifrx->slave_config); 42403e4d5d5Solivier moysan if (ret < 0) { 42503e4d5d5Solivier moysan dev_err(dev, "dmaengine_slave_config returned error %d\n", ret); 42603e4d5d5Solivier moysan spdifrx->ctrl_chan = NULL; 42703e4d5d5Solivier moysan } 42803e4d5d5Solivier moysan 42903e4d5d5Solivier moysan return ret; 43003e4d5d5Solivier moysan }; 43103e4d5d5Solivier moysan 43203e4d5d5Solivier moysan static const char * const spdifrx_enum_input[] = { 43303e4d5d5Solivier moysan "in0", "in1", "in2", "in3" 43403e4d5d5Solivier moysan }; 43503e4d5d5Solivier moysan 43603e4d5d5Solivier moysan /* By default CS bits are retrieved from channel A */ 43703e4d5d5Solivier moysan static const char * const spdifrx_enum_cs_channel[] = { 43803e4d5d5Solivier moysan "A", "B" 43903e4d5d5Solivier moysan }; 44003e4d5d5Solivier moysan 44103e4d5d5Solivier moysan static SOC_ENUM_SINGLE_DECL(ctrl_enum_input, 44203e4d5d5Solivier moysan STM32_SPDIFRX_CR, SPDIFRX_CR_INSEL_SHIFT, 44303e4d5d5Solivier moysan spdifrx_enum_input); 44403e4d5d5Solivier moysan 44503e4d5d5Solivier moysan static SOC_ENUM_SINGLE_DECL(ctrl_enum_cs_channel, 44603e4d5d5Solivier moysan STM32_SPDIFRX_CR, SPDIFRX_CR_CHSEL_SHIFT, 44703e4d5d5Solivier moysan spdifrx_enum_cs_channel); 44803e4d5d5Solivier moysan 44903e4d5d5Solivier moysan static int stm32_spdifrx_info(struct snd_kcontrol *kcontrol, 45003e4d5d5Solivier moysan struct snd_ctl_elem_info *uinfo) 45103e4d5d5Solivier moysan { 45203e4d5d5Solivier moysan uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 45303e4d5d5Solivier moysan uinfo->count = 1; 45403e4d5d5Solivier moysan 45503e4d5d5Solivier moysan return 0; 45603e4d5d5Solivier moysan } 45703e4d5d5Solivier moysan 45803e4d5d5Solivier moysan static int stm32_spdifrx_ub_info(struct snd_kcontrol *kcontrol, 45903e4d5d5Solivier moysan struct snd_ctl_elem_info *uinfo) 46003e4d5d5Solivier moysan { 46103e4d5d5Solivier moysan uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 46203e4d5d5Solivier moysan uinfo->count = 1; 46303e4d5d5Solivier moysan 46403e4d5d5Solivier moysan return 0; 46503e4d5d5Solivier moysan } 46603e4d5d5Solivier moysan 46703e4d5d5Solivier moysan static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx) 46803e4d5d5Solivier moysan { 46903e4d5d5Solivier moysan int ret = 0; 47003e4d5d5Solivier moysan 47103e4d5d5Solivier moysan memset(spdifrx->cs, 0, SPDIFRX_CS_BYTES_NB); 47203e4d5d5Solivier moysan memset(spdifrx->ub, 0, SPDIFRX_UB_BYTES_NB); 47303e4d5d5Solivier moysan 47403e4d5d5Solivier moysan ret = stm32_spdifrx_dma_ctrl_start(spdifrx); 47503e4d5d5Solivier moysan if (ret < 0) 47603e4d5d5Solivier moysan return ret; 47703e4d5d5Solivier moysan 47803e4d5d5Solivier moysan ret = clk_prepare_enable(spdifrx->kclk); 47903e4d5d5Solivier moysan if (ret) { 48003e4d5d5Solivier moysan dev_err(&spdifrx->pdev->dev, "Enable kclk failed: %d\n", ret); 48103e4d5d5Solivier moysan return ret; 48203e4d5d5Solivier moysan } 48303e4d5d5Solivier moysan 48403e4d5d5Solivier moysan ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 48503e4d5d5Solivier moysan SPDIFRX_CR_CBDMAEN, SPDIFRX_CR_CBDMAEN); 48603e4d5d5Solivier moysan if (ret < 0) 48703e4d5d5Solivier moysan goto end; 48803e4d5d5Solivier moysan 48903e4d5d5Solivier moysan ret = stm32_spdifrx_start_sync(spdifrx); 49003e4d5d5Solivier moysan if (ret < 0) 49103e4d5d5Solivier moysan goto end; 49203e4d5d5Solivier moysan 49303e4d5d5Solivier moysan if (wait_for_completion_interruptible_timeout(&spdifrx->cs_completion, 49403e4d5d5Solivier moysan msecs_to_jiffies(100)) 49503e4d5d5Solivier moysan <= 0) { 49603e4d5d5Solivier moysan dev_err(&spdifrx->pdev->dev, "Failed to get control data\n"); 49703e4d5d5Solivier moysan ret = -EAGAIN; 49803e4d5d5Solivier moysan } 49903e4d5d5Solivier moysan 50003e4d5d5Solivier moysan stm32_spdifrx_stop(spdifrx); 50103e4d5d5Solivier moysan stm32_spdifrx_dma_ctrl_stop(spdifrx); 50203e4d5d5Solivier moysan 50303e4d5d5Solivier moysan end: 50403e4d5d5Solivier moysan clk_disable_unprepare(spdifrx->kclk); 50503e4d5d5Solivier moysan 50603e4d5d5Solivier moysan return ret; 50703e4d5d5Solivier moysan } 50803e4d5d5Solivier moysan 50903e4d5d5Solivier moysan static int stm32_spdifrx_capture_get(struct snd_kcontrol *kcontrol, 51003e4d5d5Solivier moysan struct snd_ctl_elem_value *ucontrol) 51103e4d5d5Solivier moysan { 51203e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 51303e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 51403e4d5d5Solivier moysan 51503e4d5d5Solivier moysan stm32_spdifrx_get_ctrl_data(spdifrx); 51603e4d5d5Solivier moysan 51703e4d5d5Solivier moysan ucontrol->value.iec958.status[0] = spdifrx->cs[0]; 51803e4d5d5Solivier moysan ucontrol->value.iec958.status[1] = spdifrx->cs[1]; 51903e4d5d5Solivier moysan ucontrol->value.iec958.status[2] = spdifrx->cs[2]; 52003e4d5d5Solivier moysan ucontrol->value.iec958.status[3] = spdifrx->cs[3]; 52103e4d5d5Solivier moysan ucontrol->value.iec958.status[4] = spdifrx->cs[4]; 52203e4d5d5Solivier moysan 52303e4d5d5Solivier moysan return 0; 52403e4d5d5Solivier moysan } 52503e4d5d5Solivier moysan 52603e4d5d5Solivier moysan static int stm32_spdif_user_bits_get(struct snd_kcontrol *kcontrol, 52703e4d5d5Solivier moysan struct snd_ctl_elem_value *ucontrol) 52803e4d5d5Solivier moysan { 52903e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 53003e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 53103e4d5d5Solivier moysan 53203e4d5d5Solivier moysan stm32_spdifrx_get_ctrl_data(spdifrx); 53303e4d5d5Solivier moysan 53403e4d5d5Solivier moysan ucontrol->value.iec958.status[0] = spdifrx->ub[0]; 53503e4d5d5Solivier moysan ucontrol->value.iec958.status[1] = spdifrx->ub[1]; 53603e4d5d5Solivier moysan ucontrol->value.iec958.status[2] = spdifrx->ub[2]; 53703e4d5d5Solivier moysan ucontrol->value.iec958.status[3] = spdifrx->ub[3]; 53803e4d5d5Solivier moysan ucontrol->value.iec958.status[4] = spdifrx->ub[4]; 53903e4d5d5Solivier moysan 54003e4d5d5Solivier moysan return 0; 54103e4d5d5Solivier moysan } 54203e4d5d5Solivier moysan 54303e4d5d5Solivier moysan static struct snd_kcontrol_new stm32_spdifrx_iec_ctrls[] = { 54403e4d5d5Solivier moysan /* Channel status control */ 54503e4d5d5Solivier moysan { 54603e4d5d5Solivier moysan .iface = SNDRV_CTL_ELEM_IFACE_PCM, 54703e4d5d5Solivier moysan .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), 54803e4d5d5Solivier moysan .access = SNDRV_CTL_ELEM_ACCESS_READ | 54903e4d5d5Solivier moysan SNDRV_CTL_ELEM_ACCESS_VOLATILE, 55003e4d5d5Solivier moysan .info = stm32_spdifrx_info, 55103e4d5d5Solivier moysan .get = stm32_spdifrx_capture_get, 55203e4d5d5Solivier moysan }, 55303e4d5d5Solivier moysan /* User bits control */ 55403e4d5d5Solivier moysan { 55503e4d5d5Solivier moysan .iface = SNDRV_CTL_ELEM_IFACE_PCM, 55603e4d5d5Solivier moysan .name = "IEC958 User Bit Capture Default", 55703e4d5d5Solivier moysan .access = SNDRV_CTL_ELEM_ACCESS_READ | 55803e4d5d5Solivier moysan SNDRV_CTL_ELEM_ACCESS_VOLATILE, 55903e4d5d5Solivier moysan .info = stm32_spdifrx_ub_info, 56003e4d5d5Solivier moysan .get = stm32_spdif_user_bits_get, 56103e4d5d5Solivier moysan }, 56203e4d5d5Solivier moysan }; 56303e4d5d5Solivier moysan 56403e4d5d5Solivier moysan static struct snd_kcontrol_new stm32_spdifrx_ctrls[] = { 56503e4d5d5Solivier moysan SOC_ENUM("SPDIFRX input", ctrl_enum_input), 56603e4d5d5Solivier moysan SOC_ENUM("SPDIFRX CS channel", ctrl_enum_cs_channel), 56703e4d5d5Solivier moysan }; 56803e4d5d5Solivier moysan 56903e4d5d5Solivier moysan static int stm32_spdifrx_dai_register_ctrls(struct snd_soc_dai *cpu_dai) 57003e4d5d5Solivier moysan { 57103e4d5d5Solivier moysan int ret; 57203e4d5d5Solivier moysan 57303e4d5d5Solivier moysan ret = snd_soc_add_dai_controls(cpu_dai, stm32_spdifrx_iec_ctrls, 57403e4d5d5Solivier moysan ARRAY_SIZE(stm32_spdifrx_iec_ctrls)); 57503e4d5d5Solivier moysan if (ret < 0) 57603e4d5d5Solivier moysan return ret; 57703e4d5d5Solivier moysan 57803e4d5d5Solivier moysan return snd_soc_add_component_controls(cpu_dai->component, 57903e4d5d5Solivier moysan stm32_spdifrx_ctrls, 58003e4d5d5Solivier moysan ARRAY_SIZE(stm32_spdifrx_ctrls)); 58103e4d5d5Solivier moysan } 58203e4d5d5Solivier moysan 58303e4d5d5Solivier moysan static int stm32_spdifrx_dai_probe(struct snd_soc_dai *cpu_dai) 58403e4d5d5Solivier moysan { 58503e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(cpu_dai->dev); 58603e4d5d5Solivier moysan 58703e4d5d5Solivier moysan spdifrx->dma_params.addr = (dma_addr_t)(spdifrx->phys_addr + 58803e4d5d5Solivier moysan STM32_SPDIFRX_DR); 58903e4d5d5Solivier moysan spdifrx->dma_params.maxburst = 1; 59003e4d5d5Solivier moysan 59103e4d5d5Solivier moysan snd_soc_dai_init_dma_data(cpu_dai, NULL, &spdifrx->dma_params); 59203e4d5d5Solivier moysan 59303e4d5d5Solivier moysan return stm32_spdifrx_dai_register_ctrls(cpu_dai); 59403e4d5d5Solivier moysan } 59503e4d5d5Solivier moysan 59603e4d5d5Solivier moysan static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) 59703e4d5d5Solivier moysan { 59803e4d5d5Solivier moysan switch (reg) { 59903e4d5d5Solivier moysan case STM32_SPDIFRX_CR: 60003e4d5d5Solivier moysan case STM32_SPDIFRX_IMR: 60103e4d5d5Solivier moysan case STM32_SPDIFRX_SR: 60203e4d5d5Solivier moysan case STM32_SPDIFRX_IFCR: 60303e4d5d5Solivier moysan case STM32_SPDIFRX_DR: 60403e4d5d5Solivier moysan case STM32_SPDIFRX_CSR: 60503e4d5d5Solivier moysan case STM32_SPDIFRX_DIR: 60603e4d5d5Solivier moysan return true; 60703e4d5d5Solivier moysan default: 60803e4d5d5Solivier moysan return false; 60903e4d5d5Solivier moysan } 61003e4d5d5Solivier moysan } 61103e4d5d5Solivier moysan 61203e4d5d5Solivier moysan static bool stm32_spdifrx_volatile_reg(struct device *dev, unsigned int reg) 61303e4d5d5Solivier moysan { 61403e4d5d5Solivier moysan if (reg == STM32_SPDIFRX_DR) 61503e4d5d5Solivier moysan return true; 61603e4d5d5Solivier moysan 61703e4d5d5Solivier moysan return false; 61803e4d5d5Solivier moysan } 61903e4d5d5Solivier moysan 62003e4d5d5Solivier moysan static bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg) 62103e4d5d5Solivier moysan { 62203e4d5d5Solivier moysan switch (reg) { 62303e4d5d5Solivier moysan case STM32_SPDIFRX_CR: 62403e4d5d5Solivier moysan case STM32_SPDIFRX_IMR: 62503e4d5d5Solivier moysan case STM32_SPDIFRX_IFCR: 62603e4d5d5Solivier moysan return true; 62703e4d5d5Solivier moysan default: 62803e4d5d5Solivier moysan return false; 62903e4d5d5Solivier moysan } 63003e4d5d5Solivier moysan } 63103e4d5d5Solivier moysan 63203e4d5d5Solivier moysan static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { 63303e4d5d5Solivier moysan .reg_bits = 32, 63403e4d5d5Solivier moysan .reg_stride = 4, 63503e4d5d5Solivier moysan .val_bits = 32, 63603e4d5d5Solivier moysan .max_register = STM32_SPDIFRX_DIR, 63703e4d5d5Solivier moysan .readable_reg = stm32_spdifrx_readable_reg, 63803e4d5d5Solivier moysan .volatile_reg = stm32_spdifrx_volatile_reg, 63903e4d5d5Solivier moysan .writeable_reg = stm32_spdifrx_writeable_reg, 64003e4d5d5Solivier moysan .fast_io = true, 64103e4d5d5Solivier moysan }; 64203e4d5d5Solivier moysan 64303e4d5d5Solivier moysan static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) 64403e4d5d5Solivier moysan { 64503e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)devid; 64603e4d5d5Solivier moysan struct snd_pcm_substream *substream = spdifrx->substream; 64703e4d5d5Solivier moysan struct platform_device *pdev = spdifrx->pdev; 64803e4d5d5Solivier moysan unsigned int cr, mask, sr, imr; 64903e4d5d5Solivier moysan unsigned int flags; 65003e4d5d5Solivier moysan int err = 0, err_xrun = 0; 65103e4d5d5Solivier moysan 65203e4d5d5Solivier moysan regmap_read(spdifrx->regmap, STM32_SPDIFRX_SR, &sr); 65303e4d5d5Solivier moysan regmap_read(spdifrx->regmap, STM32_SPDIFRX_IMR, &imr); 65403e4d5d5Solivier moysan 65503e4d5d5Solivier moysan mask = imr & SPDIFRX_XIMR_MASK; 65603e4d5d5Solivier moysan /* SERR, TERR, FERR IRQs are generated if IFEIE is set */ 65703e4d5d5Solivier moysan if (mask & SPDIFRX_IMR_IFEIE) 65803e4d5d5Solivier moysan mask |= (SPDIFRX_IMR_IFEIE << 1) | (SPDIFRX_IMR_IFEIE << 2); 65903e4d5d5Solivier moysan 66003e4d5d5Solivier moysan flags = sr & mask; 66103e4d5d5Solivier moysan if (!flags) { 66203e4d5d5Solivier moysan dev_err(&pdev->dev, "Unexpected IRQ. rflags=%#x, imr=%#x\n", 66303e4d5d5Solivier moysan sr, imr); 66403e4d5d5Solivier moysan return IRQ_NONE; 66503e4d5d5Solivier moysan } 66603e4d5d5Solivier moysan 66703e4d5d5Solivier moysan /* Clear IRQs */ 66803e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IFCR, 66903e4d5d5Solivier moysan SPDIFRX_XIFCR_MASK, flags); 67003e4d5d5Solivier moysan 67103e4d5d5Solivier moysan if (flags & SPDIFRX_SR_PERR) { 67203e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Parity error\n"); 67303e4d5d5Solivier moysan err_xrun = 1; 67403e4d5d5Solivier moysan } 67503e4d5d5Solivier moysan 67603e4d5d5Solivier moysan if (flags & SPDIFRX_SR_OVR) { 67703e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Overrun error\n"); 67803e4d5d5Solivier moysan err_xrun = 1; 67903e4d5d5Solivier moysan } 68003e4d5d5Solivier moysan 68103e4d5d5Solivier moysan if (flags & SPDIFRX_SR_SBD) 68203e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Synchronization block detected\n"); 68303e4d5d5Solivier moysan 68403e4d5d5Solivier moysan if (flags & SPDIFRX_SR_SYNCD) { 68503e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Synchronization done\n"); 68603e4d5d5Solivier moysan 68703e4d5d5Solivier moysan /* Enable spdifrx */ 68803e4d5d5Solivier moysan cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_ENABLE); 68903e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 69003e4d5d5Solivier moysan SPDIFRX_CR_SPDIFEN_MASK, cr); 69103e4d5d5Solivier moysan } 69203e4d5d5Solivier moysan 69303e4d5d5Solivier moysan if (flags & SPDIFRX_SR_FERR) { 69403e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Frame error\n"); 69503e4d5d5Solivier moysan err = 1; 69603e4d5d5Solivier moysan } 69703e4d5d5Solivier moysan 69803e4d5d5Solivier moysan if (flags & SPDIFRX_SR_SERR) { 69903e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Synchronization error\n"); 70003e4d5d5Solivier moysan err = 1; 70103e4d5d5Solivier moysan } 70203e4d5d5Solivier moysan 70303e4d5d5Solivier moysan if (flags & SPDIFRX_SR_TERR) { 70403e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Timeout error\n"); 70503e4d5d5Solivier moysan err = 1; 70603e4d5d5Solivier moysan } 70703e4d5d5Solivier moysan 70803e4d5d5Solivier moysan if (err) { 70903e4d5d5Solivier moysan /* SPDIFRX in STATE_STOP. Disable SPDIFRX to clear errors */ 71003e4d5d5Solivier moysan cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); 71103e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 71203e4d5d5Solivier moysan SPDIFRX_CR_SPDIFEN_MASK, cr); 71303e4d5d5Solivier moysan 71403e4d5d5Solivier moysan if (substream) 71503e4d5d5Solivier moysan snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); 71603e4d5d5Solivier moysan 71703e4d5d5Solivier moysan return IRQ_HANDLED; 71803e4d5d5Solivier moysan } 71903e4d5d5Solivier moysan 72003e4d5d5Solivier moysan if (err_xrun && substream) 72103e4d5d5Solivier moysan snd_pcm_stop_xrun(substream); 72203e4d5d5Solivier moysan 72303e4d5d5Solivier moysan return IRQ_HANDLED; 72403e4d5d5Solivier moysan } 72503e4d5d5Solivier moysan 72603e4d5d5Solivier moysan static int stm32_spdifrx_startup(struct snd_pcm_substream *substream, 72703e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai) 72803e4d5d5Solivier moysan { 72903e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 73003e4d5d5Solivier moysan int ret; 73103e4d5d5Solivier moysan 73203e4d5d5Solivier moysan spdifrx->substream = substream; 73303e4d5d5Solivier moysan 73403e4d5d5Solivier moysan ret = clk_prepare_enable(spdifrx->kclk); 73503e4d5d5Solivier moysan if (ret) 73603e4d5d5Solivier moysan dev_err(&spdifrx->pdev->dev, "Enable kclk failed: %d\n", ret); 73703e4d5d5Solivier moysan 73803e4d5d5Solivier moysan return ret; 73903e4d5d5Solivier moysan } 74003e4d5d5Solivier moysan 74103e4d5d5Solivier moysan static int stm32_spdifrx_hw_params(struct snd_pcm_substream *substream, 74203e4d5d5Solivier moysan struct snd_pcm_hw_params *params, 74303e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai) 74403e4d5d5Solivier moysan { 74503e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 74603e4d5d5Solivier moysan int data_size = params_width(params); 74703e4d5d5Solivier moysan int fmt; 74803e4d5d5Solivier moysan 74903e4d5d5Solivier moysan switch (data_size) { 75003e4d5d5Solivier moysan case 16: 75103e4d5d5Solivier moysan fmt = SPDIFRX_DRFMT_PACKED; 75203e4d5d5Solivier moysan break; 75303e4d5d5Solivier moysan case 32: 75403e4d5d5Solivier moysan fmt = SPDIFRX_DRFMT_LEFT; 75503e4d5d5Solivier moysan break; 75603e4d5d5Solivier moysan default: 75703e4d5d5Solivier moysan dev_err(&spdifrx->pdev->dev, "Unexpected data format\n"); 75803e4d5d5Solivier moysan return -EINVAL; 75903e4d5d5Solivier moysan } 76003e4d5d5Solivier moysan 7619036e4acSolivier moysan /* 7629036e4acSolivier moysan * Set buswidth to 4 bytes for all data formats. 7639036e4acSolivier moysan * Packed format: transfer 2 x 2 bytes samples 7649036e4acSolivier moysan * Left format: transfer 1 x 3 bytes samples + 1 dummy byte 7659036e4acSolivier moysan */ 7669036e4acSolivier moysan spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 76703e4d5d5Solivier moysan snd_soc_dai_init_dma_data(cpu_dai, NULL, &spdifrx->dma_params); 76803e4d5d5Solivier moysan 76903e4d5d5Solivier moysan return regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 77003e4d5d5Solivier moysan SPDIFRX_CR_DRFMT_MASK, 77103e4d5d5Solivier moysan SPDIFRX_CR_DRFMTSET(fmt)); 77203e4d5d5Solivier moysan } 77303e4d5d5Solivier moysan 77403e4d5d5Solivier moysan static int stm32_spdifrx_trigger(struct snd_pcm_substream *substream, int cmd, 77503e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai) 77603e4d5d5Solivier moysan { 77703e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 77803e4d5d5Solivier moysan int ret = 0; 77903e4d5d5Solivier moysan 78003e4d5d5Solivier moysan switch (cmd) { 78103e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_START: 78203e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_RESUME: 78303e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 78403e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, 78503e4d5d5Solivier moysan SPDIFRX_IMR_OVRIE, SPDIFRX_IMR_OVRIE); 78603e4d5d5Solivier moysan 78703e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 78803e4d5d5Solivier moysan SPDIFRX_CR_RXDMAEN, SPDIFRX_CR_RXDMAEN); 78903e4d5d5Solivier moysan 79003e4d5d5Solivier moysan ret = stm32_spdifrx_start_sync(spdifrx); 79103e4d5d5Solivier moysan break; 79203e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_SUSPEND: 79303e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 79403e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_STOP: 79503e4d5d5Solivier moysan stm32_spdifrx_stop(spdifrx); 79603e4d5d5Solivier moysan break; 79703e4d5d5Solivier moysan default: 79803e4d5d5Solivier moysan return -EINVAL; 79903e4d5d5Solivier moysan } 80003e4d5d5Solivier moysan 80103e4d5d5Solivier moysan return ret; 80203e4d5d5Solivier moysan } 80303e4d5d5Solivier moysan 80403e4d5d5Solivier moysan static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, 80503e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai) 80603e4d5d5Solivier moysan { 80703e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 80803e4d5d5Solivier moysan 80903e4d5d5Solivier moysan spdifrx->substream = NULL; 81003e4d5d5Solivier moysan clk_disable_unprepare(spdifrx->kclk); 81103e4d5d5Solivier moysan } 81203e4d5d5Solivier moysan 81303e4d5d5Solivier moysan static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { 81403e4d5d5Solivier moysan .startup = stm32_spdifrx_startup, 81503e4d5d5Solivier moysan .hw_params = stm32_spdifrx_hw_params, 81603e4d5d5Solivier moysan .trigger = stm32_spdifrx_trigger, 81703e4d5d5Solivier moysan .shutdown = stm32_spdifrx_shutdown, 81803e4d5d5Solivier moysan }; 81903e4d5d5Solivier moysan 82003e4d5d5Solivier moysan static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { 82103e4d5d5Solivier moysan { 82203e4d5d5Solivier moysan .name = "spdifrx-capture-cpu-dai", 82303e4d5d5Solivier moysan .probe = stm32_spdifrx_dai_probe, 82403e4d5d5Solivier moysan .capture = { 82503e4d5d5Solivier moysan .stream_name = "CPU-Capture", 82603e4d5d5Solivier moysan .channels_min = 1, 82703e4d5d5Solivier moysan .channels_max = 2, 82803e4d5d5Solivier moysan .rates = SNDRV_PCM_RATE_8000_192000, 82903e4d5d5Solivier moysan .formats = SNDRV_PCM_FMTBIT_S32_LE | 83003e4d5d5Solivier moysan SNDRV_PCM_FMTBIT_S16_LE, 83103e4d5d5Solivier moysan }, 83203e4d5d5Solivier moysan .ops = &stm32_spdifrx_pcm_dai_ops, 83303e4d5d5Solivier moysan } 83403e4d5d5Solivier moysan }; 83503e4d5d5Solivier moysan 83603e4d5d5Solivier moysan static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = { 83703e4d5d5Solivier moysan .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, 83803e4d5d5Solivier moysan .buffer_bytes_max = 8 * PAGE_SIZE, 83903e4d5d5Solivier moysan .period_bytes_max = 2048, /* MDMA constraint */ 84003e4d5d5Solivier moysan .periods_min = 2, 84103e4d5d5Solivier moysan .periods_max = 8, 84203e4d5d5Solivier moysan }; 84303e4d5d5Solivier moysan 84403e4d5d5Solivier moysan static const struct snd_soc_component_driver stm32_spdifrx_component = { 84503e4d5d5Solivier moysan .name = "stm32-spdifrx", 84603e4d5d5Solivier moysan }; 84703e4d5d5Solivier moysan 84803e4d5d5Solivier moysan static const struct snd_dmaengine_pcm_config stm32_spdifrx_pcm_config = { 84903e4d5d5Solivier moysan .pcm_hardware = &stm32_spdifrx_pcm_hw, 85003e4d5d5Solivier moysan .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, 85103e4d5d5Solivier moysan }; 85203e4d5d5Solivier moysan 85303e4d5d5Solivier moysan static const struct of_device_id stm32_spdifrx_ids[] = { 85403e4d5d5Solivier moysan { 85503e4d5d5Solivier moysan .compatible = "st,stm32h7-spdifrx", 85603e4d5d5Solivier moysan .data = &stm32_h7_spdifrx_regmap_conf 85703e4d5d5Solivier moysan }, 85803e4d5d5Solivier moysan {} 85903e4d5d5Solivier moysan }; 86003e4d5d5Solivier moysan 861*b9aa4716Solivier moysan static int stm32_spdifrx_parse_of(struct platform_device *pdev, 86203e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx) 86303e4d5d5Solivier moysan { 86403e4d5d5Solivier moysan struct device_node *np = pdev->dev.of_node; 86503e4d5d5Solivier moysan const struct of_device_id *of_id; 86603e4d5d5Solivier moysan struct resource *res; 86703e4d5d5Solivier moysan 86803e4d5d5Solivier moysan if (!np) 86903e4d5d5Solivier moysan return -ENODEV; 87003e4d5d5Solivier moysan 87103e4d5d5Solivier moysan of_id = of_match_device(stm32_spdifrx_ids, &pdev->dev); 87203e4d5d5Solivier moysan if (of_id) 87303e4d5d5Solivier moysan spdifrx->regmap_conf = 87403e4d5d5Solivier moysan (const struct regmap_config *)of_id->data; 87503e4d5d5Solivier moysan else 87603e4d5d5Solivier moysan return -EINVAL; 87703e4d5d5Solivier moysan 87803e4d5d5Solivier moysan res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 87903e4d5d5Solivier moysan spdifrx->base = devm_ioremap_resource(&pdev->dev, res); 88003e4d5d5Solivier moysan if (IS_ERR(spdifrx->base)) 88103e4d5d5Solivier moysan return PTR_ERR(spdifrx->base); 88203e4d5d5Solivier moysan 88303e4d5d5Solivier moysan spdifrx->phys_addr = res->start; 88403e4d5d5Solivier moysan 88503e4d5d5Solivier moysan spdifrx->kclk = devm_clk_get(&pdev->dev, "kclk"); 88603e4d5d5Solivier moysan if (IS_ERR(spdifrx->kclk)) { 88703e4d5d5Solivier moysan dev_err(&pdev->dev, "Could not get kclk\n"); 88803e4d5d5Solivier moysan return PTR_ERR(spdifrx->kclk); 88903e4d5d5Solivier moysan } 89003e4d5d5Solivier moysan 89103e4d5d5Solivier moysan spdifrx->irq = platform_get_irq(pdev, 0); 89203e4d5d5Solivier moysan if (spdifrx->irq < 0) { 89303e4d5d5Solivier moysan dev_err(&pdev->dev, "No irq for node %s\n", pdev->name); 89403e4d5d5Solivier moysan return spdifrx->irq; 89503e4d5d5Solivier moysan } 89603e4d5d5Solivier moysan 89703e4d5d5Solivier moysan return 0; 89803e4d5d5Solivier moysan } 89903e4d5d5Solivier moysan 90003e4d5d5Solivier moysan static int stm32_spdifrx_probe(struct platform_device *pdev) 90103e4d5d5Solivier moysan { 90203e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx; 90303e4d5d5Solivier moysan struct reset_control *rst; 90403e4d5d5Solivier moysan const struct snd_dmaengine_pcm_config *pcm_config = NULL; 90503e4d5d5Solivier moysan int ret; 90603e4d5d5Solivier moysan 90703e4d5d5Solivier moysan spdifrx = devm_kzalloc(&pdev->dev, sizeof(*spdifrx), GFP_KERNEL); 90803e4d5d5Solivier moysan if (!spdifrx) 90903e4d5d5Solivier moysan return -ENOMEM; 91003e4d5d5Solivier moysan 91103e4d5d5Solivier moysan spdifrx->pdev = pdev; 91203e4d5d5Solivier moysan init_completion(&spdifrx->cs_completion); 91303e4d5d5Solivier moysan spin_lock_init(&spdifrx->lock); 91403e4d5d5Solivier moysan 91503e4d5d5Solivier moysan platform_set_drvdata(pdev, spdifrx); 91603e4d5d5Solivier moysan 917*b9aa4716Solivier moysan ret = stm32_spdifrx_parse_of(pdev, spdifrx); 91803e4d5d5Solivier moysan if (ret) 91903e4d5d5Solivier moysan return ret; 92003e4d5d5Solivier moysan 92103e4d5d5Solivier moysan spdifrx->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "kclk", 92203e4d5d5Solivier moysan spdifrx->base, 92303e4d5d5Solivier moysan spdifrx->regmap_conf); 92403e4d5d5Solivier moysan if (IS_ERR(spdifrx->regmap)) { 92503e4d5d5Solivier moysan dev_err(&pdev->dev, "Regmap init failed\n"); 92603e4d5d5Solivier moysan return PTR_ERR(spdifrx->regmap); 92703e4d5d5Solivier moysan } 92803e4d5d5Solivier moysan 92903e4d5d5Solivier moysan ret = devm_request_irq(&pdev->dev, spdifrx->irq, stm32_spdifrx_isr, 0, 93003e4d5d5Solivier moysan dev_name(&pdev->dev), spdifrx); 93103e4d5d5Solivier moysan if (ret) { 93203e4d5d5Solivier moysan dev_err(&pdev->dev, "IRQ request returned %d\n", ret); 93303e4d5d5Solivier moysan return ret; 93403e4d5d5Solivier moysan } 93503e4d5d5Solivier moysan 936635eac1eSPhilipp Zabel rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); 93703e4d5d5Solivier moysan if (!IS_ERR(rst)) { 93803e4d5d5Solivier moysan reset_control_assert(rst); 93903e4d5d5Solivier moysan udelay(2); 94003e4d5d5Solivier moysan reset_control_deassert(rst); 94103e4d5d5Solivier moysan } 94203e4d5d5Solivier moysan 94303e4d5d5Solivier moysan ret = devm_snd_soc_register_component(&pdev->dev, 94403e4d5d5Solivier moysan &stm32_spdifrx_component, 94503e4d5d5Solivier moysan stm32_spdifrx_dai, 94603e4d5d5Solivier moysan ARRAY_SIZE(stm32_spdifrx_dai)); 94703e4d5d5Solivier moysan if (ret) 94803e4d5d5Solivier moysan return ret; 94903e4d5d5Solivier moysan 95003e4d5d5Solivier moysan ret = stm32_spdifrx_dma_ctrl_register(&pdev->dev, spdifrx); 95103e4d5d5Solivier moysan if (ret) 95203e4d5d5Solivier moysan goto error; 95303e4d5d5Solivier moysan 95403e4d5d5Solivier moysan pcm_config = &stm32_spdifrx_pcm_config; 95503e4d5d5Solivier moysan ret = devm_snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); 95603e4d5d5Solivier moysan if (ret) { 95703e4d5d5Solivier moysan dev_err(&pdev->dev, "PCM DMA register returned %d\n", ret); 95803e4d5d5Solivier moysan goto error; 95903e4d5d5Solivier moysan } 96003e4d5d5Solivier moysan 96103e4d5d5Solivier moysan return 0; 96203e4d5d5Solivier moysan 96303e4d5d5Solivier moysan error: 96498c8dc2fSolivier moysan if (!IS_ERR(spdifrx->ctrl_chan)) 96503e4d5d5Solivier moysan dma_release_channel(spdifrx->ctrl_chan); 96603e4d5d5Solivier moysan if (spdifrx->dmab) 96703e4d5d5Solivier moysan snd_dma_free_pages(spdifrx->dmab); 96803e4d5d5Solivier moysan 96903e4d5d5Solivier moysan return ret; 97003e4d5d5Solivier moysan } 97103e4d5d5Solivier moysan 97203e4d5d5Solivier moysan static int stm32_spdifrx_remove(struct platform_device *pdev) 97303e4d5d5Solivier moysan { 97403e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = platform_get_drvdata(pdev); 97503e4d5d5Solivier moysan 97603e4d5d5Solivier moysan if (spdifrx->ctrl_chan) 97703e4d5d5Solivier moysan dma_release_channel(spdifrx->ctrl_chan); 97803e4d5d5Solivier moysan 97903e4d5d5Solivier moysan if (spdifrx->dmab) 98003e4d5d5Solivier moysan snd_dma_free_pages(spdifrx->dmab); 98103e4d5d5Solivier moysan 98203e4d5d5Solivier moysan return 0; 98303e4d5d5Solivier moysan } 98403e4d5d5Solivier moysan 98503e4d5d5Solivier moysan MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids); 98603e4d5d5Solivier moysan 98703e4d5d5Solivier moysan static struct platform_driver stm32_spdifrx_driver = { 98803e4d5d5Solivier moysan .driver = { 98903e4d5d5Solivier moysan .name = "st,stm32-spdifrx", 99003e4d5d5Solivier moysan .of_match_table = stm32_spdifrx_ids, 99103e4d5d5Solivier moysan }, 99203e4d5d5Solivier moysan .probe = stm32_spdifrx_probe, 99303e4d5d5Solivier moysan .remove = stm32_spdifrx_remove, 99403e4d5d5Solivier moysan }; 99503e4d5d5Solivier moysan 99603e4d5d5Solivier moysan module_platform_driver(stm32_spdifrx_driver); 99703e4d5d5Solivier moysan 99803e4d5d5Solivier moysan MODULE_DESCRIPTION("STM32 Soc spdifrx Interface"); 99903e4d5d5Solivier moysan MODULE_AUTHOR("Olivier Moysan, <olivier.moysan@st.com>"); 100003e4d5d5Solivier moysan MODULE_ALIAS("platform:stm32-spdifrx"); 100103e4d5d5Solivier moysan MODULE_LICENSE("GPL v2"); 1002