<commit_before>/*
 * Renesas R-Car Audio DMAC support
 *
 * Copyright (C) 2015 Renesas Electronics Corp.
 * Copyright (c) 2015 <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/delay.h>
#include <linux/of_dma.h>
#include "rsnd.h"

/*
 * Audio DMAC peri peri register
 */
#define PDMASAR		0x00
#define PDMADAR		0x04
#define PDMACHCR	0x0c

/* PDMACHCR */
#define PDMACHCR_DE		(1 << 0)

struct rsnd_dma_ctrl {
	void __iomem *base;
	int dmapp_num;
};

#define rsnd_priv_to_dmac(p)	((struct rsnd_dma_ctrl *)(p)->dma)

/*
 *		Audio DMAC
 */
static void rsnd_dmaen_complete(void *data)
{
	struct rsnd_dma *dma = (struct rsnd_dma *)data;
	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);

	/*
	 * Renesas sound Gen1 needs 1 DMAC,
	 * Gen2 needs 2 DMAC.
	 * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
	 * But, Audio-DMAC-peri-peri doesn't have interrupt,
	 * and this driver is assuming that here.
	 *
	 * If Audio-DMAC-peri-peri has interrpt,
	 * rsnd_dai_pointer_update() will be called twice,
	 * ant it will breaks io->byte_pos
	 */

	rsnd_dai_pointer_update(io, io->byte_per_period);
}

static void rsnd_dmaen_stop(struct rsnd_dma *dma)
{
	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);

	dmaengine_terminate_all(dmaen->chan);
}

static void rsnd_dmaen_start(struct rsnd_dma *dma)
{
	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
	struct snd_pcm_substream *substream = io->substream;
	struct device *dev = rsnd_priv_to_dev(priv);
	struct dma_async_tx_descriptor *desc;
	int is_play = rsnd_io_is_play(io);

	desc = dmaengine_prep_dma_cyclic(dmaen->chan,
					 substream->runtime->dma_addr,
					 snd_pcm_lib_buffer_bytes(substream),
					 snd_pcm_lib_period_bytes(substream),
					 is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
					 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);

	if (!desc) {
		dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
		return;
	}

	desc->callback		= rsnd_dmaen_complete;
	desc->callback_param	= dma;

	if (dmaengine_submit(desc) < 0) {
		dev_err(dev, "dmaengine_submit() fail\n");
		return;
	}

	dma_async_issue_pending(dmaen->chan);
}

struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
					  struct rsnd_mod *mod, char *name)
{
	struct dma_chan *chan;
	struct device_node *np;
	int i = 0;

	for_each_child_of_node(of_node, np) {
		if (i == rsnd_mod_id(mod))
			break;
		i++;
	}

	chan = of_dma_request_slave_channel(np, name);

	of_node_put(np);
	of_node_put(of_node);

	return chan;
}

static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_mod *mod_from,
						   struct rsnd_mod *mod_to)
{
	if ((!mod_from && !mod_to) ||
	    (mod_from && mod_to))
		return NULL;

	if (mod_from)
		return rsnd_mod_dma_req(mod_from);
	else
		return rsnd_mod_dma_req(mod_to);
}

static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
			   struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
{
	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
	struct device *dev = rsnd_priv_to_dev(priv);
	struct dma_slave_config cfg = {};
	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
	int is_play = rsnd_io_is_play(io);
	int ret;

	if (dmaen->chan) {
		dev_err(dev, "it already has dma channel\n");
		return -EIO;
	}

	if (dev->of_node) {
		dmaen->chan = rsnd_dmaen_request_channel(mod_from, mod_to);
	} else {
		dma_cap_mask_t mask;

		dma_cap_zero(mask);
		dma_cap_set(DMA_SLAVE, mask);

		dmaen->chan = dma_request_channel(mask, shdma_chan_filter,
						  (void *)id);
	}
	if (IS_ERR_OR_NULL(dmaen->chan)) {
		dev_err(dev, "can't get dma channel\n");
		goto rsnd_dma_channel_err;
	}

	cfg.direction	= is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
	cfg.src_addr	= dma->src_addr;
	cfg.dst_addr	= dma->dst_addr;
	cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;

	dev_dbg(dev, "dma : %pad -> %pad\n",
		&cfg.src_addr, &cfg.dst_addr);

	ret = dmaengine_slave_config(dmaen->chan, &cfg);<commit_msg>ASoC: rsnd: set dmaen->chan = NULL when error case<commit_after>/*
 * Renesas R-Car Audio DMAC support
 *
 * Copyright (C) 2015 Renesas Electronics Corp.
 * Copyright (c) 2015 <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/delay.h>
#include <linux/of_dma.h>
#include "rsnd.h"

/*
 * Audio DMAC peri peri register
 */
#define PDMASAR		0x00
#define PDMADAR		0x04
#define PDMACHCR	0x0c

/* PDMACHCR */
#define PDMACHCR_DE		(1 << 0)

struct rsnd_dma_ctrl {
	void __iomem *base;
	int dmapp_num;
};

#define rsnd_priv_to_dmac(p)	((struct rsnd_dma_ctrl *)(p)->dma)

/*
 *		Audio DMAC
 */
static void rsnd_dmaen_complete(void *data)
{
	struct rsnd_dma *dma = (struct rsnd_dma *)data;
	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);

	/*
	 * Renesas sound Gen1 needs 1 DMAC,
	 * Gen2 needs 2 DMAC.
	 * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
	 * But, Audio-DMAC-peri-peri doesn't have interrupt,
	 * and this driver is assuming that here.
	 *
	 * If Audio-DMAC-peri-peri has interrpt,
	 * rsnd_dai_pointer_update() will be called twice,
	 * ant it will breaks io->byte_pos
	 */

	rsnd_dai_pointer_update(io, io->byte_per_period);
}

static void rsnd_dmaen_stop(struct rsnd_dma *dma)
{
	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);

	dmaengine_terminate_all(dmaen->chan);
}

static void rsnd_dmaen_start(struct rsnd_dma *dma)
{
	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
	struct snd_pcm_substream *substream = io->substream;
	struct device *dev = rsnd_priv_to_dev(priv);
	struct dma_async_tx_descriptor *desc;
	int is_play = rsnd_io_is_play(io);

	desc = dmaengine_prep_dma_cyclic(dmaen->chan,
					 substream->runtime->dma_addr,
					 snd_pcm_lib_buffer_bytes(substream),
					 snd_pcm_lib_period_bytes(substream),
					 is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
					 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);

	if (!desc) {
		dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
		return;
	}

	desc->callback		= rsnd_dmaen_complete;
	desc->callback_param	= dma;

	if (dmaengine_submit(desc) < 0) {
		dev_err(dev, "dmaengine_submit() fail\n");
		return;
	}

	dma_async_issue_pending(dmaen->chan);
}

struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
					  struct rsnd_mod *mod, char *name)
{
	struct dma_chan *chan;
	struct device_node *np;
	int i = 0;

	for_each_child_of_node(of_node, np) {
		if (i == rsnd_mod_id(mod))
			break;
		i++;
	}

	chan = of_dma_request_slave_channel(np, name);

	of_node_put(np);
	of_node_put(of_node);

	return chan;
}

static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_mod *mod_from,
						   struct rsnd_mod *mod_to)
{
	if ((!mod_from && !mod_to) ||
	    (mod_from && mod_to))
		return NULL;

	if (mod_from)
		return rsnd_mod_dma_req(mod_from);
	else
		return rsnd_mod_dma_req(mod_to);
}

static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
			   struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
{
	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
	struct device *dev = rsnd_priv_to_dev(priv);
	struct dma_slave_config cfg = {};
	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
	int is_play = rsnd_io_is_play(io);
	int ret;

	if (dmaen->chan) {
		dev_err(dev, "it already has dma channel\n");
		return -EIO;
	}

	if (dev->of_node) {
		dmaen->chan = rsnd_dmaen_request_channel(mod_from, mod_to);
	} else {
		dma_cap_mask_t mask;

		dma_cap_zero(mask);
		dma_cap_set(DMA_SLAVE, mask);

		dmaen->chan = dma_request_channel(mask, shdma_chan_filter,
						  (void *)id);
	}
	if (IS_ERR_OR_NULL(dmaen->chan)) {
		dmaen->chan = NULL;
		dev_err(dev, "can't get dma channel\n");
		goto rsnd_dma_channel_err;
	}

	cfg.direction	= is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
	cfg.src_addr	= dma->src_addr;
	cfg.dst_addr	= dma->dst_addr;
	cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;

	dev_dbg(dev, "dma : %pad -> %pad\n",
		&cfg.src_addr, &cfg.dst_addr);

	ret = dmaengine_slave_config(dmaen->chan, &cfg);
{'fraction_non_alphanumeric': 0.11546840958605664, 'fraction_numerical': 0.006421281963077629, 'mean_word_length': 4.605398457583547, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4404795', 'n_tokens_mistral': 3832, 'n_tokens_neox': 3588, 'n_words': 758}