brintos

brintos / linux-shallow public Read only

0
0
Text · 18.8 KiB · 17ef053 Raw
728 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Xilinx ASoC audio formatter support4//5// Copyright (C) 2018 Xilinx, Inc.6//7// Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>8 9#include <linux/clk.h>10#include <linux/io.h>11#include <linux/module.h>12#include <linux/of_address.h>13#include <linux/of_irq.h>14#include <linux/sizes.h>15 16#include <sound/asoundef.h>17#include <sound/soc.h>18#include <sound/pcm_params.h>19 20#define DRV_NAME "xlnx_formatter_pcm"21 22#define XLNX_S2MM_OFFSET	023#define XLNX_MM2S_OFFSET	0x10024 25#define XLNX_AUD_CORE_CONFIG	0x426#define XLNX_AUD_CTRL		0x1027#define XLNX_AUD_STS		0x1428 29#define AUD_CTRL_RESET_MASK	BIT(1)30#define AUD_CFG_MM2S_MASK	BIT(15)31#define AUD_CFG_S2MM_MASK	BIT(31)32 33#define XLNX_AUD_FS_MULTIPLIER	0x1834#define XLNX_AUD_PERIOD_CONFIG	0x1C35#define XLNX_AUD_BUFF_ADDR_LSB	0x2036#define XLNX_AUD_BUFF_ADDR_MSB	0x2437#define XLNX_AUD_XFER_COUNT	0x2838#define XLNX_AUD_CH_STS_START	0x2C39#define XLNX_BYTES_PER_CH	0x4440#define XLNX_AUD_ALIGN_BYTES	6441 42#define AUD_STS_IOC_IRQ_MASK	BIT(31)43#define AUD_STS_CH_STS_MASK	BIT(29)44#define AUD_CTRL_IOC_IRQ_MASK	BIT(13)45#define AUD_CTRL_TOUT_IRQ_MASK	BIT(14)46#define AUD_CTRL_DMA_EN_MASK	BIT(0)47 48#define CFG_MM2S_CH_MASK	GENMASK(11, 8)49#define CFG_MM2S_CH_SHIFT	850#define CFG_MM2S_XFER_MASK	GENMASK(14, 13)51#define CFG_MM2S_XFER_SHIFT	1352#define CFG_MM2S_PKG_MASK	BIT(12)53 54#define CFG_S2MM_CH_MASK	GENMASK(27, 24)55#define CFG_S2MM_CH_SHIFT	2456#define CFG_S2MM_XFER_MASK	GENMASK(30, 29)57#define CFG_S2MM_XFER_SHIFT	2958#define CFG_S2MM_PKG_MASK	BIT(28)59 60#define AUD_CTRL_DATA_WIDTH_SHIFT	1661#define AUD_CTRL_ACTIVE_CH_SHIFT	1962#define PERIOD_CFG_PERIODS_SHIFT	1663 64#define PERIODS_MIN		265#define PERIODS_MAX		666#define PERIOD_BYTES_MIN	19267#define PERIOD_BYTES_MAX	(50 * 1024)68#define XLNX_PARAM_UNKNOWN	069 70enum bit_depth {71	BIT_DEPTH_8,72	BIT_DEPTH_16,73	BIT_DEPTH_20,74	BIT_DEPTH_24,75	BIT_DEPTH_32,76};77 78struct xlnx_pcm_drv_data {79	void __iomem *mmio;80	bool s2mm_presence;81	bool mm2s_presence;82	int s2mm_irq;83	int mm2s_irq;84	struct snd_pcm_substream *play_stream;85	struct snd_pcm_substream *capture_stream;86	struct clk *axi_clk;87	unsigned int sysclk;88};89 90/*91 * struct xlnx_pcm_stream_param - stream configuration92 * @mmio: base address offset93 * @interleaved: audio channels arrangement in buffer94 * @xfer_mode: data formatting mode during transfer95 * @ch_limit: Maximum channels supported96 * @buffer_size: stream ring buffer size97 */98struct xlnx_pcm_stream_param {99	void __iomem *mmio;100	bool interleaved;101	u32 xfer_mode;102	u32 ch_limit;103	u64 buffer_size;104};105 106static const struct snd_pcm_hardware xlnx_pcm_hardware = {107	.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |108		SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_PAUSE |109		SNDRV_PCM_INFO_RESUME,110	.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |111		   SNDRV_PCM_FMTBIT_S24_LE,112	.channels_min = 2,113	.channels_max = 2,114	.rates = SNDRV_PCM_RATE_8000_192000,115	.rate_min = 8000,116	.rate_max = 192000,117	.buffer_bytes_max = PERIODS_MAX * PERIOD_BYTES_MAX,118	.period_bytes_min = PERIOD_BYTES_MIN,119	.period_bytes_max = PERIOD_BYTES_MAX,120	.periods_min = PERIODS_MIN,121	.periods_max = PERIODS_MAX,122};123 124enum {125	AES_TO_AES,126	AES_TO_PCM,127	PCM_TO_PCM,128	PCM_TO_AES129};130 131static void xlnx_parse_aes_params(u32 chsts_reg1_val, u32 chsts_reg2_val,132				  struct device *dev)133{134	u32 padded, srate, bit_depth, status[2];135 136	if (chsts_reg1_val & IEC958_AES0_PROFESSIONAL) {137		status[0] = chsts_reg1_val & 0xff;138		status[1] = (chsts_reg1_val >> 16) & 0xff;139 140		switch (status[0] & IEC958_AES0_PRO_FS) {141		case IEC958_AES0_PRO_FS_44100:142			srate = 44100;143			break;144		case IEC958_AES0_PRO_FS_48000:145			srate = 48000;146			break;147		case IEC958_AES0_PRO_FS_32000:148			srate = 32000;149			break;150		case IEC958_AES0_PRO_FS_NOTID:151		default:152			srate = XLNX_PARAM_UNKNOWN;153			break;154		}155 156		switch (status[1] & IEC958_AES2_PRO_SBITS) {157		case IEC958_AES2_PRO_WORDLEN_NOTID:158		case IEC958_AES2_PRO_SBITS_20:159			padded = 0;160			break;161		case IEC958_AES2_PRO_SBITS_24:162			padded = 4;163			break;164		default:165			bit_depth = XLNX_PARAM_UNKNOWN;166			goto log_params;167		}168 169		switch (status[1] & IEC958_AES2_PRO_WORDLEN) {170		case IEC958_AES2_PRO_WORDLEN_20_16:171			bit_depth = 16 + padded;172			break;173		case IEC958_AES2_PRO_WORDLEN_22_18:174			bit_depth = 18 + padded;175			break;176		case IEC958_AES2_PRO_WORDLEN_23_19:177			bit_depth = 19 + padded;178			break;179		case IEC958_AES2_PRO_WORDLEN_24_20:180			bit_depth = 20 + padded;181			break;182		case IEC958_AES2_PRO_WORDLEN_NOTID:183		default:184			bit_depth = XLNX_PARAM_UNKNOWN;185			break;186		}187 188	} else {189		status[0] = (chsts_reg1_val >> 24) & 0xff;190		status[1] = chsts_reg2_val & 0xff;191 192		switch (status[0] & IEC958_AES3_CON_FS) {193		case IEC958_AES3_CON_FS_44100:194			srate = 44100;195			break;196		case IEC958_AES3_CON_FS_48000:197			srate = 48000;198			break;199		case IEC958_AES3_CON_FS_32000:200			srate = 32000;201			break;202		default:203			srate = XLNX_PARAM_UNKNOWN;204			break;205		}206 207		if (status[1] & IEC958_AES4_CON_MAX_WORDLEN_24)208			padded = 4;209		else210			padded = 0;211 212		switch (status[1] & IEC958_AES4_CON_WORDLEN) {213		case IEC958_AES4_CON_WORDLEN_20_16:214			bit_depth = 16 + padded;215			break;216		case IEC958_AES4_CON_WORDLEN_22_18:217			bit_depth = 18 + padded;218			break;219		case IEC958_AES4_CON_WORDLEN_23_19:220			bit_depth = 19 + padded;221			break;222		case IEC958_AES4_CON_WORDLEN_24_20:223			bit_depth = 20 + padded;224			break;225		case IEC958_AES4_CON_WORDLEN_21_17:226			bit_depth = 17 + padded;227			break;228		case IEC958_AES4_CON_WORDLEN_NOTID:229		default:230			bit_depth = XLNX_PARAM_UNKNOWN;231			break;232		}233	}234 235log_params:236	if (srate != XLNX_PARAM_UNKNOWN)237		dev_info(dev, "sample rate = %d\n", srate);238	else239		dev_info(dev, "sample rate = unknown\n");240 241	if (bit_depth != XLNX_PARAM_UNKNOWN)242		dev_info(dev, "bit_depth = %d\n", bit_depth);243	else244		dev_info(dev, "bit_depth = unknown\n");245}246 247static int xlnx_formatter_pcm_reset(void __iomem *mmio_base)248{249	u32 val, retries = 0;250 251	val = readl(mmio_base + XLNX_AUD_CTRL);252	val |= AUD_CTRL_RESET_MASK;253	writel(val, mmio_base + XLNX_AUD_CTRL);254 255	val = readl(mmio_base + XLNX_AUD_CTRL);256	/* Poll for maximum timeout of approximately 100ms (1 * 100)*/257	while ((val & AUD_CTRL_RESET_MASK) && (retries < 100)) {258		mdelay(1);259		retries++;260		val = readl(mmio_base + XLNX_AUD_CTRL);261	}262	if (val & AUD_CTRL_RESET_MASK)263		return -ENODEV;264 265	return 0;266}267 268static void xlnx_formatter_disable_irqs(void __iomem *mmio_base, int stream)269{270	u32 val;271 272	val = readl(mmio_base + XLNX_AUD_CTRL);273	val &= ~AUD_CTRL_IOC_IRQ_MASK;274	if (stream == SNDRV_PCM_STREAM_CAPTURE)275		val &= ~AUD_CTRL_TOUT_IRQ_MASK;276 277	writel(val, mmio_base + XLNX_AUD_CTRL);278}279 280static irqreturn_t xlnx_mm2s_irq_handler(int irq, void *arg)281{282	u32 val;283	void __iomem *reg;284	struct device *dev = arg;285	struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev);286 287	reg = adata->mmio + XLNX_MM2S_OFFSET + XLNX_AUD_STS;288	val = readl(reg);289	if (val & AUD_STS_IOC_IRQ_MASK) {290		writel(val & AUD_STS_IOC_IRQ_MASK, reg);291		if (adata->play_stream)292			snd_pcm_period_elapsed(adata->play_stream);293		return IRQ_HANDLED;294	}295 296	return IRQ_NONE;297}298 299static irqreturn_t xlnx_s2mm_irq_handler(int irq, void *arg)300{301	u32 val;302	void __iomem *reg;303	struct device *dev = arg;304	struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev);305 306	reg = adata->mmio + XLNX_S2MM_OFFSET + XLNX_AUD_STS;307	val = readl(reg);308	if (val & AUD_STS_IOC_IRQ_MASK) {309		writel(val & AUD_STS_IOC_IRQ_MASK, reg);310		if (adata->capture_stream)311			snd_pcm_period_elapsed(adata->capture_stream);312		return IRQ_HANDLED;313	}314 315	return IRQ_NONE;316}317 318static int xlnx_formatter_set_sysclk(struct snd_soc_component *component,319				     int clk_id, int source, unsigned int freq, int dir)320{321	struct xlnx_pcm_drv_data *adata = dev_get_drvdata(component->dev);322 323	adata->sysclk = freq;324	return 0;325}326 327static int xlnx_formatter_pcm_open(struct snd_soc_component *component,328				   struct snd_pcm_substream *substream)329{330	int err;331	u32 val, data_format_mode;332	u32 ch_count_mask, ch_count_shift, data_xfer_mode, data_xfer_shift;333	struct xlnx_pcm_stream_param *stream_data;334	struct snd_pcm_runtime *runtime = substream->runtime;335	struct xlnx_pcm_drv_data *adata = dev_get_drvdata(component->dev);336 337	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&338	    !adata->mm2s_presence)339		return -ENODEV;340	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&341		 !adata->s2mm_presence)342		return -ENODEV;343 344	stream_data = kzalloc(sizeof(*stream_data), GFP_KERNEL);345	if (!stream_data)346		return -ENOMEM;347 348	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {349		ch_count_mask = CFG_MM2S_CH_MASK;350		ch_count_shift = CFG_MM2S_CH_SHIFT;351		data_xfer_mode = CFG_MM2S_XFER_MASK;352		data_xfer_shift = CFG_MM2S_XFER_SHIFT;353		data_format_mode = CFG_MM2S_PKG_MASK;354		stream_data->mmio = adata->mmio + XLNX_MM2S_OFFSET;355		adata->play_stream = substream;356 357	} else {358		ch_count_mask = CFG_S2MM_CH_MASK;359		ch_count_shift = CFG_S2MM_CH_SHIFT;360		data_xfer_mode = CFG_S2MM_XFER_MASK;361		data_xfer_shift = CFG_S2MM_XFER_SHIFT;362		data_format_mode = CFG_S2MM_PKG_MASK;363		stream_data->mmio = adata->mmio + XLNX_S2MM_OFFSET;364		adata->capture_stream = substream;365	}366 367	val = readl(adata->mmio + XLNX_AUD_CORE_CONFIG);368 369	if (!(val & data_format_mode))370		stream_data->interleaved = true;371 372	stream_data->xfer_mode = (val & data_xfer_mode) >> data_xfer_shift;373	stream_data->ch_limit = (val & ch_count_mask) >> ch_count_shift;374	dev_info(component->dev,375		 "stream %d : format = %d mode = %d ch_limit = %d\n",376		 substream->stream, stream_data->interleaved,377		 stream_data->xfer_mode, stream_data->ch_limit);378 379	snd_soc_set_runtime_hwparams(substream, &xlnx_pcm_hardware);380	runtime->private_data = stream_data;381 382	/* Resize the period bytes as divisible by 64 */383	err = snd_pcm_hw_constraint_step(runtime, 0,384					 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,385					 XLNX_AUD_ALIGN_BYTES);386	if (err) {387		dev_err(component->dev,388			"Unable to set constraint on period bytes\n");389		return err;390	}391 392	/* Resize the buffer bytes as divisible by 64 */393	err = snd_pcm_hw_constraint_step(runtime, 0,394					 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,395					 XLNX_AUD_ALIGN_BYTES);396	if (err) {397		dev_err(component->dev,398			"Unable to set constraint on buffer bytes\n");399		return err;400	}401 402	/* Set periods as integer multiple */403	err = snd_pcm_hw_constraint_integer(runtime,404					    SNDRV_PCM_HW_PARAM_PERIODS);405	if (err < 0) {406		dev_err(component->dev,407			"Unable to set constraint on periods to be integer\n");408		return err;409	}410 411	/* enable DMA IOC irq */412	val = readl(stream_data->mmio + XLNX_AUD_CTRL);413	val |= AUD_CTRL_IOC_IRQ_MASK;414	writel(val, stream_data->mmio + XLNX_AUD_CTRL);415 416	return 0;417}418 419static int xlnx_formatter_pcm_close(struct snd_soc_component *component,420				    struct snd_pcm_substream *substream)421{422	int ret;423	struct xlnx_pcm_stream_param *stream_data =424			substream->runtime->private_data;425 426	ret = xlnx_formatter_pcm_reset(stream_data->mmio);427	if (ret) {428		dev_err(component->dev, "audio formatter reset failed\n");429		goto err_reset;430	}431	xlnx_formatter_disable_irqs(stream_data->mmio, substream->stream);432 433err_reset:434	kfree(stream_data);435	return 0;436}437 438static snd_pcm_uframes_t439xlnx_formatter_pcm_pointer(struct snd_soc_component *component,440			   struct snd_pcm_substream *substream)441{442	u32 pos;443	struct snd_pcm_runtime *runtime = substream->runtime;444	struct xlnx_pcm_stream_param *stream_data = runtime->private_data;445 446	pos = readl(stream_data->mmio + XLNX_AUD_XFER_COUNT);447 448	if (pos >= stream_data->buffer_size)449		pos = 0;450 451	return bytes_to_frames(runtime, pos);452}453 454static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component,455					struct snd_pcm_substream *substream,456					struct snd_pcm_hw_params *params)457{458	u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample;459	u32 aes_reg1_val, aes_reg2_val;460	u64 size;461	struct snd_pcm_runtime *runtime = substream->runtime;462	struct xlnx_pcm_stream_param *stream_data = runtime->private_data;463	struct xlnx_pcm_drv_data *adata = dev_get_drvdata(component->dev);464 465	active_ch = params_channels(params);466	if (active_ch > stream_data->ch_limit)467		return -EINVAL;468 469	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&470	    adata->sysclk) {471		unsigned int mclk_fs = adata->sysclk / params_rate(params);472 473		if (adata->sysclk % params_rate(params) != 0) {474			dev_warn(component->dev, "sysclk %u not divisible by rate %u\n",475				 adata->sysclk, params_rate(params));476			return -EINVAL;477		}478 479		writel(mclk_fs, stream_data->mmio + XLNX_AUD_FS_MULTIPLIER);480	}481 482	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&483	    stream_data->xfer_mode == AES_TO_PCM) {484		val = readl(stream_data->mmio + XLNX_AUD_STS);485		if (val & AUD_STS_CH_STS_MASK) {486			aes_reg1_val = readl(stream_data->mmio +487					     XLNX_AUD_CH_STS_START);488			aes_reg2_val = readl(stream_data->mmio +489					     XLNX_AUD_CH_STS_START + 0x4);490 491			xlnx_parse_aes_params(aes_reg1_val, aes_reg2_val,492					      component->dev);493		}494	}495 496	size = params_buffer_bytes(params);497 498	stream_data->buffer_size = size;499 500	low = lower_32_bits(runtime->dma_addr);501	high = upper_32_bits(runtime->dma_addr);502	writel(low, stream_data->mmio + XLNX_AUD_BUFF_ADDR_LSB);503	writel(high, stream_data->mmio + XLNX_AUD_BUFF_ADDR_MSB);504 505	val = readl(stream_data->mmio + XLNX_AUD_CTRL);506	bits_per_sample = params_width(params);507	switch (bits_per_sample) {508	case 8:509		val |= (BIT_DEPTH_8 << AUD_CTRL_DATA_WIDTH_SHIFT);510		break;511	case 16:512		val |= (BIT_DEPTH_16 << AUD_CTRL_DATA_WIDTH_SHIFT);513		break;514	case 20:515		val |= (BIT_DEPTH_20 << AUD_CTRL_DATA_WIDTH_SHIFT);516		break;517	case 24:518		val |= (BIT_DEPTH_24 << AUD_CTRL_DATA_WIDTH_SHIFT);519		break;520	case 32:521		val |= (BIT_DEPTH_32 << AUD_CTRL_DATA_WIDTH_SHIFT);522		break;523	default:524		return -EINVAL;525	}526 527	val |= active_ch << AUD_CTRL_ACTIVE_CH_SHIFT;528	writel(val, stream_data->mmio + XLNX_AUD_CTRL);529 530	val = (params_periods(params) << PERIOD_CFG_PERIODS_SHIFT)531		| params_period_bytes(params);532	writel(val, stream_data->mmio + XLNX_AUD_PERIOD_CONFIG);533	bytes_per_ch = DIV_ROUND_UP(params_period_bytes(params), active_ch);534	writel(bytes_per_ch, stream_data->mmio + XLNX_BYTES_PER_CH);535 536	return 0;537}538 539static int xlnx_formatter_pcm_trigger(struct snd_soc_component *component,540				      struct snd_pcm_substream *substream,541				      int cmd)542{543	u32 val;544	struct xlnx_pcm_stream_param *stream_data =545			substream->runtime->private_data;546 547	switch (cmd) {548	case SNDRV_PCM_TRIGGER_START:549	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:550	case SNDRV_PCM_TRIGGER_RESUME:551		val = readl(stream_data->mmio + XLNX_AUD_CTRL);552		val |= AUD_CTRL_DMA_EN_MASK;553		writel(val, stream_data->mmio + XLNX_AUD_CTRL);554		break;555	case SNDRV_PCM_TRIGGER_STOP:556	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:557	case SNDRV_PCM_TRIGGER_SUSPEND:558		val = readl(stream_data->mmio + XLNX_AUD_CTRL);559		val &= ~AUD_CTRL_DMA_EN_MASK;560		writel(val, stream_data->mmio + XLNX_AUD_CTRL);561		break;562	}563 564	return 0;565}566 567static int xlnx_formatter_pcm_new(struct snd_soc_component *component,568				  struct snd_soc_pcm_runtime *rtd)569{570	snd_pcm_set_managed_buffer_all(rtd->pcm,571			SNDRV_DMA_TYPE_DEV, component->dev,572			xlnx_pcm_hardware.buffer_bytes_max,573			xlnx_pcm_hardware.buffer_bytes_max);574	return 0;575}576 577static const struct snd_soc_component_driver xlnx_asoc_component = {578	.name			= DRV_NAME,579	.set_sysclk		= xlnx_formatter_set_sysclk,580	.open			= xlnx_formatter_pcm_open,581	.close			= xlnx_formatter_pcm_close,582	.hw_params		= xlnx_formatter_pcm_hw_params,583	.trigger		= xlnx_formatter_pcm_trigger,584	.pointer		= xlnx_formatter_pcm_pointer,585	.pcm_construct		= xlnx_formatter_pcm_new,586};587 588static int xlnx_formatter_pcm_probe(struct platform_device *pdev)589{590	int ret;591	u32 val;592	struct xlnx_pcm_drv_data *aud_drv_data;593	struct device *dev = &pdev->dev;594 595	aud_drv_data = devm_kzalloc(dev, sizeof(*aud_drv_data), GFP_KERNEL);596	if (!aud_drv_data)597		return -ENOMEM;598 599	aud_drv_data->axi_clk = devm_clk_get(dev, "s_axi_lite_aclk");600	if (IS_ERR(aud_drv_data->axi_clk)) {601		ret = PTR_ERR(aud_drv_data->axi_clk);602		dev_err(dev, "failed to get s_axi_lite_aclk(%d)\n", ret);603		return ret;604	}605	ret = clk_prepare_enable(aud_drv_data->axi_clk);606	if (ret) {607		dev_err(dev,608			"failed to enable s_axi_lite_aclk(%d)\n", ret);609		return ret;610	}611 612	aud_drv_data->mmio = devm_platform_ioremap_resource(pdev, 0);613	if (IS_ERR(aud_drv_data->mmio)) {614		dev_err(dev, "audio formatter ioremap failed\n");615		ret = PTR_ERR(aud_drv_data->mmio);616		goto clk_err;617	}618 619	val = readl(aud_drv_data->mmio + XLNX_AUD_CORE_CONFIG);620	if (val & AUD_CFG_MM2S_MASK) {621		aud_drv_data->mm2s_presence = true;622		ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio +623					       XLNX_MM2S_OFFSET);624		if (ret) {625			dev_err(dev, "audio formatter reset failed\n");626			goto clk_err;627		}628		xlnx_formatter_disable_irqs(aud_drv_data->mmio +629					    XLNX_MM2S_OFFSET,630					    SNDRV_PCM_STREAM_PLAYBACK);631 632		aud_drv_data->mm2s_irq = platform_get_irq_byname(pdev,633								 "irq_mm2s");634		if (aud_drv_data->mm2s_irq < 0) {635			ret = aud_drv_data->mm2s_irq;636			goto clk_err;637		}638		ret = devm_request_irq(dev, aud_drv_data->mm2s_irq,639				       xlnx_mm2s_irq_handler, 0,640				       "xlnx_formatter_pcm_mm2s_irq", dev);641		if (ret) {642			dev_err(dev, "xlnx audio mm2s irq request failed\n");643			goto clk_err;644		}645	}646	if (val & AUD_CFG_S2MM_MASK) {647		aud_drv_data->s2mm_presence = true;648		ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio +649					       XLNX_S2MM_OFFSET);650		if (ret) {651			dev_err(dev, "audio formatter reset failed\n");652			goto clk_err;653		}654		xlnx_formatter_disable_irqs(aud_drv_data->mmio +655					    XLNX_S2MM_OFFSET,656					    SNDRV_PCM_STREAM_CAPTURE);657 658		aud_drv_data->s2mm_irq = platform_get_irq_byname(pdev,659								 "irq_s2mm");660		if (aud_drv_data->s2mm_irq < 0) {661			ret = aud_drv_data->s2mm_irq;662			goto clk_err;663		}664		ret = devm_request_irq(dev, aud_drv_data->s2mm_irq,665				       xlnx_s2mm_irq_handler, 0,666				       "xlnx_formatter_pcm_s2mm_irq",667				       dev);668		if (ret) {669			dev_err(dev, "xlnx audio s2mm irq request failed\n");670			goto clk_err;671		}672	}673 674	dev_set_drvdata(dev, aud_drv_data);675 676	ret = devm_snd_soc_register_component(dev, &xlnx_asoc_component,677					      NULL, 0);678	if (ret) {679		dev_err(dev, "pcm platform device register failed\n");680		goto clk_err;681	}682 683	return 0;684 685clk_err:686	clk_disable_unprepare(aud_drv_data->axi_clk);687	return ret;688}689 690static void xlnx_formatter_pcm_remove(struct platform_device *pdev)691{692	int ret = 0;693	struct xlnx_pcm_drv_data *adata = dev_get_drvdata(&pdev->dev);694 695	if (adata->s2mm_presence)696		ret = xlnx_formatter_pcm_reset(adata->mmio + XLNX_S2MM_OFFSET);697 698	/* Try MM2S reset, even if S2MM  reset fails */699	if (adata->mm2s_presence)700		ret = xlnx_formatter_pcm_reset(adata->mmio + XLNX_MM2S_OFFSET);701 702	if (ret)703		dev_err(&pdev->dev, "audio formatter reset failed\n");704 705	clk_disable_unprepare(adata->axi_clk);706}707 708static const struct of_device_id xlnx_formatter_pcm_of_match[] = {709	{ .compatible = "xlnx,audio-formatter-1.0"},710	{},711};712MODULE_DEVICE_TABLE(of, xlnx_formatter_pcm_of_match);713 714static struct platform_driver xlnx_formatter_pcm_driver = {715	.probe	= xlnx_formatter_pcm_probe,716	.remove = xlnx_formatter_pcm_remove,717	.driver	= {718		.name	= DRV_NAME,719		.of_match_table	= xlnx_formatter_pcm_of_match,720	},721};722 723module_platform_driver(xlnx_formatter_pcm_driver);724 725MODULE_DESCRIPTION("ASoC driver for Xilinx audio formatter");726MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>");727MODULE_LICENSE("GPL v2");728