File Index
Files and directories
Sign in
FILE

tegra_isomgr_bw.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/tegra/tegra_isomgr_bw.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
  3// All rights reserved.
  4//
  5// ADMA bandwidth calculation
  6
  7#include <linux/interconnect.h>
  8#include <linux/module.h>
  9#include <sound/pcm_params.h>
 10#include <sound/soc.h>
 11#include "tegra_isomgr_bw.h"
 12#include "tegra210_admaif.h"
 13
 14#define MAX_SAMPLE_RATE		192	/* KHz*/
 15#define MAX_BYTES_PER_SAMPLE	4
 16
 17int tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream,
 18			    struct snd_soc_dai *dai, bool is_running)
 19{
 20	struct device *dev = dai->dev;
 21	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
 22	struct tegra_adma_isomgr *adma_isomgr = admaif->adma_isomgr;
 23	struct snd_pcm_runtime *runtime = substream->runtime;
 24	struct snd_pcm *pcm = substream->pcm;
 25	u32 type = substream->stream, bandwidth = 0;
 26	int sample_bytes;
 27
 28	if (!adma_isomgr)
 29		return 0;
 30
 31	if (!runtime || !pcm)
 32		return -EINVAL;
 33
 34	if (pcm->device >= adma_isomgr->max_pcm_device) {
 35		dev_err(dev, "%s: PCM device number %d is greater than %d\n", __func__,
 36			pcm->device, adma_isomgr->max_pcm_device);
 37		return -EINVAL;
 38	}
 39
 40	/*
 41	 * No action if  stream is running and bandwidth is already set or
 42	 * stream is not running and bandwidth is already reset
 43	 */
 44	if ((adma_isomgr->bw_per_dev[type][pcm->device] && is_running) ||
 45	    (!adma_isomgr->bw_per_dev[type][pcm->device] && !is_running))
 46		return 0;
 47
 48	if (is_running) {
 49		sample_bytes = snd_pcm_format_width(runtime->format) / 8;
 50		if (sample_bytes < 0)
 51			return sample_bytes;
 52
 53		/* KB/s kilo bytes per sec */
 54		bandwidth = runtime->channels * (runtime->rate / 1000) *
 55				sample_bytes;
 56	}
 57
 58	mutex_lock(&adma_isomgr->mutex);
 59
 60	if (is_running) {
 61		if (bandwidth + adma_isomgr->current_bandwidth > adma_isomgr->max_bw)
 62			bandwidth = adma_isomgr->max_bw - adma_isomgr->current_bandwidth;
 63
 64		adma_isomgr->current_bandwidth += bandwidth;
 65	} else {
 66		adma_isomgr->current_bandwidth -= adma_isomgr->bw_per_dev[type][pcm->device];
 67	}
 68
 69	mutex_unlock(&adma_isomgr->mutex);
 70
 71	adma_isomgr->bw_per_dev[type][pcm->device] = bandwidth;
 72
 73	dev_dbg(dev, "Setting up bandwidth to %d KBps\n", adma_isomgr->current_bandwidth);
 74
 75	return icc_set_bw(adma_isomgr->icc_path_handle,
 76			  adma_isomgr->current_bandwidth, adma_isomgr->max_bw);
 77}
 78
 79int tegra_isomgr_adma_register(struct device *dev)
 80{
 81	struct tegra_admaif *admaif = dev_get_drvdata(dev);
 82	struct tegra_adma_isomgr *adma_isomgr;
 83	int i;
 84
 85	adma_isomgr = devm_kzalloc(dev, sizeof(struct tegra_adma_isomgr), GFP_KERNEL);
 86	if (!adma_isomgr)
 87		return -ENOMEM;
 88
 89	adma_isomgr->icc_path_handle = devm_of_icc_get(dev, "write");
 90	if (IS_ERR(adma_isomgr->icc_path_handle))
 91		return dev_err_probe(dev, PTR_ERR(adma_isomgr->icc_path_handle),
 92				"failed to acquire interconnect path\n");
 93
 94	/* Either INTERCONNECT config OR interconnect property is not defined */
 95	if (!adma_isomgr->icc_path_handle) {
 96		devm_kfree(dev, adma_isomgr);
 97		return 0;
 98	}
 99
100	adma_isomgr->max_pcm_device = admaif->soc_data->num_ch;
101	adma_isomgr->max_bw = STREAM_TYPE * MAX_SAMPLE_RATE * MAX_BYTES_PER_SAMPLE *
102			      admaif->soc_data->max_stream_ch * adma_isomgr->max_pcm_device;
103
104	for (i = 0; i < STREAM_TYPE; i++) {
105		adma_isomgr->bw_per_dev[i] = devm_kzalloc(dev, adma_isomgr->max_pcm_device *
106							  sizeof(u32), GFP_KERNEL);
107		if (!adma_isomgr->bw_per_dev[i])
108			return -ENOMEM;
109	}
110
111	adma_isomgr->current_bandwidth = 0;
112	mutex_init(&adma_isomgr->mutex);
113	admaif->adma_isomgr = adma_isomgr;
114
115	return 0;
116}
117
118void tegra_isomgr_adma_unregister(struct device *dev)
119{
120	struct tegra_admaif *admaif = dev_get_drvdata(dev);
121
122	if (!admaif->adma_isomgr)
123		return;
124
125	mutex_destroy(&admaif->adma_isomgr->mutex);
126}
127
128MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
129MODULE_DESCRIPTION("Tegra ADMA Bandwidth Request driver");
130MODULE_LICENSE("GPL");
~/ Read-only file preview.