162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2012
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
662306a36Sopenharmony_ci *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
762306a36Sopenharmony_ci *         for ST-Ericsson.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <asm/page.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1462306a36Sopenharmony_ci#include <linux/dmaengine.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <sound/pcm.h>
1862306a36Sopenharmony_ci#include <sound/pcm_params.h>
1962306a36Sopenharmony_ci#include <sound/soc.h>
2062306a36Sopenharmony_ci#include <sound/dmaengine_pcm.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "ux500_msp_i2s.h"
2362306a36Sopenharmony_ci#include "ux500_pcm.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define UX500_PLATFORM_PERIODS_BYTES_MIN	128
2662306a36Sopenharmony_ci#define UX500_PLATFORM_PERIODS_BYTES_MAX	(64 * PAGE_SIZE)
2762306a36Sopenharmony_ci#define UX500_PLATFORM_PERIODS_MIN		2
2862306a36Sopenharmony_ci#define UX500_PLATFORM_PERIODS_MAX		48
2962306a36Sopenharmony_ci#define UX500_PLATFORM_BUFFER_BYTES_MAX		(2048 * PAGE_SIZE)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic int ux500_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
3262306a36Sopenharmony_ci		struct snd_pcm_hw_params *params,
3362306a36Sopenharmony_ci		struct dma_slave_config *slave_config)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
3662306a36Sopenharmony_ci	struct snd_dmaengine_dai_dma_data *snd_dma_params;
3762306a36Sopenharmony_ci	dma_addr_t dma_addr;
3862306a36Sopenharmony_ci	int ret;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	snd_dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
4162306a36Sopenharmony_ci	dma_addr = snd_dma_params->addr;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
4462306a36Sopenharmony_ci	if (ret)
4562306a36Sopenharmony_ci		return ret;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	slave_config->dst_maxburst = 4;
4862306a36Sopenharmony_ci	slave_config->src_maxburst = 4;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
5162306a36Sopenharmony_ci	slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
5462306a36Sopenharmony_ci		slave_config->dst_addr = dma_addr;
5562306a36Sopenharmony_ci	else
5662306a36Sopenharmony_ci		slave_config->src_addr = dma_addr;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return 0;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic const struct snd_dmaengine_pcm_config ux500_dmaengine_of_pcm_config = {
6262306a36Sopenharmony_ci	.prepare_slave_config = ux500_pcm_prepare_slave_config,
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ciint ux500_pcm_register_platform(struct platform_device *pdev)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	int ret;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	ret = snd_dmaengine_pcm_register(&pdev->dev,
7062306a36Sopenharmony_ci					 &ux500_dmaengine_of_pcm_config, 0);
7162306a36Sopenharmony_ci	if (ret < 0) {
7262306a36Sopenharmony_ci		dev_err(&pdev->dev,
7362306a36Sopenharmony_ci			"%s: ERROR: Failed to register platform '%s' (%d)!\n",
7462306a36Sopenharmony_ci			__func__, pdev->name, ret);
7562306a36Sopenharmony_ci		return ret;
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	return 0;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ux500_pcm_register_platform);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ciint ux500_pcm_unregister_platform(struct platform_device *pdev)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	snd_dmaengine_pcm_unregister(&pdev->dev);
8562306a36Sopenharmony_ci	return 0;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ciMODULE_AUTHOR("Ola Lilja");
9062306a36Sopenharmony_ciMODULE_AUTHOR("Roger Nilsson");
9162306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC UX500 driver");
9262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
93