cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xlnx_formatter_pcm.c (19183B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Xilinx ASoC audio formatter support
      4//
      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	0
     23#define XLNX_MM2S_OFFSET	0x100
     24
     25#define XLNX_AUD_CORE_CONFIG	0x4
     26#define XLNX_AUD_CTRL		0x10
     27#define XLNX_AUD_STS		0x14
     28
     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	0x18
     34#define XLNX_AUD_PERIOD_CONFIG	0x1C
     35#define XLNX_AUD_BUFF_ADDR_LSB	0x20
     36#define XLNX_AUD_BUFF_ADDR_MSB	0x24
     37#define XLNX_AUD_XFER_COUNT	0x28
     38#define XLNX_AUD_CH_STS_START	0x2C
     39#define XLNX_BYTES_PER_CH	0x44
     40#define XLNX_AUD_ALIGN_BYTES	64
     41
     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	8
     50#define CFG_MM2S_XFER_MASK	GENMASK(14, 13)
     51#define CFG_MM2S_XFER_SHIFT	13
     52#define CFG_MM2S_PKG_MASK	BIT(12)
     53
     54#define CFG_S2MM_CH_MASK	GENMASK(27, 24)
     55#define CFG_S2MM_CH_SHIFT	24
     56#define CFG_S2MM_XFER_MASK	GENMASK(30, 29)
     57#define CFG_S2MM_XFER_SHIFT	29
     58#define CFG_S2MM_PKG_MASK	BIT(28)
     59
     60#define AUD_CTRL_DATA_WIDTH_SHIFT	16
     61#define AUD_CTRL_ACTIVE_CH_SHIFT	19
     62#define PERIOD_CFG_PERIODS_SHIFT	16
     63
     64#define PERIODS_MIN		2
     65#define PERIODS_MAX		6
     66#define PERIOD_BYTES_MIN	192
     67#define PERIOD_BYTES_MAX	(50 * 1024)
     68#define XLNX_PARAM_UNKNOWN	0
     69
     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 configuration
     92 * @mmio: base address offset
     93 * @interleaved: audio channels arrangement in buffer
     94 * @xfer_mode: data formatting mode during transfer
     95 * @ch_limit: Maximum channels supported
     96 * @buffer_size: stream ring buffer size
     97 */
     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_AES
    129};
    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		else
    210			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	else
    239		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	else
    244		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_t
    439xlnx_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 int 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	return ret;
    707}
    708
    709static const struct of_device_id xlnx_formatter_pcm_of_match[] = {
    710	{ .compatible = "xlnx,audio-formatter-1.0"},
    711	{},
    712};
    713MODULE_DEVICE_TABLE(of, xlnx_formatter_pcm_of_match);
    714
    715static struct platform_driver xlnx_formatter_pcm_driver = {
    716	.probe	= xlnx_formatter_pcm_probe,
    717	.remove	= xlnx_formatter_pcm_remove,
    718	.driver	= {
    719		.name	= DRV_NAME,
    720		.of_match_table	= xlnx_formatter_pcm_of_match,
    721	},
    722};
    723
    724module_platform_driver(xlnx_formatter_pcm_driver);
    725MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>");
    726MODULE_LICENSE("GPL v2");