brintos

brintos / linux-shallow public Read only

0
0
Text · 5.0 KiB · e0e00ec Raw
189 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Copyright (c) 2020 BayLibre, SAS.4// Author: Jerome Brunet <jbrunet@baylibre.com>5 6#include <linux/clk.h>7#include <sound/pcm_params.h>8#include <sound/soc.h>9#include <sound/soc-dai.h>10 11#include "aiu.h"12#include "aiu-fifo.h"13 14#define AIU_IEC958_DCU_FF_CTRL_EN		BIT(0)15#define AIU_IEC958_DCU_FF_CTRL_AUTO_DISABLE	BIT(1)16#define AIU_IEC958_DCU_FF_CTRL_IRQ_MODE		GENMASK(3, 2)17#define AIU_IEC958_DCU_FF_CTRL_IRQ_OUT_THD	BIT(2)18#define AIU_IEC958_DCU_FF_CTRL_IRQ_FRAME_READ	BIT(3)19#define AIU_IEC958_DCU_FF_CTRL_SYNC_HEAD_EN	BIT(4)20#define AIU_IEC958_DCU_FF_CTRL_BYTE_SEEK	BIT(5)21#define AIU_IEC958_DCU_FF_CTRL_CONTINUE		BIT(6)22#define AIU_MEM_IEC958_CONTROL_ENDIAN		GENMASK(5, 3)23#define AIU_MEM_IEC958_CONTROL_RD_DDR		BIT(6)24#define AIU_MEM_IEC958_CONTROL_MODE_16BIT	BIT(7)25#define AIU_MEM_IEC958_CONTROL_MODE_LINEAR	BIT(8)26#define AIU_MEM_IEC958_BUF_CNTL_INIT		BIT(0)27 28#define AIU_FIFO_SPDIF_BLOCK			829 30static const struct snd_pcm_hardware fifo_spdif_pcm = {31	.info = (SNDRV_PCM_INFO_INTERLEAVED |32		 SNDRV_PCM_INFO_MMAP |33		 SNDRV_PCM_INFO_MMAP_VALID |34		 SNDRV_PCM_INFO_PAUSE),35	.formats = AIU_FORMATS,36	.rate_min = 5512,37	.rate_max = 192000,38	.channels_min = 2,39	.channels_max = 2,40	.period_bytes_min = AIU_FIFO_SPDIF_BLOCK,41	.period_bytes_max = AIU_FIFO_SPDIF_BLOCK * USHRT_MAX,42	.periods_min = 2,43	.periods_max = UINT_MAX,44 45	/* No real justification for this */46	.buffer_bytes_max = 1 * 1024 * 1024,47};48 49static void fifo_spdif_dcu_enable(struct snd_soc_component *component,50				  bool enable)51{52	snd_soc_component_update_bits(component, AIU_IEC958_DCU_FF_CTRL,53				      AIU_IEC958_DCU_FF_CTRL_EN,54				      enable ? AIU_IEC958_DCU_FF_CTRL_EN : 0);55}56 57static int fifo_spdif_trigger(struct snd_pcm_substream *substream, int cmd,58			      struct snd_soc_dai *dai)59{60	struct snd_soc_component *component = dai->component;61	int ret;62 63	ret = aiu_fifo_trigger(substream, cmd, dai);64	if (ret)65		return ret;66 67	switch (cmd) {68	case SNDRV_PCM_TRIGGER_START:69	case SNDRV_PCM_TRIGGER_RESUME:70	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:71		fifo_spdif_dcu_enable(component, true);72		break;73	case SNDRV_PCM_TRIGGER_SUSPEND:74	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:75	case SNDRV_PCM_TRIGGER_STOP:76		fifo_spdif_dcu_enable(component, false);77		break;78	default:79		return -EINVAL;80	}81 82	return 0;83}84 85static int fifo_spdif_prepare(struct snd_pcm_substream *substream,86			      struct snd_soc_dai *dai)87{88	struct snd_soc_component *component = dai->component;89	int ret;90 91	ret = aiu_fifo_prepare(substream, dai);92	if (ret)93		return ret;94 95	snd_soc_component_update_bits(component,96				      AIU_MEM_IEC958_BUF_CNTL,97				      AIU_MEM_IEC958_BUF_CNTL_INIT,98				      AIU_MEM_IEC958_BUF_CNTL_INIT);99	snd_soc_component_update_bits(component,100				      AIU_MEM_IEC958_BUF_CNTL,101				      AIU_MEM_IEC958_BUF_CNTL_INIT, 0);102 103	return 0;104}105 106static int fifo_spdif_hw_params(struct snd_pcm_substream *substream,107				struct snd_pcm_hw_params *params,108				struct snd_soc_dai *dai)109{110	struct snd_soc_component *component = dai->component;111	unsigned int val;112	int ret;113 114	ret = aiu_fifo_hw_params(substream, params, dai);115	if (ret)116		return ret;117 118	val = AIU_MEM_IEC958_CONTROL_RD_DDR |119	      AIU_MEM_IEC958_CONTROL_MODE_LINEAR;120 121	switch (params_physical_width(params)) {122	case 16:123		val |= AIU_MEM_IEC958_CONTROL_MODE_16BIT;124		break;125	case 32:126		break;127	default:128		dev_err(dai->dev, "Unsupported physical width %u\n",129			params_physical_width(params));130		return -EINVAL;131	}132 133	snd_soc_component_update_bits(component, AIU_MEM_IEC958_CONTROL,134				      AIU_MEM_IEC958_CONTROL_ENDIAN |135				      AIU_MEM_IEC958_CONTROL_RD_DDR |136				      AIU_MEM_IEC958_CONTROL_MODE_LINEAR |137				      AIU_MEM_IEC958_CONTROL_MODE_16BIT,138				      val);139 140	/* Number bytes read by the FIFO between each IRQ */141	snd_soc_component_write(component, AIU_IEC958_BPF,142				params_period_bytes(params));143 144	/*145	 * AUTO_DISABLE and SYNC_HEAD are enabled by default but146	 * this should be disabled in PCM (uncompressed) mode147	 */148	snd_soc_component_update_bits(component, AIU_IEC958_DCU_FF_CTRL,149				      AIU_IEC958_DCU_FF_CTRL_AUTO_DISABLE |150				      AIU_IEC958_DCU_FF_CTRL_IRQ_MODE |151				      AIU_IEC958_DCU_FF_CTRL_SYNC_HEAD_EN,152				      AIU_IEC958_DCU_FF_CTRL_IRQ_FRAME_READ);153 154	return 0;155}156 157const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = {158	.pcm_new	= aiu_fifo_pcm_new,159	.probe		= aiu_fifo_spdif_dai_probe,160	.remove		= aiu_fifo_dai_remove,161	.trigger	= fifo_spdif_trigger,162	.prepare	= fifo_spdif_prepare,163	.hw_params	= fifo_spdif_hw_params,164	.startup	= aiu_fifo_startup,165	.shutdown	= aiu_fifo_shutdown,166};167 168int aiu_fifo_spdif_dai_probe(struct snd_soc_dai *dai)169{170	struct snd_soc_component *component = dai->component;171	struct aiu *aiu = snd_soc_component_get_drvdata(component);172	struct aiu_fifo *fifo;173	int ret;174 175	ret = aiu_fifo_dai_probe(dai);176	if (ret)177		return ret;178 179	fifo = snd_soc_dai_dma_data_get_playback(dai);180 181	fifo->pcm = &fifo_spdif_pcm;182	fifo->mem_offset = AIU_MEM_IEC958_START;183	fifo->fifo_block = 1;184	fifo->pclk = aiu->spdif.clks[PCLK].clk;185	fifo->irq = aiu->spdif.irq;186 187	return 0;188}189