162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  PCM DRM helpers
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#include <linux/export.h>
662306a36Sopenharmony_ci#include <linux/types.h>
762306a36Sopenharmony_ci#include <sound/asoundef.h>
862306a36Sopenharmony_ci#include <sound/pcm.h>
962306a36Sopenharmony_ci#include <sound/pcm_params.h>
1062306a36Sopenharmony_ci#include <sound/pcm_iec958.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/**
1362306a36Sopenharmony_ci * snd_pcm_create_iec958_consumer_default - create default consumer format IEC958 channel status
1462306a36Sopenharmony_ci * @cs: channel status buffer, at least four bytes
1562306a36Sopenharmony_ci * @len: length of channel status buffer
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * Create the consumer format channel status data in @cs of maximum size
1862306a36Sopenharmony_ci * @len. When relevant, the configuration-dependant bits will be set as
1962306a36Sopenharmony_ci * unspecified.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * Drivers should then call einter snd_pcm_fill_iec958_consumer() or
2262306a36Sopenharmony_ci * snd_pcm_fill_iec958_consumer_hw_params() to replace these unspecified
2362306a36Sopenharmony_ci * bits by their actual values.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * Drivers may wish to tweak the contents of the buffer after creation.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * Returns: length of buffer, or negative error code if something failed.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ciint snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	if (len < 4)
3262306a36Sopenharmony_ci		return -EINVAL;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	memset(cs, 0, len);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
3762306a36Sopenharmony_ci	cs[1] = IEC958_AES1_CON_GENERAL;
3862306a36Sopenharmony_ci	cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
3962306a36Sopenharmony_ci	cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (len > 4)
4262306a36Sopenharmony_ci		cs[4] = IEC958_AES4_CON_WORDLEN_NOTID;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	return len;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_pcm_create_iec958_consumer_default);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic int fill_iec958_consumer(uint rate, uint sample_width,
4962306a36Sopenharmony_ci				u8 *cs, size_t len)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	if (len < 4)
5262306a36Sopenharmony_ci		return -EINVAL;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if ((cs[3] & IEC958_AES3_CON_FS) == IEC958_AES3_CON_FS_NOTID) {
5562306a36Sopenharmony_ci		unsigned int fs;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		switch (rate) {
5862306a36Sopenharmony_ci			case 32000:
5962306a36Sopenharmony_ci				fs = IEC958_AES3_CON_FS_32000;
6062306a36Sopenharmony_ci				break;
6162306a36Sopenharmony_ci			case 44100:
6262306a36Sopenharmony_ci				fs = IEC958_AES3_CON_FS_44100;
6362306a36Sopenharmony_ci				break;
6462306a36Sopenharmony_ci			case 48000:
6562306a36Sopenharmony_ci				fs = IEC958_AES3_CON_FS_48000;
6662306a36Sopenharmony_ci				break;
6762306a36Sopenharmony_ci			case 88200:
6862306a36Sopenharmony_ci				fs = IEC958_AES3_CON_FS_88200;
6962306a36Sopenharmony_ci				break;
7062306a36Sopenharmony_ci			case 96000:
7162306a36Sopenharmony_ci				fs = IEC958_AES3_CON_FS_96000;
7262306a36Sopenharmony_ci				break;
7362306a36Sopenharmony_ci			case 176400:
7462306a36Sopenharmony_ci				fs = IEC958_AES3_CON_FS_176400;
7562306a36Sopenharmony_ci				break;
7662306a36Sopenharmony_ci			case 192000:
7762306a36Sopenharmony_ci				fs = IEC958_AES3_CON_FS_192000;
7862306a36Sopenharmony_ci				break;
7962306a36Sopenharmony_ci			default:
8062306a36Sopenharmony_ci				return -EINVAL;
8162306a36Sopenharmony_ci		}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci		cs[3] &= ~IEC958_AES3_CON_FS;
8462306a36Sopenharmony_ci		cs[3] |= fs;
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (len > 4 &&
8862306a36Sopenharmony_ci	    (cs[4] & IEC958_AES4_CON_WORDLEN) == IEC958_AES4_CON_WORDLEN_NOTID) {
8962306a36Sopenharmony_ci		unsigned int ws;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		switch (sample_width) {
9262306a36Sopenharmony_ci		case 16:
9362306a36Sopenharmony_ci			ws = IEC958_AES4_CON_WORDLEN_20_16;
9462306a36Sopenharmony_ci			break;
9562306a36Sopenharmony_ci		case 18:
9662306a36Sopenharmony_ci			ws = IEC958_AES4_CON_WORDLEN_22_18;
9762306a36Sopenharmony_ci			break;
9862306a36Sopenharmony_ci		case 20:
9962306a36Sopenharmony_ci			ws = IEC958_AES4_CON_WORDLEN_20_16 |
10062306a36Sopenharmony_ci			     IEC958_AES4_CON_MAX_WORDLEN_24;
10162306a36Sopenharmony_ci			break;
10262306a36Sopenharmony_ci		case 24:
10362306a36Sopenharmony_ci		case 32: /* Assume 24-bit width for 32-bit samples. */
10462306a36Sopenharmony_ci			ws = IEC958_AES4_CON_WORDLEN_24_20 |
10562306a36Sopenharmony_ci			     IEC958_AES4_CON_MAX_WORDLEN_24;
10662306a36Sopenharmony_ci			break;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		default:
10962306a36Sopenharmony_ci			return -EINVAL;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		cs[4] &= ~IEC958_AES4_CON_WORDLEN;
11362306a36Sopenharmony_ci		cs[4] |= ws;
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return len;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/**
12062306a36Sopenharmony_ci * snd_pcm_fill_iec958_consumer - Fill consumer format IEC958 channel status
12162306a36Sopenharmony_ci * @runtime: pcm runtime structure with ->rate filled in
12262306a36Sopenharmony_ci * @cs: channel status buffer, at least four bytes
12362306a36Sopenharmony_ci * @len: length of channel status buffer
12462306a36Sopenharmony_ci *
12562306a36Sopenharmony_ci * Fill the unspecified bits in an IEC958 status bits array using the
12662306a36Sopenharmony_ci * parameters of the PCM runtime @runtime.
12762306a36Sopenharmony_ci *
12862306a36Sopenharmony_ci * Drivers may wish to tweak the contents of the buffer after its been
12962306a36Sopenharmony_ci * filled.
13062306a36Sopenharmony_ci *
13162306a36Sopenharmony_ci * Returns: length of buffer, or negative error code if something failed.
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_ciint snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime,
13462306a36Sopenharmony_ci				 u8 *cs, size_t len)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	return fill_iec958_consumer(runtime->rate,
13762306a36Sopenharmony_ci				    snd_pcm_format_width(runtime->format),
13862306a36Sopenharmony_ci				    cs, len);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/**
14362306a36Sopenharmony_ci * snd_pcm_fill_iec958_consumer_hw_params - Fill consumer format IEC958 channel status
14462306a36Sopenharmony_ci * @params: the hw_params instance for extracting rate and sample format
14562306a36Sopenharmony_ci * @cs: channel status buffer, at least four bytes
14662306a36Sopenharmony_ci * @len: length of channel status buffer
14762306a36Sopenharmony_ci *
14862306a36Sopenharmony_ci * Fill the unspecified bits in an IEC958 status bits array using the
14962306a36Sopenharmony_ci * parameters of the PCM hardware parameters @params.
15062306a36Sopenharmony_ci *
15162306a36Sopenharmony_ci * Drivers may wish to tweak the contents of the buffer after its been
15262306a36Sopenharmony_ci * filled..
15362306a36Sopenharmony_ci *
15462306a36Sopenharmony_ci * Returns: length of buffer, or negative error code if something failed.
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_ciint snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,
15762306a36Sopenharmony_ci					   u8 *cs, size_t len)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	return fill_iec958_consumer(params_rate(params), params_width(params), cs, len);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer_hw_params);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/**
16462306a36Sopenharmony_ci * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status
16562306a36Sopenharmony_ci * @runtime: pcm runtime structure with ->rate filled in
16662306a36Sopenharmony_ci * @cs: channel status buffer, at least four bytes
16762306a36Sopenharmony_ci * @len: length of channel status buffer
16862306a36Sopenharmony_ci *
16962306a36Sopenharmony_ci * Create the consumer format channel status data in @cs of maximum size
17062306a36Sopenharmony_ci * @len corresponding to the parameters of the PCM runtime @runtime.
17162306a36Sopenharmony_ci *
17262306a36Sopenharmony_ci * Drivers may wish to tweak the contents of the buffer after creation.
17362306a36Sopenharmony_ci *
17462306a36Sopenharmony_ci * Returns: length of buffer, or negative error code if something failed.
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_ciint snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
17762306a36Sopenharmony_ci	size_t len)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	int ret;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	ret = snd_pcm_create_iec958_consumer_default(cs, len);
18262306a36Sopenharmony_ci	if (ret < 0)
18362306a36Sopenharmony_ci		return ret;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return snd_pcm_fill_iec958_consumer(runtime, cs, len);
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_create_iec958_consumer);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/**
19062306a36Sopenharmony_ci * snd_pcm_create_iec958_consumer_hw_params - create IEC958 channel status
19162306a36Sopenharmony_ci * @params: the hw_params instance for extracting rate and sample format
19262306a36Sopenharmony_ci * @cs: channel status buffer, at least four bytes
19362306a36Sopenharmony_ci * @len: length of channel status buffer
19462306a36Sopenharmony_ci *
19562306a36Sopenharmony_ci * Create the consumer format channel status data in @cs of maximum size
19662306a36Sopenharmony_ci * @len corresponding to the parameters of the PCM runtime @runtime.
19762306a36Sopenharmony_ci *
19862306a36Sopenharmony_ci * Drivers may wish to tweak the contents of the buffer after creation.
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * Returns: length of buffer, or negative error code if something failed.
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_ciint snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,
20362306a36Sopenharmony_ci					     u8 *cs, size_t len)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	int ret;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	ret = snd_pcm_create_iec958_consumer_default(cs, len);
20862306a36Sopenharmony_ci	if (ret < 0)
20962306a36Sopenharmony_ci		return ret;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	return fill_iec958_consumer(params_rate(params), params_width(params), cs, len);
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params);
214