Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
May 2023
- 146 participants
- 468 discussions
[PATCH AUTOSEL 6.3 2/9] soundwire: dmi-quirks: add remapping for Intel 'Rooks County' NUC M15
by Sasha Levin 10 May '23
by Sasha Levin 10 May '23
10 May '23
From: Eugene Huang <eugene.huang99(a)gmail.com>
[ Upstream commit 01b33e284ca28cc977bdcfb23be2c719f2139175 ]
Same DSDT problem as the HP Omen 16-k0005TX, except rt1316 amp is on
link2.
Link: https://github.com/thesofproject/linux/issues/4088
Signed-off-by: Eugene Huang <eugene.huang99(a)gmail.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart(a)linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi(a)linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao(a)linux.intel.com>
Link: https://lore.kernel.org/r/20230314090618.498716-1-yung-chuan.liao@linux.int…
Signed-off-by: Vinod Koul <vkoul(a)kernel.org>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
---
drivers/soundwire/dmi-quirks.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c
index 7969881f126dc..58ea013fa918a 100644
--- a/drivers/soundwire/dmi-quirks.c
+++ b/drivers/soundwire/dmi-quirks.c
@@ -73,6 +73,23 @@ static const struct adr_remap hp_omen_16[] = {
{}
};
+/*
+ * Intel NUC M15 LAPRC510 and LAPRC710
+ */
+static const struct adr_remap intel_rooks_county[] = {
+ /* rt711-sdca on link0 */
+ {
+ 0x000020025d071100ull,
+ 0x000030025d071101ull
+ },
+ /* rt1316-sdca on link2 */
+ {
+ 0x000120025d071100ull,
+ 0x000230025d131601ull
+ },
+ {}
+};
+
static const struct dmi_system_id adr_remap_quirk_table[] = {
/* TGL devices */
{
@@ -98,6 +115,14 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
},
.driver_data = (void *)intel_tgl_bios,
},
+ {
+ /* quirk used for NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"),
+ },
+ .driver_data = (void *)intel_rooks_county,
+ },
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
--
2.39.2
1
0
Newest Update for Fedora 37 (alsa-lib-1.2.9-1.fc37) causes crackling with device
by GitHub issues - opened 10 May '23
by GitHub issues - opened 10 May '23
10 May '23
alsa-project/alsa-lib issue #317 was opened from ClaraCrazy:
First bug report here + not skilled with debugging, so please go easy on me :smile:
OS: Fedora 37
Alsa-lib: 1.2.9-1
Issue: Audio crackling
Audio Device: `Logic3 TX101 5.1 Soundbar` connected via `Scarlett 2i2 3rd Gen audio interface (USB)`
Reverted lib back to `alsa-lib.1.2.8-2.fc37` (which in turn also downgraded alsa-ucm and alsa-utils again) and issues are fixed. I have no idea how to debug this, but would love to help in any way possible, sadly there was no issue template that would give me infos on what logs are useful / where to get those so uh.. please someone just point me in the right direction :)
Thanks for your time
Issue URL : https://github.com/alsa-project/alsa-lib/issues/317
Repository URL: https://github.com/alsa-project/alsa-lib
1
0
[PATCH v3] ALSA: pcm: auto-fill buffer with silence when draining playback
by Oswald Buddenhagen 10 May '23
by Oswald Buddenhagen 10 May '23
10 May '23
Draining will always playback somewhat beyond the end of the filled
buffer. This would produce artifacts if the user did not set up the
auto-silencing machinery, which is an extremely easy mistake to make, as
the API strongly suggests convenient fire-and-forget semantics. This
patch makes it work out of the box.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen(a)gmx.de>
---
you are NOT expected to apply this. i just needed it for my testing
(it's easier to deploy as i'm hacking on the kernel anyway) and wanted
to post it for posterity.
v3:
- rebased to updated silencing code
- intro period alignment to reduce redundant fill
- cut down commit message again, as it's disabled by default now
v2:
- fill only up to two periods, to avoid undue load with big buffers
- added discussion to commit message
---
sound/core/pcm_lib.c | 35 ++++++++++++++++++++++++++++++++++-
sound/core/pcm_native.c | 3 ++-
2 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 9c121a921b04..46e63e653789 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -67,6 +67,11 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
snd_pcm_uframes_t frames, ofs, transfer;
int err;
+ if (runtime->silence_size == 0 &&
+ (runtime->state != SNDRV_PCM_STATE_DRAINING ||
+ (runtime->info & SNDRV_PCM_HW_PARAMS_NO_DRAIN_SILENCE) ||
+ (runtime->hw.info & SNDRV_PCM_INFO_PERFECT_DRAIN)))
+ return;
if (runtime->silence_size < runtime->boundary) {
snd_pcm_sframes_t noise_dist;
snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr);
@@ -80,6 +85,33 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
noise_dist += runtime->boundary;
/* total noise distance */
noise_dist += runtime->silence_filled;
+ if (runtime->state == SNDRV_PCM_STATE_DRAINING) {
+ snd_pcm_uframes_t slack = runtime->rate / 10;
+ snd_pcm_sframes_t threshold;
+ snd_pcm_uframes_t ps = runtime->period_size;
+ snd_pcm_uframes_t silence_size = ps;
+ // Round down to start of next period. This is disabled
+ // if the period count is not integer.
+ if (runtime->periods * ps == runtime->buffer_size)
+ silence_size = ps - (appl_ptr + ps - 1) % ps - 1;
+ // Add overshoot to accomodate FIFOs and IRQ delays.
+ // The default 1/10th secs is very generous. But more than one
+ // period doesn't make sense; the driver would set the minimum
+ // period size accordingly.
+ slack = min(slack, ps);
+ silence_size += slack;
+ // This catches the periods == 1 case.
+ silence_size = min(silence_size, runtime->buffer_size);
+
+ threshold = ps + slack;
+ if (noise_dist >= threshold)
+ return;
+ frames = threshold - noise_dist;
+ if (frames > silence_size)
+ frames = silence_size;
+
+ goto avoid_reindent;
+ }
if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold)
return;
frames = runtime->silence_threshold - noise_dist;
@@ -118,6 +150,7 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
*/
frames = runtime->buffer_size - runtime->silence_filled;
}
+avoid_reindent:
if (snd_BUG_ON(frames > runtime->buffer_size))
return;
if (frames == 0)
@@ -465,7 +498,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- runtime->silence_size > 0)
+ (runtime->silence_size > 0 || runtime->state == SNDRV_PCM_STATE_DRAINING))
snd_pcm_playback_silence(substream, new_hw_ptr);
if (in_interrupt) {
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 39a65d1415ab..913dae449ba0 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1454,7 +1454,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream,
runtime->rate;
__snd_pcm_set_state(runtime, state);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- runtime->silence_size > 0)
+ (runtime->silence_size > 0 || state == SNDRV_PCM_STATE_DRAINING))
snd_pcm_playback_silence(substream, ULONG_MAX);
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
}
@@ -2045,6 +2045,7 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_STATE_RUNNING:
__snd_pcm_set_state(runtime, SNDRV_PCM_STATE_DRAINING);
+ snd_pcm_playback_silence(substream, ULONG_MAX);
break;
case SNDRV_PCM_STATE_XRUN:
__snd_pcm_set_state(runtime, SNDRV_PCM_STATE_SETUP);
--
2.40.0.152.g15d061e6df
2
2
[PATCH AUTOSEL 5.10 1/3] ASOC: Intel: sof_sdw: add quirk for Intel 'Rooks County' NUC M15
by Sasha Levin 10 May '23
by Sasha Levin 10 May '23
10 May '23
From: Eugene Huang <eugene.huang99(a)gmail.com>
[ Upstream commit 3c728b1bc5b99c5275ac5c7788ef814c0e51ef54 ]
Same quirks as the 'Bishop County' NUC M15, except the rt711 is in the
'JD2 100K' jack detection mode.
Link: https://github.com/thesofproject/linux/issues/4088
Signed-off-by: Eugene Huang <eugene.huang99(a)gmail.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart(a)linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi(a)linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao(a)linux.intel.com>
Link: https://lore.kernel.org/r/20230314090553.498664-2-yung-chuan.liao@linux.int…
Signed-off-by: Mark Brown <broonie(a)kernel.org>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
---
sound/soc/intel/boards/sof_sdw.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index f5d8f7951cfc3..eb713e9c2bd22 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -175,6 +175,17 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
SOF_SDW_PCH_DMIC |
SOF_RT711_JD_SRC_JD2),
},
+ {
+ /* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"),
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ SOF_SDW_PCH_DMIC |
+ RT711_JD2_100K),
+ },
/* TigerLake-SDCA devices */
{
.callback = sof_sdw_quirk_cb,
--
2.39.2
2
2
Fix some obvious codestyle issues in the pcm_native.c file. Some of them
were found by checkpatch with --strict option, and the others by just
looking at the code. These issues include incorrect placement of brackets,
trailing and starting spaces, wrong alignment of function arguments,
incorrect multiline comments, using __attribute__((packed)) instead of just
"__packed", comparison with null instead of using "!". Also, today we have
100 columns per line available, and I tried to reformat the file
considering this.
Signed-off-by: Ivan Orlov <ivan.orlov0322(a)gmail.com>
---
sound/core/pcm_native.c | 696 +++++++++++++++++++---------------------
1 file changed, 323 insertions(+), 373 deletions(-)
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 39a65d1415ab..4a8d2e825b1d 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -43,10 +43,9 @@
struct snd_pcm_hw_params_old {
unsigned int flags;
- unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
- SNDRV_PCM_HW_PARAM_ACCESS + 1];
+ unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT - SNDRV_PCM_HW_PARAM_ACCESS + 1];
struct snd_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
- SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
unsigned int rmask;
unsigned int cmask;
unsigned int info;
@@ -62,9 +61,9 @@ struct snd_pcm_hw_params_old {
#define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct snd_pcm_hw_params_old)
static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params_old __user * _oparams);
+ struct snd_pcm_hw_params_old __user *_oparams);
static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params_old __user * _oparams);
+ struct snd_pcm_hw_params_old __user *_oparams);
#endif
static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
@@ -133,8 +132,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock);
*/
void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
{
- snd_pcm_group_lock_irq(&substream->self_group,
- substream->pcm->nonatomic);
+ snd_pcm_group_lock_irq(&substream->self_group, substream->pcm->nonatomic);
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq);
@@ -164,6 +162,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq);
unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
{
unsigned long flags = 0;
+
if (substream->pcm->nonatomic)
mutex_lock(&substream->self_group.mutex);
else
@@ -175,12 +174,11 @@ EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
unsigned long _snd_pcm_stream_lock_irqsave_nested(struct snd_pcm_substream *substream)
{
unsigned long flags = 0;
+
if (substream->pcm->nonatomic)
- mutex_lock_nested(&substream->self_group.mutex,
- SINGLE_DEPTH_NESTING);
+ mutex_lock_nested(&substream->self_group.mutex, SINGLE_DEPTH_NESTING);
else
- spin_lock_irqsave_nested(&substream->self_group.lock, flags,
- SINGLE_DEPTH_NESTING);
+ spin_lock_irqsave_nested(&substream->self_group.lock, flags, SINGLE_DEPTH_NESTING);
return flags;
}
EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave_nested);
@@ -192,8 +190,7 @@ EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave_nested);
*
* This is a counter-part of snd_pcm_stream_lock_irqsave().
*/
-void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
- unsigned long flags)
+void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, unsigned long flags)
{
if (substream->pcm->nonatomic)
mutex_unlock(&substream->self_group.mutex);
@@ -203,8 +200,7 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore);
/* Run PCM ioctl ops */
-static int snd_pcm_ops_ioctl(struct snd_pcm_substream *substream,
- unsigned cmd, void *arg)
+static int snd_pcm_ops_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg)
{
if (substream->ops->ioctl)
return substream->ops->ioctl(substream, cmd, arg);
@@ -233,14 +229,13 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
return 0;
}
-int snd_pcm_info_user(struct snd_pcm_substream *substream,
- struct snd_pcm_info __user * _info)
+int snd_pcm_info_user(struct snd_pcm_substream *substream, struct snd_pcm_info __user *_info)
{
struct snd_pcm_info *info;
int err;
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (! info)
+ if (!info)
return -ENOMEM;
err = snd_pcm_info(substream, info);
if (err >= 0) {
@@ -284,8 +279,7 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream)
static int constrain_mask_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_pcm_hw_constraints *constrs =
- &substream->runtime->hw_constraints;
+ struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints;
struct snd_mask *m;
unsigned int k;
struct snd_mask old_mask __maybe_unused;
@@ -320,8 +314,7 @@ static int constrain_mask_params(struct snd_pcm_substream *substream,
static int constrain_interval_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_pcm_hw_constraints *constrs =
- &substream->runtime->hw_constraints;
+ struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints;
struct snd_interval *i;
unsigned int k;
struct snd_interval old_interval __maybe_unused;
@@ -356,8 +349,7 @@ static int constrain_interval_params(struct snd_pcm_substream *substream,
static int constrain_params_by_rules(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_pcm_hw_constraints *constrs =
- &substream->runtime->hw_constraints;
+ struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints;
unsigned int k;
unsigned int *rstamps;
unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
@@ -447,14 +439,12 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
*/
if (changed && r->var >= 0) {
if (hw_is_mask(r->var)) {
- trace_hw_mask_param(substream, r->var,
- k + 1, &old_mask,
- hw_param_mask(params, r->var));
+ trace_hw_mask_param(substream, r->var, k + 1, &old_mask,
+ hw_param_mask(params, r->var));
}
if (hw_is_interval(r->var)) {
- trace_hw_interval_param(substream, r->var,
- k + 1, &old_interval,
- hw_param_interval(params, r->var));
+ trace_hw_interval_param(substream, r->var, k + 1, &old_interval,
+ hw_param_interval(params, r->var));
}
params->cmask |= PARAM_MASK_BIT(r->var);
@@ -509,18 +499,15 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
if (!params->info) {
params->info = substream->runtime->hw.info;
- params->info &= ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
- SNDRV_PCM_INFO_DRAIN_TRIGGER);
+ params->info &= ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | SNDRV_PCM_INFO_DRAIN_TRIGGER);
if (!hw_support_mmap(substream))
- params->info &= ~(SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID);
+ params->info &= ~(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID);
}
return 0;
}
-int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
{
int err;
@@ -552,7 +539,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
EXPORT_SYMBOL(snd_pcm_hw_refine);
static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params __user * _params)
+ struct snd_pcm_hw_params __user *_params)
{
struct snd_pcm_hw_params *params;
int err;
@@ -580,7 +567,7 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
{
int usecs;
- if (! runtime->rate)
+ if (!runtime->rate)
return -1; /* invalid */
/* take 75% of period time as the deadline */
@@ -591,8 +578,7 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
return usecs;
}
-static void snd_pcm_set_state(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static void snd_pcm_set_state(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
snd_pcm_stream_lock_irq(substream);
if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED)
@@ -600,13 +586,11 @@ static void snd_pcm_set_state(struct snd_pcm_substream *substream,
snd_pcm_stream_unlock_irq(substream);
}
-static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
- int event)
+static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream, int event)
{
#ifdef CONFIG_SND_PCM_TIMER
if (substream->timer)
- snd_timer_notify(substream->timer, event,
- &substream->runtime->trigger_tstamp);
+ snd_timer_notify(substream->timer, event, &substream->runtime->trigger_tstamp);
#endif
}
@@ -672,10 +656,8 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
continue;
/* Trace the changed parameter. */
- if (hw_is_mask(*v)) {
- trace_hw_mask_param(pcm, *v, 0, &old_mask,
- hw_param_mask(params, *v));
- }
+ if (hw_is_mask(*v))
+ trace_hw_mask_param(pcm, *v, 0, &old_mask, hw_param_mask(params, *v));
if (hw_is_interval(*v)) {
trace_hw_interval_param(pcm, *v, 0, &old_interval,
hw_param_interval(params, *v));
@@ -756,14 +738,13 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
goto _error;
if (substream->managed_buffer_alloc) {
- err = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(params));
+ err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
if (err < 0)
goto _error;
runtime->buffer_changed = err > 0;
}
- if (substream->ops->hw_params != NULL) {
+ if (substream->ops->hw_params) {
err = substream->ops->hw_params(substream, params);
if (err < 0)
goto _error;
@@ -780,9 +761,8 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
runtime->info = params->info;
runtime->rate_num = params->rate_num;
runtime->rate_den = params->rate_den;
- runtime->no_period_wakeup =
- (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
- (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
+ runtime->no_period_wakeup = (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
+ (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
bits = snd_pcm_format_physical_width(runtime->format);
runtime->sample_bits = bits;
@@ -824,8 +804,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
cpu_latency_qos_remove_request(&substream->latency_pm_qos_req);
usecs = period_to_usecs(runtime);
if (usecs >= 0)
- cpu_latency_qos_add_request(&substream->latency_pm_qos_req,
- usecs);
+ cpu_latency_qos_add_request(&substream->latency_pm_qos_req, usecs);
err = 0;
_error:
if (err) {
@@ -834,7 +813,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
* the correct hardware parameter settings
*/
snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
- if (substream->ops->hw_free != NULL)
+ if (substream->ops->hw_free)
substream->ops->hw_free(substream);
if (substream->managed_buffer_alloc)
snd_pcm_lib_free_pages(substream);
@@ -845,7 +824,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
}
static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params __user * _params)
+ struct snd_pcm_hw_params __user *_params)
{
struct snd_pcm_hw_params *params;
int err;
@@ -954,10 +933,9 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
runtime->stop_threshold = params->stop_threshold;
runtime->silence_threshold = params->silence_threshold;
runtime->silence_size = params->silence_size;
- params->boundary = runtime->boundary;
+ params->boundary = runtime->boundary;
if (snd_pcm_running(substream)) {
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- runtime->silence_size > 0)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
err = snd_pcm_update_state(substream, runtime);
}
@@ -966,10 +944,11 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
}
static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
- struct snd_pcm_sw_params __user * _params)
+ struct snd_pcm_sw_params __user *_params)
{
struct snd_pcm_sw_params params;
int err;
+
if (copy_from_user(¶ms, _params, sizeof(params)))
return -EFAULT;
err = snd_pcm_sw_params(substream, ¶ms);
@@ -978,8 +957,7 @@ static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
return err;
}
-static inline snd_pcm_uframes_t
-snd_pcm_calc_delay(struct snd_pcm_substream *substream)
+static inline snd_pcm_uframes_t snd_pcm_calc_delay(struct snd_pcm_substream *substream)
{
snd_pcm_uframes_t delay;
@@ -990,15 +968,14 @@ snd_pcm_calc_delay(struct snd_pcm_substream *substream)
return delay + substream->runtime->delay;
}
-int snd_pcm_status64(struct snd_pcm_substream *substream,
- struct snd_pcm_status64 *status)
+int snd_pcm_status64(struct snd_pcm_substream *substream, struct snd_pcm_status64 *status)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream);
snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
- &runtime->audio_tstamp_config);
+ &runtime->audio_tstamp_config);
/* backwards compatible behavior */
if (runtime->audio_tstamp_config.type_requested ==
@@ -1010,8 +987,9 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
runtime->audio_tstamp_config.type_requested =
SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
runtime->audio_tstamp_report.valid = 0;
- } else
+ } else {
runtime->audio_tstamp_report.valid = 1;
+ }
status->state = runtime->state;
status->suspended_state = runtime->suspended_state;
@@ -1036,8 +1014,8 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
if (runtime->audio_tstamp_report.valid == 1)
/* backwards compatibility, no report provided in COMPAT mode */
snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data,
- &status->audio_tstamp_accuracy,
- &runtime->audio_tstamp_report);
+ &status->audio_tstamp_accuracy,
+ &runtime->audio_tstamp_report);
goto _tstamp_end;
}
@@ -1055,19 +1033,18 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
status->appl_ptr = runtime->control->appl_ptr;
status->hw_ptr = runtime->status->hw_ptr;
status->avail = snd_pcm_avail(substream);
- status->delay = snd_pcm_running(substream) ?
- snd_pcm_calc_delay(substream) : 0;
+ status->delay = snd_pcm_running(substream) ? snd_pcm_calc_delay(substream) : 0;
status->avail_max = runtime->avail_max;
status->overrange = runtime->overrange;
runtime->avail_max = 0;
runtime->overrange = 0;
- _end:
- snd_pcm_stream_unlock_irq(substream);
+_end:
+ snd_pcm_stream_unlock_irq(substream);
return 0;
}
static int snd_pcm_status_user64(struct snd_pcm_substream *substream,
- struct snd_pcm_status64 __user * _status,
+ struct snd_pcm_status64 __user *_status,
bool ext)
{
struct snd_pcm_status64 status;
@@ -1079,8 +1056,7 @@ static int snd_pcm_status_user64(struct snd_pcm_substream *substream,
* get audio_tstamp_data from user,
* ignore rest of status structure
*/
- if (ext && get_user(status.audio_tstamp_data,
- (u32 __user *)(&_status->audio_tstamp_data)))
+ if (ext && get_user(status.audio_tstamp_data, (u32 __user *)&_status->audio_tstamp_data))
return -EFAULT;
res = snd_pcm_status64(substream, &status);
if (res < 0)
@@ -1091,7 +1067,7 @@ static int snd_pcm_status_user64(struct snd_pcm_substream *substream,
}
static int snd_pcm_status_user32(struct snd_pcm_substream *substream,
- struct snd_pcm_status32 __user * _status,
+ struct snd_pcm_status32 __user *_status,
bool ext)
{
struct snd_pcm_status64 status64;
@@ -1105,8 +1081,7 @@ static int snd_pcm_status_user32(struct snd_pcm_substream *substream,
* get audio_tstamp_data from user,
* ignore rest of status structure
*/
- if (ext && get_user(status64.audio_tstamp_data,
- (u32 __user *)(&_status->audio_tstamp_data)))
+ if (ext && get_user(status64.audio_tstamp_data, (u32 __user *)&_status->audio_tstamp_data))
return -EFAULT;
res = snd_pcm_status64(substream, &status64);
if (res < 0)
@@ -1140,11 +1115,11 @@ static int snd_pcm_status_user32(struct snd_pcm_substream *substream,
}
static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
- struct snd_pcm_channel_info * info)
+ struct snd_pcm_channel_info *info)
{
struct snd_pcm_runtime *runtime;
unsigned int channel;
-
+
channel = info->channel;
runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream);
@@ -1161,11 +1136,11 @@ static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
}
static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
- struct snd_pcm_channel_info __user * _info)
+ struct snd_pcm_channel_info __user *_info)
{
struct snd_pcm_channel_info info;
int res;
-
+
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
res = snd_pcm_channel_info(substream, &info);
@@ -1179,7 +1154,8 @@ static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- if (runtime->trigger_master == NULL)
+
+ if (!runtime->trigger_master)
return;
if (runtime->trigger_master == substream) {
if (!runtime->trigger_tstamp_latched)
@@ -1191,17 +1167,13 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
runtime->trigger_master = NULL;
}
-#define ACTION_ARG_IGNORE (__force snd_pcm_state_t)0
+#define ACTION_ARG_IGNORE ((__force snd_pcm_state_t)0)
struct action_ops {
- int (*pre_action)(struct snd_pcm_substream *substream,
- snd_pcm_state_t state);
- int (*do_action)(struct snd_pcm_substream *substream,
- snd_pcm_state_t state);
- void (*undo_action)(struct snd_pcm_substream *substream,
- snd_pcm_state_t state);
- void (*post_action)(struct snd_pcm_substream *substream,
- snd_pcm_state_t state);
+ int (*pre_action)(struct snd_pcm_substream *substream, snd_pcm_state_t state);
+ int (*do_action)(struct snd_pcm_substream *substream, snd_pcm_state_t state);
+ void (*undo_action)(struct snd_pcm_substream *substream, snd_pcm_state_t state);
+ void (*post_action)(struct snd_pcm_substream *substream, snd_pcm_state_t state);
};
/*
@@ -1209,10 +1181,8 @@ struct action_ops {
* Note: the stream state might be changed also on failure
* Note2: call with calling stream lock + link lock
*/
-static int snd_pcm_action_group(const struct action_ops *ops,
- struct snd_pcm_substream *substream,
- snd_pcm_state_t state,
- bool stream_lock)
+static int snd_pcm_action_group(const struct action_ops *ops, struct snd_pcm_substream *substream,
+ snd_pcm_state_t state, bool stream_lock)
{
struct snd_pcm_substream *s = NULL;
struct snd_pcm_substream *s1;
@@ -1274,7 +1244,7 @@ static int snd_pcm_action_single(const struct action_ops *ops,
snd_pcm_state_t state)
{
int res;
-
+
res = ops->pre_action(substream, state);
if (res < 0)
return res;
@@ -1297,8 +1267,7 @@ static void snd_pcm_group_assign(struct snd_pcm_substream *substream,
* Unref and unlock the group, but keep the stream lock;
* when the group becomes empty and no longer referred, destroy itself
*/
-static void snd_pcm_group_unref(struct snd_pcm_group *group,
- struct snd_pcm_substream *substream)
+static void snd_pcm_group_unref(struct snd_pcm_group *group, struct snd_pcm_substream *substream)
{
bool do_free;
@@ -1314,8 +1283,7 @@ static void snd_pcm_group_unref(struct snd_pcm_group *group,
* Lock the group inside a stream lock and reference it;
* return the locked group object, or NULL if not linked
*/
-static struct snd_pcm_group *
-snd_pcm_stream_group_ref(struct snd_pcm_substream *substream)
+static struct snd_pcm_group *snd_pcm_stream_group_ref(struct snd_pcm_substream *substream)
{
bool nonatomic = substream->pcm->nonatomic;
struct snd_pcm_group *group;
@@ -1328,8 +1296,7 @@ snd_pcm_stream_group_ref(struct snd_pcm_substream *substream)
/* block freeing the group object */
refcount_inc(&group->refs);
- trylock = nonatomic ? mutex_trylock(&group->mutex) :
- spin_trylock(&group->lock);
+ trylock = nonatomic ? mutex_trylock(&group->mutex) : spin_trylock(&group->lock);
if (trylock)
break; /* OK */
@@ -1411,10 +1378,10 @@ static int snd_pcm_pre_start(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
if (runtime->state != SNDRV_PCM_STATE_PREPARED)
return -EBADFD;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- !snd_pcm_playback_data(substream))
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !snd_pcm_playback_data(substream))
return -EPIPE;
runtime->trigger_tstamp_latched = false;
runtime->trigger_master = substream;
@@ -1448,13 +1415,12 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
snd_pcm_trigger_tstamp(substream);
runtime->hw_ptr_jiffies = jiffies;
- runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) /
- runtime->rate;
+ runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / runtime->rate;
__snd_pcm_set_state(runtime, state);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- runtime->silence_size > 0)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
}
@@ -1475,15 +1441,13 @@ static const struct action_ops snd_pcm_action_start = {
*/
int snd_pcm_start(struct snd_pcm_substream *substream)
{
- return snd_pcm_action(&snd_pcm_action_start, substream,
- SNDRV_PCM_STATE_RUNNING);
+ return snd_pcm_action(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING);
}
/* take the stream lock and start the streams */
static int snd_pcm_start_lock_irq(struct snd_pcm_substream *substream)
{
- return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream,
- SNDRV_PCM_STATE_RUNNING);
+ return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING);
}
/*
@@ -1493,6 +1457,7 @@ static int snd_pcm_pre_stop(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
if (runtime->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
runtime->trigger_master = substream;
@@ -1502,8 +1467,7 @@ static int snd_pcm_pre_stop(struct snd_pcm_substream *substream,
static int snd_pcm_do_stop(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
- if (substream->runtime->trigger_master == substream &&
- snd_pcm_running(substream)) {
+ if (substream->runtime->trigger_master == substream && snd_pcm_running(substream)) {
substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
substream->runtime->stop_operating = true;
}
@@ -1514,6 +1478,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
if (runtime->state != state) {
snd_pcm_trigger_tstamp(substream);
__snd_pcm_set_state(runtime, state);
@@ -1555,8 +1520,7 @@ EXPORT_SYMBOL(snd_pcm_stop);
*/
int snd_pcm_drain_done(struct snd_pcm_substream *substream)
{
- return snd_pcm_action_single(&snd_pcm_action_stop, substream,
- SNDRV_PCM_STATE_SETUP);
+ return snd_pcm_action_single(&snd_pcm_action_stop, substream, SNDRV_PCM_STATE_SETUP);
}
/**
@@ -1583,19 +1547,20 @@ EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
/*
* pause callbacks: pass boolean (to start pause or resume) as state argument
*/
-#define pause_pushed(state) (__force bool)(state)
+#define pause_pushed(state) ((__force bool)(state))
-static int snd_pcm_pre_pause(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
if (!(runtime->info & SNDRV_PCM_INFO_PAUSE))
return -ENOSYS;
if (pause_pushed(state)) {
if (runtime->state != SNDRV_PCM_STATE_RUNNING)
return -EBADFD;
- } else if (runtime->state != SNDRV_PCM_STATE_PAUSED)
+ } else if (runtime->state != SNDRV_PCM_STATE_PAUSED) {
return -EBADFD;
+ }
runtime->trigger_master = substream;
return 0;
}
@@ -1605,8 +1570,7 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream,
{
if (substream->runtime->trigger_master != substream)
return 0;
- /* some drivers might use hw_ptr to recover from the pause -
- update the hw_ptr now */
+ // some drivers might use hw_ptr to recover from the pause - update the hw_ptr now
if (pause_pushed(state))
snd_pcm_update_hw_ptr(substream);
/* The jiffies check in snd_pcm_update_hw_ptr*() is done by
@@ -1614,26 +1578,23 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream,
* delta, effectively to skip the check once.
*/
substream->runtime->hw_ptr_jiffies = jiffies - HZ * 1000;
- return substream->ops->trigger(substream,
- pause_pushed(state) ?
+ return substream->ops->trigger(substream, pause_pushed(state) ?
SNDRV_PCM_TRIGGER_PAUSE_PUSH :
SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
}
-static void snd_pcm_undo_pause(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static void snd_pcm_undo_pause(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
if (substream->runtime->trigger_master == substream)
- substream->ops->trigger(substream,
- pause_pushed(state) ?
+ substream->ops->trigger(substream, pause_pushed(state) ?
SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
SNDRV_PCM_TRIGGER_PAUSE_PUSH);
}
-static void snd_pcm_post_pause(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static void snd_pcm_post_pause(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
snd_pcm_trigger_tstamp(substream);
if (pause_pushed(state)) {
__snd_pcm_set_state(runtime, SNDRV_PCM_STATE_PAUSED);
@@ -1658,24 +1619,23 @@ static const struct action_ops snd_pcm_action_pause = {
*/
static int snd_pcm_pause(struct snd_pcm_substream *substream, bool push)
{
- return snd_pcm_action(&snd_pcm_action_pause, substream,
- (__force snd_pcm_state_t)push);
+ return snd_pcm_action(&snd_pcm_action_pause, substream, (__force snd_pcm_state_t)push);
}
-static int snd_pcm_pause_lock_irq(struct snd_pcm_substream *substream,
- bool push)
+static int snd_pcm_pause_lock_irq(struct snd_pcm_substream *substream, bool push)
{
return snd_pcm_action_lock_irq(&snd_pcm_action_pause, substream,
(__force snd_pcm_state_t)push);
}
#ifdef CONFIG_PM
+
/* suspend callback: state argument ignored */
-static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
switch (runtime->state) {
case SNDRV_PCM_STATE_SUSPENDED:
return -EBUSY;
@@ -1689,23 +1649,23 @@ static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream,
return 0;
}
-static int snd_pcm_do_suspend(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static int snd_pcm_do_suspend(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
if (runtime->trigger_master != substream)
return 0;
- if (! snd_pcm_running(substream))
+ if (!snd_pcm_running(substream))
return 0;
substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND);
runtime->stop_operating = true;
return 0; /* suspend unconditionally */
}
-static void snd_pcm_post_suspend(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
snd_pcm_trigger_tstamp(substream);
runtime->suspended_state = runtime->state;
runtime->status->suspended_state = runtime->suspended_state;
@@ -1735,8 +1695,7 @@ static int snd_pcm_suspend(struct snd_pcm_substream *substream)
unsigned long flags;
snd_pcm_stream_lock_irqsave(substream, flags);
- err = snd_pcm_action(&snd_pcm_action_suspend, substream,
- ACTION_ARG_IGNORE);
+ err = snd_pcm_action(&snd_pcm_action_suspend, substream, ACTION_ARG_IGNORE);
snd_pcm_stream_unlock_irqrestore(substream, flags);
return err;
}
@@ -1754,7 +1713,7 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm)
struct snd_pcm_substream *substream;
int stream, err = 0;
- if (! pcm)
+ if (!pcm)
return 0;
for_each_pcm_substream(pcm, stream, substream) {
@@ -1783,20 +1742,20 @@ EXPORT_SYMBOL(snd_pcm_suspend_all);
/* resume callbacks: state argument ignored */
-static int snd_pcm_pre_resume(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
if (!(runtime->info & SNDRV_PCM_INFO_RESUME))
return -ENOSYS;
runtime->trigger_master = substream;
return 0;
}
-static int snd_pcm_do_resume(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static int snd_pcm_do_resume(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
if (runtime->trigger_master != substream)
return 0;
/* DMA not running previously? */
@@ -1807,18 +1766,16 @@ static int snd_pcm_do_resume(struct snd_pcm_substream *substream,
return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME);
}
-static void snd_pcm_undo_resume(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static void snd_pcm_undo_resume(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
- if (substream->runtime->trigger_master == substream &&
- snd_pcm_running(substream))
+ if (substream->runtime->trigger_master == substream && snd_pcm_running(substream))
substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND);
}
-static void snd_pcm_post_resume(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static void snd_pcm_post_resume(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
snd_pcm_trigger_tstamp(substream);
__snd_pcm_set_state(runtime, runtime->suspended_state);
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME);
@@ -1833,8 +1790,7 @@ static const struct action_ops snd_pcm_action_resume = {
static int snd_pcm_resume(struct snd_pcm_substream *substream)
{
- return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream,
- ACTION_ARG_IGNORE);
+ return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, ACTION_ARG_IGNORE);
}
#else
@@ -1876,10 +1832,10 @@ static int snd_pcm_xrun(struct snd_pcm_substream *substream)
* reset ioctl
*/
/* reset callbacks: state argument ignored */
-static int snd_pcm_pre_reset(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static int snd_pcm_pre_reset(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
switch (runtime->state) {
case SNDRV_PCM_STATE_RUNNING:
case SNDRV_PCM_STATE_PREPARED:
@@ -1891,11 +1847,12 @@ static int snd_pcm_pre_reset(struct snd_pcm_substream *substream,
}
}
-static int snd_pcm_do_reset(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static int snd_pcm_do_reset(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
+ int err;
+
+ err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
if (err < 0)
return err;
snd_pcm_stream_lock_irq(substream);
@@ -1908,14 +1865,13 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream,
return 0;
}
-static void snd_pcm_post_reset(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static void snd_pcm_post_reset(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
snd_pcm_stream_lock_irq(substream);
runtime->control->appl_ptr = runtime->status->hw_ptr;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- runtime->silence_size > 0)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
snd_pcm_stream_unlock_irq(substream);
}
@@ -1928,16 +1884,14 @@ static const struct action_ops snd_pcm_action_reset = {
static int snd_pcm_reset(struct snd_pcm_substream *substream)
{
- return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream,
- ACTION_ARG_IGNORE);
+ return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream, ACTION_ARG_IGNORE);
}
/*
* prepare ioctl
*/
/* pass f_flags as state argument */
-static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int f_flags = (__force int)state;
@@ -1951,10 +1905,10 @@ static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,
return 0;
}
-static int snd_pcm_do_prepare(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
int err;
+
snd_pcm_sync_stop(substream, true);
err = substream->ops->prepare(substream);
if (err < 0)
@@ -1962,10 +1916,10 @@ static int snd_pcm_do_prepare(struct snd_pcm_substream *substream,
return snd_pcm_do_reset(substream, state);
}
-static void snd_pcm_post_prepare(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
runtime->control->appl_ptr = runtime->status->hw_ptr;
snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
}
@@ -1983,8 +1937,7 @@ static const struct action_ops snd_pcm_action_prepare = {
*
* Return: Zero if successful, or a negative error code.
*/
-static int snd_pcm_prepare(struct snd_pcm_substream *substream,
- struct file *file)
+static int snd_pcm_prepare(struct snd_pcm_substream *substream, struct file *file)
{
int f_flags;
@@ -2004,8 +1957,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
}
snd_pcm_stream_unlock_irq(substream);
- return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
- substream,
+ return snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream,
(__force snd_pcm_state_t)f_flags);
}
@@ -2014,10 +1966,10 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
*/
/* drain init callbacks: state argument ignored */
-static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
switch (runtime->state) {
case SNDRV_PCM_STATE_OPEN:
case SNDRV_PCM_STATE_DISCONNECTED:
@@ -2028,15 +1980,15 @@ static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream,
return 0;
}
-static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
switch (runtime->state) {
case SNDRV_PCM_STATE_PREPARED:
/* start playback stream if possible */
- if (! snd_pcm_playback_empty(substream)) {
+ if (!snd_pcm_playback_empty(substream)) {
snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING);
snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING);
} else {
@@ -2064,17 +2016,15 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream,
}
}
- if (runtime->state == SNDRV_PCM_STATE_DRAINING &&
- runtime->trigger_master == substream &&
- (runtime->hw.info & SNDRV_PCM_INFO_DRAIN_TRIGGER))
+ if (runtime->state == SNDRV_PCM_STATE_DRAINING && runtime->trigger_master == substream &&
+ runtime->hw.info & SNDRV_PCM_INFO_DRAIN_TRIGGER)
return substream->ops->trigger(substream,
SNDRV_PCM_TRIGGER_DRAIN);
return 0;
}
-static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream,
- snd_pcm_state_t state)
+static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
}
@@ -2091,8 +2041,7 @@ static const struct action_ops snd_pcm_action_drain_init = {
* After this call, all streams are supposed to be either SETUP or DRAINING
* (capture only) state.
*/
-static int snd_pcm_drain(struct snd_pcm_substream *substream,
- struct file *file)
+static int snd_pcm_drain(struct snd_pcm_substream *substream, struct file *file)
{
struct snd_card *card;
struct snd_pcm_runtime *runtime;
@@ -2111,8 +2060,9 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
if (file) {
if (file->f_flags & O_NONBLOCK)
nonblock = 1;
- } else if (substream->f_flags & O_NONBLOCK)
+ } else if (substream->f_flags & O_NONBLOCK) {
nonblock = 1;
+ }
snd_pcm_stream_lock_irq(substream);
/* resume pause */
@@ -2120,8 +2070,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
snd_pcm_pause(substream, false);
/* pre-start/stop - all running streams are changed to DRAINING state */
- result = snd_pcm_action(&snd_pcm_action_drain_init, substream,
- ACTION_ARG_IGNORE);
+ result = snd_pcm_action(&snd_pcm_action_drain_init, substream, ACTION_ARG_IGNORE);
if (result < 0)
goto unlock;
/* in non-blocking, we don't wait in ioctl but let caller poll */
@@ -2131,8 +2080,9 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
}
for (;;) {
- long tout;
+ long tout, t;
struct snd_pcm_runtime *to_check;
+
if (signal_pending(current)) {
result = -ERESTARTSYS;
break;
@@ -2156,12 +2106,12 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&to_check->sleep, &wait);
snd_pcm_stream_unlock_irq(substream);
- if (runtime->no_period_wakeup)
+ if (runtime->no_period_wakeup) {
tout = MAX_SCHEDULE_TIMEOUT;
- else {
+ } else {
tout = 100;
if (runtime->rate) {
- long t = runtime->buffer_size * 1100 / runtime->rate;
+ t = runtime->buffer_size * 1100 / runtime->rate;
tout = max(t, tout);
}
tout = msecs_to_jiffies(tout);
@@ -2183,9 +2133,9 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
break;
}
if (tout == 0) {
- if (substream->runtime->state == SNDRV_PCM_STATE_SUSPENDED)
+ if (substream->runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
result = -ESTRPIPE;
- else {
+ } else {
dev_dbg(substream->pcm->card->dev,
"playback drain timeout (DMA or IRQ trouble?)\n");
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
@@ -2195,7 +2145,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
}
}
- unlock:
+unlock:
snd_pcm_stream_unlock_irq(substream);
return result;
@@ -2210,7 +2160,7 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime;
int result = 0;
-
+
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
runtime = substream->runtime;
@@ -2231,7 +2181,6 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
return result;
}
-
static bool is_pcm_file(struct file *file)
{
struct inode *inode = file_inode(file);
@@ -2347,8 +2296,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
/* detach the last stream, too */
if (list_is_singular(&group->substreams)) {
- relink_to_local(list_first_entry(&group->substreams,
- struct snd_pcm_substream,
+ relink_to_local(list_first_entry(&group->substreams, struct snd_pcm_substream,
link_list));
do_free = refcount_dec_and_test(&group->refs);
}
@@ -2357,7 +2305,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
if (do_free)
kfree(group);
- _end:
+_end:
up_write(&snd_pcm_link_rwsem);
return res;
}
@@ -2365,62 +2313,62 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
/*
* hw configurator
*/
-static int snd_pcm_hw_rule_mul(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int snd_pcm_hw_rule_mul(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
{
struct snd_interval t;
+
snd_interval_mul(hw_param_interval_c(params, rule->deps[0]),
- hw_param_interval_c(params, rule->deps[1]), &t);
+ hw_param_interval_c(params, rule->deps[1]), &t);
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-static int snd_pcm_hw_rule_div(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int snd_pcm_hw_rule_div(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
{
struct snd_interval t;
+
snd_interval_div(hw_param_interval_c(params, rule->deps[0]),
- hw_param_interval_c(params, rule->deps[1]), &t);
+ hw_param_interval_c(params, rule->deps[1]), &t);
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-static int snd_pcm_hw_rule_muldivk(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int snd_pcm_hw_rule_muldivk(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
{
struct snd_interval t;
+
snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]),
- hw_param_interval_c(params, rule->deps[1]),
- (unsigned long) rule->private, &t);
+ hw_param_interval_c(params, rule->deps[1]),
+ (unsigned long)rule->private, &t);
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-static int snd_pcm_hw_rule_mulkdiv(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int snd_pcm_hw_rule_mulkdiv(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
{
struct snd_interval t;
+
snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]),
- (unsigned long) rule->private,
- hw_param_interval_c(params, rule->deps[1]), &t);
+ (unsigned long)rule->private,
+ hw_param_interval_c(params, rule->deps[1]), &t);
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
{
snd_pcm_format_t k;
- const struct snd_interval *i =
- hw_param_interval_c(params, rule->deps[0]);
+ const struct snd_interval *i = hw_param_interval_c(params, rule->deps[0]);
struct snd_mask m;
struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
snd_mask_any(&m);
pcm_for_each_format(k) {
int bits;
+
if (!snd_mask_test_format(mask, k))
continue;
bits = snd_pcm_format_physical_width(k);
if (bits <= 0)
continue; /* ignore invalid formats */
- if ((unsigned)bits < i->min || (unsigned)bits > i->max)
- snd_mask_reset(&m, (__force unsigned)k);
+ if ((unsigned int)bits < i->min || (unsigned int)bits > i->max)
+ snd_mask_reset(&m, (__force unsigned int)k);
}
return snd_mask_refine(mask, &m);
}
@@ -2437,14 +2385,15 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
t.openmax = 0;
pcm_for_each_format(k) {
int bits;
+
if (!snd_mask_test_format(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k))
continue;
bits = snd_pcm_format_physical_width(k);
if (bits <= 0)
continue; /* ignore invalid formats */
- if (t.min > (unsigned)bits)
+ if (t.min > (unsigned int)bits)
t.min = bits;
- if (t.max < (unsigned)bits)
+ if (t.max < (unsigned int)bits)
t.max = bits;
}
t.integer = 1;
@@ -2465,27 +2414,28 @@ const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
.list = rates,
};
-static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
{
struct snd_pcm_hardware *hw = rule->private;
+
return snd_interval_list(hw_param_interval(params, rule->var),
snd_pcm_known_rates.count,
snd_pcm_known_rates.list, hw->rates);
-}
+}
static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_interval t;
struct snd_pcm_substream *substream = rule->private;
+
t.min = 0;
t.max = substream->buffer_bytes_max;
t.openmin = 0;
t.openmax = 0;
t.integer = 1;
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
-}
+}
static int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream)
{
@@ -2493,13 +2443,11 @@ static int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream)
struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
int k, err;
- for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {
+ for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++)
snd_mask_any(constrs_mask(constrs, k));
- }
- for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {
+ for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
snd_interval_any(constrs_interval(constrs, k));
- }
snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_CHANNELS));
snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_SIZE));
@@ -2508,103 +2456,115 @@ static int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream)
snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_FRAME_BITS));
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
- snd_pcm_hw_rule_format, NULL,
+ snd_pcm_hw_rule_format, NULL,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
snd_pcm_hw_rule_sample_bits, NULL,
- SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_HW_PARAM_FORMAT,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
snd_pcm_hw_rule_div, NULL,
- SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS,
snd_pcm_hw_rule_mul, NULL,
- SNDRV_PCM_HW_PARAM_SAMPLE_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS,
- snd_pcm_hw_rule_mulkdiv, (void*) 8,
- SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ snd_pcm_hw_rule_mulkdiv, (void *)8,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS,
- snd_pcm_hw_rule_mulkdiv, (void*) 8,
- SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ snd_pcm_hw_rule_mulkdiv, (void *)8,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_pcm_hw_rule_div, NULL,
- SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
+ SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_TIME, -1);
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ snd_pcm_hw_rule_mulkdiv, (void *)1000000,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ SNDRV_PCM_HW_PARAM_PERIOD_TIME, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_BUFFER_TIME, -1);
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ snd_pcm_hw_rule_mulkdiv, (void *)1000000,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ SNDRV_PCM_HW_PARAM_BUFFER_TIME, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS,
snd_pcm_hw_rule_div, NULL,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
snd_pcm_hw_rule_div, NULL,
SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- snd_pcm_hw_rule_mulkdiv, (void*) 8,
- SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ snd_pcm_hw_rule_mulkdiv, (void *)8,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- snd_pcm_hw_rule_muldivk, (void*) 1000000,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ snd_pcm_hw_rule_muldivk, (void *)1000000,
SNDRV_PCM_HW_PARAM_PERIOD_TIME, SNDRV_PCM_HW_PARAM_RATE, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
snd_pcm_hw_rule_mul, NULL,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- snd_pcm_hw_rule_mulkdiv, (void*) 8,
- SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ snd_pcm_hw_rule_mulkdiv, (void *)8,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- snd_pcm_hw_rule_muldivk, (void*) 1000000,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ snd_pcm_hw_rule_muldivk, (void *)1000000,
SNDRV_PCM_HW_PARAM_BUFFER_TIME, SNDRV_PCM_HW_PARAM_RATE, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
- snd_pcm_hw_rule_muldivk, (void*) 8,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ snd_pcm_hw_rule_muldivk, (void *)8,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
- snd_pcm_hw_rule_muldivk, (void*) 8,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ snd_pcm_hw_rule_muldivk, (void *)8,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
- snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+ snd_pcm_hw_rule_mulkdiv, (void *)1000000,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1);
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
- snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
+ snd_pcm_hw_rule_mulkdiv, (void *)1000000,
SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1);
if (err < 0)
return err;
@@ -2618,9 +2578,9 @@ static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
int err;
unsigned int mask = 0;
- if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)
+ if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)
mask |= PARAM_MASK_BIT(SNDRV_PCM_ACCESS_RW_INTERLEAVED);
- if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
+ if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
mask |= PARAM_MASK_BIT(SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
if (hw_support_mmap(substream)) {
if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)
@@ -2668,7 +2628,7 @@ static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
if (err < 0)
return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
snd_pcm_hw_rule_buffer_bytes_max, substream,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1);
if (err < 0)
@@ -2676,13 +2636,14 @@ static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
/* FIXME: remove */
if (runtime->dma_bytes) {
- err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes);
+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ 0, runtime->dma_bytes);
if (err < 0)
return err;
}
if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) {
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
snd_pcm_hw_rule_rate, hw,
SNDRV_PCM_HW_PARAM_RATE, -1);
if (err < 0)
@@ -2724,8 +2685,7 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL(snd_pcm_release_substream);
-int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
- struct file *file,
+int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct file *file,
struct snd_pcm_substream **rsubstream)
{
struct snd_pcm_substream *substream;
@@ -2760,8 +2720,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
/* automatically set EXPLICIT_SYNC flag in the managed mode whenever
* the DMA buffer requires it
*/
- if (substream->managed_buffer_alloc &&
- substream->dma_buffer.dev.need_sync)
+ if (substream->managed_buffer_alloc && substream->dma_buffer.dev.need_sync)
substream->runtime->hw.info |= SNDRV_PCM_INFO_EXPLICIT_SYNC;
*rsubstream = substream;
@@ -2773,9 +2732,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
}
EXPORT_SYMBOL(snd_pcm_open_substream);
-static int snd_pcm_open_file(struct file *file,
- struct snd_pcm *pcm,
- int stream)
+static int snd_pcm_open_file(struct file *file, struct snd_pcm *pcm, int stream)
{
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream;
@@ -2786,7 +2743,7 @@ static int snd_pcm_open_file(struct file *file,
return err;
pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
- if (pcm_file == NULL) {
+ if (!pcm_file) {
snd_pcm_release_substream(substream);
return -ENOMEM;
}
@@ -2802,10 +2759,10 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
{
struct snd_pcm *pcm;
int err = nonseekable_open(inode, file);
+
if (err < 0)
return err;
- pcm = snd_lookup_minor_data(iminor(inode),
- SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
+ pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
if (pcm)
snd_card_unref(pcm->card);
@@ -2816,10 +2773,10 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file)
{
struct snd_pcm *pcm;
int err = nonseekable_open(inode, file);
+
if (err < 0)
return err;
- pcm = snd_lookup_minor_data(iminor(inode),
- SNDRV_DEVICE_TYPE_PCM_CAPTURE);
+ pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_CAPTURE);
err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
if (pcm)
snd_card_unref(pcm->card);
@@ -2831,7 +2788,7 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
int err;
wait_queue_entry_t wait;
- if (pcm == NULL) {
+ if (!pcm) {
err = -ENODEV;
goto __error1;
}
@@ -2854,8 +2811,9 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
err = -EBUSY;
break;
}
- } else
+ } else {
break;
+ }
set_current_state(TASK_INTERRUPTIBLE);
mutex_unlock(&pcm->open_mutex);
schedule();
@@ -2875,12 +2833,12 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
goto __error;
return err;
- __error:
+__error:
module_put(pcm->card->module);
- __error2:
- snd_card_file_remove(pcm->card, file);
- __error1:
- return err;
+__error2:
+ snd_card_file_remove(pcm->card, file);
+__error1:
+ return err;
}
static int snd_pcm_release(struct inode *inode, struct file *file)
@@ -2935,7 +2893,7 @@ static int do_pcm_hwsync(struct snd_pcm_substream *substream)
/* increase the appl_ptr; returns the processed frames or a negative error */
static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream,
snd_pcm_uframes_t frames,
- snd_pcm_sframes_t avail)
+ snd_pcm_sframes_t avail)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t appl_ptr;
@@ -2988,8 +2946,7 @@ static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream,
snd_pcm_stream_lock_irq(substream);
ret = do_pcm_hwsync(substream);
if (!ret)
- ret = rewind_appl_ptr(substream, frames,
- snd_pcm_hw_avail(substream));
+ ret = rewind_appl_ptr(substream, frames, snd_pcm_hw_avail(substream));
snd_pcm_stream_unlock_irq(substream);
if (ret >= 0)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
@@ -3007,16 +2964,14 @@ static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream,
snd_pcm_stream_lock_irq(substream);
ret = do_pcm_hwsync(substream);
if (!ret)
- ret = forward_appl_ptr(substream, frames,
- snd_pcm_avail(substream));
+ ret = forward_appl_ptr(substream, frames, snd_pcm_avail(substream));
snd_pcm_stream_unlock_irq(substream);
if (ret >= 0)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
return ret;
}
-static int snd_pcm_delay(struct snd_pcm_substream *substream,
- snd_pcm_sframes_t *delay)
+static int snd_pcm_delay(struct snd_pcm_substream *substream, snd_pcm_sframes_t *delay)
{
int err;
@@ -3029,7 +2984,7 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
return err;
}
-
+
static inline int snd_pcm_hwsync(struct snd_pcm_substream *substream)
{
return snd_pcm_delay(substream, NULL);
@@ -3045,10 +3000,11 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
int err;
memset(&sync_ptr, 0, sizeof(sync_ptr));
- if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags)))
+ if (get_user(sync_ptr.flags, (unsigned __user *)&_sync_ptr->flags))
+ return -EFAULT;
+ if (copy_from_user(&sync_ptr.c.control, &_sync_ptr->c.control,
+ sizeof(struct snd_pcm_mmap_control)))
return -EFAULT;
- if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct snd_pcm_mmap_control)))
- return -EFAULT;
status = runtime->status;
control = runtime->control;
if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
@@ -3058,8 +3014,7 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
}
snd_pcm_stream_lock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
- err = pcm_lib_apply_appl_ptr(substream,
- sync_ptr.c.control.appl_ptr);
+ err = pcm_lib_apply_appl_ptr(substream, sync_ptr.c.control.appl_ptr);
if (err < 0) {
snd_pcm_stream_unlock_irq(substream);
return err;
@@ -3093,7 +3048,7 @@ struct snd_pcm_mmap_status32 {
snd_pcm_state_t suspended_state;
s32 audio_tstamp_sec;
s32 audio_tstamp_nsec;
-} __attribute__((packed));
+} __packed;
struct snd_pcm_mmap_control32 {
u32 appl_ptr;
@@ -3110,14 +3065,14 @@ struct snd_pcm_sync_ptr32 {
struct snd_pcm_mmap_control32 control;
unsigned char reserved[64];
} c;
-} __attribute__((packed));
+} __packed;
/* recalcuate the boundary within 32bit */
static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t boundary;
- if (! runtime->buffer_size)
+ if (!runtime->buffer_size)
return 0;
boundary = runtime->buffer_size;
while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
@@ -3152,19 +3107,19 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
status = runtime->status;
control = runtime->control;
boundary = recalculate_boundary(runtime);
- if (! boundary)
+ if (!boundary)
boundary = 0x7fffffff;
snd_pcm_stream_lock_irq(substream);
/* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
- err = pcm_lib_apply_appl_ptr(substream,
- scontrol.appl_ptr);
+ err = pcm_lib_apply_appl_ptr(substream, scontrol.appl_ptr);
if (err < 0) {
snd_pcm_stream_unlock_irq(substream);
return err;
}
- } else
+ } else {
scontrol.appl_ptr = control->appl_ptr % boundary;
+ }
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min;
else
@@ -3190,13 +3145,14 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
return 0;
}
+
#define __SNDRV_PCM_IOCTL_SYNC_PTR32 _IOWR('A', 0x23, struct snd_pcm_sync_ptr32)
static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int arg;
-
+
if (get_user(arg, _arg))
return -EFAULT;
if (arg < 0 || arg > SNDRV_PCM_TSTAMP_TYPE_LAST)
@@ -3290,8 +3246,8 @@ static int snd_pcm_forward_ioctl(struct snd_pcm_substream *substream,
}
static int snd_pcm_common_ioctl(struct file *file,
- struct snd_pcm_substream *substream,
- unsigned int cmd, void __user *arg)
+ struct snd_pcm_substream *substream,
+ unsigned int cmd, void __user *arg)
{
struct snd_pcm_file *pcm_file = file->private_data;
int res;
@@ -3316,8 +3272,7 @@ static int snd_pcm_common_ioctl(struct file *file,
case SNDRV_PCM_IOCTL_TTSTAMP:
return snd_pcm_tstamp(substream, arg);
case SNDRV_PCM_IOCTL_USER_PVERSION:
- if (get_user(pcm_file->user_pversion,
- (unsigned int __user *)arg))
+ if (get_user(pcm_file->user_pversion, (unsigned int __user *)arg))
return -EFAULT;
return 0;
case SNDRV_PCM_IOCTL_HW_REFINE:
@@ -3345,7 +3300,7 @@ static int snd_pcm_common_ioctl(struct file *file,
case SNDRV_PCM_IOCTL_START:
return snd_pcm_start_lock_irq(substream);
case SNDRV_PCM_IOCTL_LINK:
- return snd_pcm_link(substream, (int)(unsigned long) arg);
+ return snd_pcm_link(substream, (int)(unsigned long)arg);
case SNDRV_PCM_IOCTL_UNLINK:
return snd_pcm_unlink(substream);
case SNDRV_PCM_IOCTL_RESUME:
@@ -3398,8 +3353,7 @@ static int snd_pcm_common_ioctl(struct file *file,
return -ENOTTY;
}
-static long snd_pcm_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+static long snd_pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct snd_pcm_file *pcm_file;
@@ -3408,8 +3362,7 @@ static long snd_pcm_ioctl(struct file *file, unsigned int cmd,
if (((cmd >> 8) & 0xff) != 'A')
return -ENOTTY;
- return snd_pcm_common_ioctl(file, pcm_file->substream, cmd,
- (void __user *)arg);
+ return snd_pcm_common_ioctl(file, pcm_file->substream, cmd, (void __user *)arg);
}
/**
@@ -3424,12 +3377,11 @@ static long snd_pcm_ioctl(struct file *file, unsigned int cmd,
*
* Return: zero if successful, or a negative error code
*/
-int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
+int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg)
{
snd_pcm_uframes_t *frames = arg;
snd_pcm_sframes_t result;
-
+
if (substream->runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
@@ -3462,8 +3414,7 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
}
EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
-static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
- loff_t * offset)
+static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream;
@@ -3488,7 +3439,7 @@ static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
}
static ssize_t snd_pcm_write(struct file *file, const char __user *buf,
- size_t count, loff_t * offset)
+ size_t count, loff_t *offset)
{
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream;
@@ -3539,7 +3490,7 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
return -EINVAL;
frames = bytes_to_samples(runtime, iov->iov_len);
bufs = kmalloc_array(to->nr_segs, sizeof(void *), GFP_KERNEL);
- if (bufs == NULL)
+ if (!bufs)
return -ENOMEM;
for (i = 0; i < to->nr_segs; ++i) {
bufs[i] = iov->iov_base;
@@ -3578,7 +3529,7 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
return -EINVAL;
frames = bytes_to_samples(runtime, iov->iov_len);
bufs = kmalloc_array(from->nr_segs, sizeof(void *), GFP_KERNEL);
- if (bufs == NULL)
+ if (!bufs)
return -ENOMEM;
for (i = 0; i < from->nr_segs; ++i) {
bufs[i] = iov->iov_base;
@@ -3656,8 +3607,8 @@ static vm_fault_t snd_pcm_mmap_status_fault(struct vm_fault *vmf)
{
struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
struct snd_pcm_runtime *runtime;
-
- if (substream == NULL)
+
+ if (!substream)
return VM_FAULT_SIGBUS;
runtime = substream->runtime;
vmf->page = virt_to_page(runtime->status);
@@ -3665,8 +3616,7 @@ static vm_fault_t snd_pcm_mmap_status_fault(struct vm_fault *vmf)
return 0;
}
-static const struct vm_operations_struct snd_pcm_vm_ops_status =
-{
+static const struct vm_operations_struct snd_pcm_vm_ops_status = {
.fault = snd_pcm_mmap_status_fault,
};
@@ -3674,6 +3624,7 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file
struct vm_area_struct *area)
{
long size;
+
if (!(area->vm_flags & VM_READ))
return -EINVAL;
size = area->vm_end - area->vm_start;
@@ -3681,8 +3632,7 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file
return -EINVAL;
area->vm_ops = &snd_pcm_vm_ops_status;
area->vm_private_data = substream;
- vm_flags_mod(area, VM_DONTEXPAND | VM_DONTDUMP,
- VM_WRITE | VM_MAYWRITE);
+ vm_flags_mod(area, VM_DONTEXPAND | VM_DONTDUMP, VM_WRITE | VM_MAYWRITE);
return 0;
}
@@ -3694,8 +3644,8 @@ static vm_fault_t snd_pcm_mmap_control_fault(struct vm_fault *vmf)
{
struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
struct snd_pcm_runtime *runtime;
-
- if (substream == NULL)
+
+ if (!substream)
return VM_FAULT_SIGBUS;
runtime = substream->runtime;
vmf->page = virt_to_page(runtime->control);
@@ -3703,8 +3653,7 @@ static vm_fault_t snd_pcm_mmap_control_fault(struct vm_fault *vmf)
return 0;
}
-static const struct vm_operations_struct snd_pcm_vm_ops_control =
-{
+static const struct vm_operations_struct snd_pcm_vm_ops_control = {
.fault = snd_pcm_mmap_control_fault,
};
@@ -3712,6 +3661,7 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
struct vm_area_struct *area)
{
long size;
+
if (!(area->vm_flags & VM_READ))
return -EINVAL;
size = area->vm_end - area->vm_start;
@@ -3769,11 +3719,13 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file
{
return -ENXIO;
}
+
static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
return -ENXIO;
}
+
#endif /* coherent mmap */
/*
@@ -3784,10 +3736,10 @@ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf)
struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
struct snd_pcm_runtime *runtime;
unsigned long offset;
- struct page * page;
+ struct page *page;
size_t dma_bytes;
-
- if (substream == NULL)
+
+ if (!substream)
return VM_FAULT_SIGBUS;
runtime = substream->runtime;
offset = vmf->pgoff << PAGE_SHIFT;
@@ -3884,7 +3836,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
int err;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (!(area->vm_flags & (VM_WRITE|VM_READ)))
+ if (!(area->vm_flags & (VM_WRITE | VM_READ)))
return -EINVAL;
} else {
if (!(area->vm_flags & VM_READ))
@@ -3920,10 +3872,10 @@ EXPORT_SYMBOL(snd_pcm_mmap_data);
static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
{
- struct snd_pcm_file * pcm_file;
- struct snd_pcm_substream *substream;
+ struct snd_pcm_file *pcm_file;
+ struct snd_pcm_substream *substream;
unsigned long offset;
-
+
pcm_file = file->private_data;
substream = pcm_file->substream;
if (PCM_RUNTIME_CHECK(substream))
@@ -3955,9 +3907,9 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
return 0;
}
-static int snd_pcm_fasync(int fd, struct file * file, int on)
+static int snd_pcm_fasync(int fd, struct file *file, int on)
{
- struct snd_pcm_file * pcm_file;
+ struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
@@ -3985,8 +3937,8 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
*/
#ifdef CONFIG_SND_SUPPORT_OLD_API
-#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
-#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
+#define __OLD_TO_NEW_MASK(x) ((x & 7) | ((x & 0x07fffff8) << 5))
+#define __NEW_TO_OLD_MASK(x) ((x & 7) | ((x & 0xffffff00) >> 5))
static void snd_pcm_hw_convert_from_old_params(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_params_old *oparams)
@@ -4027,7 +3979,7 @@ static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *opara
}
static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params_old __user * _oparams)
+ struct snd_pcm_hw_params_old __user *_oparams)
{
struct snd_pcm_hw_params *params;
struct snd_pcm_hw_params_old *oparams = NULL;
@@ -4062,7 +4014,7 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
}
static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params_old __user * _oparams)
+ struct snd_pcm_hw_params_old __user *_oparams)
{
struct snd_pcm_hw_params *params;
struct snd_pcm_hw_params_old *oparams = NULL;
@@ -4095,10 +4047,8 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
#endif /* CONFIG_SND_SUPPORT_OLD_API */
#ifndef CONFIG_MMU
-static unsigned long snd_pcm_get_unmapped_area(struct file *file,
- unsigned long addr,
- unsigned long len,
- unsigned long pgoff,
+static unsigned long snd_pcm_get_unmapped_area(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long pgoff,
unsigned long flags)
{
struct snd_pcm_file *pcm_file = file->private_data;
@@ -4133,7 +4083,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
.llseek = no_llseek,
.poll = snd_pcm_poll,
.unlocked_ioctl = snd_pcm_ioctl,
- .compat_ioctl = snd_pcm_ioctl_compat,
+ .compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
.get_unmapped_area = snd_pcm_get_unmapped_area,
@@ -4147,7 +4097,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
.llseek = no_llseek,
.poll = snd_pcm_poll,
.unlocked_ioctl = snd_pcm_ioctl,
- .compat_ioctl = snd_pcm_ioctl_compat,
+ .compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
.get_unmapped_area = snd_pcm_get_unmapped_area,
--
2.34.1
5
7
Convert the NAU8825 audio CODEC bindings to DT schema.
Signed-off-by: David Lin <CTLIN0(a)nuvoton.com>
---
.../devicetree/bindings/sound/nau8825.txt | 111 --------
.../bindings/sound/nuvoton,nau8825.yaml | 242 ++++++++++++++++++
2 files changed, 242 insertions(+), 111 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/sound/nau8825.txt
create mode 100644 Documentation/devicetree/bindings/sound/nuvoton,nau8825.yaml
diff --git a/Documentation/devicetree/bindings/sound/nau8825.txt b/Documentation/devicetree/bindings/sound/nau8825.txt
deleted file mode 100644
index a9c34526f4cb..000000000000
--- a/Documentation/devicetree/bindings/sound/nau8825.txt
+++ /dev/null
@@ -1,111 +0,0 @@
-Nuvoton NAU8825 audio codec
-
-This device supports I2C only.
-
-Required properties:
- - compatible : Must be "nuvoton,nau8825"
-
- - reg : the I2C address of the device. This is either 0x1a (CSB=0) or 0x1b (CSB=1).
-
-Optional properties:
- - nuvoton,jkdet-enable: Enable jack detection via JKDET pin.
- - nuvoton,jkdet-pull-enable: Enable JKDET pin pull. If set - pin pull enabled,
- otherwise pin in high impedance state.
- - nuvoton,jkdet-pull-up: Pull-up JKDET pin. If set then JKDET pin is pull up, otherwise pull down.
- - nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low.
-
- - nuvoton,vref-impedance: VREF Impedance selection
- 0 - Open
- 1 - 25 kOhm
- 2 - 125 kOhm
- 3 - 2.5 kOhm
-
- - nuvoton,micbias-voltage: Micbias voltage level.
- 0 - VDDA
- 1 - VDDA
- 2 - VDDA * 1.1
- 3 - VDDA * 1.2
- 4 - VDDA * 1.3
- 5 - VDDA * 1.4
- 6 - VDDA * 1.53
- 7 - VDDA * 1.53
-
- - nuvoton,sar-threshold-num: Number of buttons supported
- - nuvoton,sar-threshold: Impedance threshold for each button. Array that contains up to 8 buttons configuration. SAR value is calculated as
- SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R)
- where MICBIAS is configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by 'nuvoton,sar-voltage', R - button impedance.
- Refer datasheet section 10.2 for more information about threshold calculation.
-
- - nuvoton,sar-hysteresis: Button impedance measurement hysteresis.
-
- - nuvoton,sar-voltage: Reference voltage for button impedance measurement.
- 0 - VDDA
- 1 - VDDA
- 2 - VDDA * 1.1
- 3 - VDDA * 1.2
- 4 - VDDA * 1.3
- 5 - VDDA * 1.4
- 6 - VDDA * 1.53
- 7 - VDDA * 1.53
-
- - nuvoton,sar-compare-time: SAR compare time
- 0 - 500 ns
- 1 - 1 us
- 2 - 2 us
- 3 - 4 us
-
- - nuvoton,sar-sampling-time: SAR sampling time
- 0 - 2 us
- 1 - 4 us
- 2 - 8 us
- 3 - 16 us
-
- - nuvoton,short-key-debounce: Button short key press debounce time.
- 0 - 30 ms
- 1 - 50 ms
- 2 - 100 ms
- 3 - 30 ms
-
- - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
- - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
-
- - nuvoton,crosstalk-enable: make crosstalk function enable if set.
-
- - nuvoton,adcout-drive-strong: make the drive strength of ADCOUT IO PIN strong if set.
- Otherwise, the drive keeps normal strength.
-
- - nuvoton,adc-delay-ms: Delay (in ms) to make input path stable and avoid pop noise. The
- default value is 125 and range between 125 to 500 ms.
-
- - clocks: list of phandle and clock specifier pairs according to common clock bindings for the
- clocks described in clock-names
- - clock-names: should include "mclk" for the MCLK master clock
-
-Example:
-
- headset: nau8825@1a {
- compatible = "nuvoton,nau8825";
- reg = <0x1a>;
- interrupt-parent = <&gpio>;
- interrupts = <TEGRA_GPIO(E, 6) IRQ_TYPE_LEVEL_LOW>;
- nuvoton,jkdet-enable;
- nuvoton,jkdet-pull-enable;
- nuvoton,jkdet-pull-up;
- nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
- nuvoton,vref-impedance = <2>;
- nuvoton,micbias-voltage = <6>;
- // Setup 4 buttons impedance according to Android specification
- nuvoton,sar-threshold-num = <4>;
- nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>;
- nuvoton,sar-hysteresis = <1>;
- nuvoton,sar-voltage = <0>;
- nuvoton,sar-compare-time = <0>;
- nuvoton,sar-sampling-time = <0>;
- nuvoton,short-key-debounce = <2>;
- nuvoton,jack-insert-debounce = <7>;
- nuvoton,jack-eject-debounce = <7>;
- nuvoton,crosstalk-enable;
-
- clock-names = "mclk";
- clocks = <&tegra_pmc TEGRA_PMC_CLK_OUT_2>;
- };
diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8825.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8825.yaml
new file mode 100644
index 000000000000..ab352422d48e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8825.yaml
@@ -0,0 +1,242 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nuvoton,nau8825.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NAU8825 audio CODEC
+
+maintainers:
+ - John Hsu <KCHSU0(a)nuvoton.com>
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ enum:
+ - nuvoton,nau8825
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+ description:
+ The CODEC's interrupt output.
+
+ nuvoton,jkdet-enable:
+ description:
+ Enable jack detection via JKDET pin.
+ type: boolean
+
+ nuvoton,jkdet-pull-enable:
+ description:
+ Enable JKDET pin pull.
+ If set - pin pull enabled, otherwise pin in high impedance state.
+ type: boolean
+
+ nuvoton,jkdet-pull-up:
+ description:
+ Pull-up JKDET pin.
+ If set then JKDET pin is pull up, otherwise pull down.
+ type: boolean
+
+ nuvoton,jkdet-polarity:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ JKDET pin polarity.
+ enum:
+ - 0 # active high
+ - 1 # active low
+ default: 1
+
+ nuvoton,vref-impedance:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ VREF Impedance selection.
+ enum:
+ - 0 # Open
+ - 1 # 25 kOhm
+ - 2 # 125 kOhm
+ - 3 # 2.5 kOhm
+ default: 2
+
+ nuvoton,micbias-voltage:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Micbias voltage level.
+ enum:
+ - 0 # VDDA
+ - 1 # VDDA
+ - 2 # VDDA * 1.1
+ - 3 # VDDA * 1.2
+ - 4 # VDDA * 1.3
+ - 5 # VDDA * 1.4
+ - 6 # VDDA * 1.53
+ - 7 # VDDA * 1.53
+ default: 6
+
+ nuvoton,sar-threshold-num:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Number of buttons supported.
+ minimum: 1
+ maximum: 4
+ default: 4
+
+ nuvoton,sar-threshold:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description:
+ Impedance threshold for each button. Array that contains up to 8 buttons
+ configuration. SAR value is calculated as
+ SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R) where MICBIAS is
+ configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by
+ 'nuvoton,sar-voltage', R - button impedance.
+ Refer datasheet section 10.2 for more information about threshold
+ calculation.
+ minItems: 1
+ maxItems: 4
+ items:
+ minimum: 0
+ maximum: 255
+
+ nuvoton,sar-hysteresis:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Button impedance measurement hysteresis.
+ default: 0
+
+ nuvoton,sar-voltage:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Reference voltage for button impedance measurement.
+ enum:
+ - 0 # VDDA
+ - 1 # VDDA
+ - 2 # VDDA * 1.1
+ - 3 # VDDA * 1.2
+ - 4 # VDDA * 1.3
+ - 5 # VDDA * 1.4
+ - 6 # VDDA * 1.53
+ - 7 # VDDA * 1.53
+ default: 6
+
+ nuvoton,sar-compare-time:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ SAR compare time.
+ enum:
+ - 0 # 500 ns
+ - 1 # 1 us
+ - 2 # 2 us
+ - 3 # 4 us
+ default: 1
+
+ nuvoton,sar-sampling-time:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ SAR sampling time.
+ enum:
+ - 0 # 2 us
+ - 1 # 4 us
+ - 2 # 8 us
+ - 3 # 16 us
+ default: 1
+
+ nuvoton,short-key-debounce:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Button short key press debounce time.
+ enum:
+ - 0 # 30 ms
+ - 1 # 50 ms
+ - 2 # 100 ms
+ - 3 # 30 ms
+ default: 3
+
+ nuvoton,jack-insert-debounce:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ number from 0 to 7 that sets debounce time to 2^(n+2) ms.
+ maximum: 7
+ default: 7
+
+ nuvoton,jack-eject-debounce:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ number from 0 to 7 that sets debounce time to 2^(n+2) ms
+ maximum: 7
+ default: 0
+
+ nuvoton,crosstalk-enable:
+ description:
+ make crosstalk function enable if set.
+ type: boolean
+
+ nuvoton,adcout-drive-strong:
+ description:
+ make the drive strength of ADCOUT IO PIN strong if set.
+ Otherwise, the drive keeps normal strength.
+ type: boolean
+
+ nuvoton,adc-delay-ms:
+ description:
+ Delay (in ms) to make input path stable and avoid pop noise.
+ The default value is 125 and range between 125 to 500 ms.
+ minimum: 125
+ maximum: 500
+ default: 125
+
+ clocks:
+ description:
+ list of phandle and clock specifier pairs according to common clock
+ bindings for the clocks described in clock-names.
+ maxItems: 1
+
+ clock-names:
+ description:
+ should include "mclk" for the MCLK master clock.
+ items:
+ - const: mclk
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ nau8825@1a {
+ compatible = "nuvoton,nau8825";
+ reg = <0x1a>;
+ interrupt-parent = <&gpio>;
+ interrupts = <38 IRQ_TYPE_LEVEL_LOW>;
+ nuvoton,jkdet-enable;
+ nuvoton,jkdet-pull-enable;
+ nuvoton,jkdet-pull-up;
+ nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
+ nuvoton,vref-impedance = <2>;
+ nuvoton,micbias-voltage = <6>;
+ // Setup 4 buttons impedance according to Android specification
+ nuvoton,sar-threshold-num = <4>;
+ nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>;
+ nuvoton,sar-hysteresis = <1>;
+ nuvoton,sar-voltage = <0>;
+ nuvoton,sar-compare-time = <0>;
+ nuvoton,sar-sampling-time = <0>;
+ nuvoton,short-key-debounce = <2>;
+ nuvoton,jack-insert-debounce = <7>;
+ nuvoton,jack-eject-debounce = <7>;
+ nuvoton,crosstalk-enable;
+
+ clock-names = "mclk";
+ clocks = <&tegra_pmc 1>;
+ };
+ };
--
2.25.1
3
4
alsa-project/alsa-ucm-conf issue #312 was opened from benfuddled:
- Distribution and distribution version: Pop!_OS 22.04 LTS (I've also experienced this issue on multiple versions of Fedora and Ubuntu.
- Desktop Environment: Gnome 42
- Kernel version (uname -r): 6.2.6-76060206-generic
- PipeWire version: 0.3.70
## Description of Problem:
My laptop (an HP Spectre X360 13-4002dx) speakers and headphone jack output audio at extremely low levels, to the point where initially I thought they weren't outputting audio at all. It was only when I allowed over-amplification in gnome-tweaks and holding my ear up to the speaker that I realized there was sound coming out.
However, when I plug in a pair of USB headphones (not via the headphone jack) sound levels are within expected range. Same thing if I output sound via HDMI to a television.
results of running alsa-info: http://alsa-project.org/db/?f=76b61d75f256f85bfcef41f7ae704fffb146cf06
Note: Myself and a few others had this problem and initially filed bugs independently with pipewire, but [a commenter](https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/2822#n… seemed to think it may be a problem with the UCM file for this device.
Hoping someone here can shed some light on the issue. Thank you!
Issue URL : https://github.com/alsa-project/alsa-ucm-conf/issues/312
Repository URL: https://github.com/alsa-project/alsa-ucm-conf
1
0
[PATCH] ASoC:codecs: lpass: Fix for KASAN use_after_free out of bounds
by Ravulapati Vishnu Vardhan Rao 09 May '23
by Ravulapati Vishnu Vardhan Rao 09 May '23
09 May '23
When we run syzkaller we get below Out of Bounds error.
"KASAN: slab-out-of-bounds Read in regcache_flat_read"
Below is the backtrace of the issue:
BUG: KASAN: slab-out-of-bounds in regcache_flat_read+0x10c/0x110
Read of size 4 at addr ffffff8088fbf714 by task syz-executor.4/14144
CPU: 6 PID: 14144 Comm: syz-executor.4 Tainted: G W
Hardware name: Qualcomm Technologies, Inc. sc7280 CRD platform (rev5+) (DT)
Call trace:
dump_backtrace+0x0/0x4ec
show_stack+0x34/0x50
dump_stack_lvl+0xdc/0x11c
print_address_description+0x30/0x2d8
kasan_report+0x178/0x1e4
__asan_report_load4_noabort+0x44/0x50
regcache_flat_read+0x10c/0x110
regcache_read+0xf8/0x5a0
_regmap_read+0x45c/0x86c
_regmap_update_bits+0x128/0x290
regmap_update_bits_base+0xc0/0x15c
snd_soc_component_update_bits+0xa8/0x22c
snd_soc_component_write_field+0x68/0xd4
tx_macro_put_dec_enum+0x1d0/0x268
snd_ctl_elem_write+0x288/0x474
By Error checking and checking valid values issue gets rectifies.
Signed-off-by: Ravulapati Vishnu Vardhan Rao <quic_visr(a)quicinc.com>
---
sound/soc/codecs/lpass-tx-macro.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index da6fcf7f0991..2fc150b17f29 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -746,6 +746,8 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
struct tx_macro *tx = snd_soc_component_get_drvdata(component);
val = ucontrol->value.enumerated.item[0];
+ if (val < 0 && val > 15)
+ return -EINVAL;
switch (e->reg) {
case CDC_TX_INP_MUX_ADC_MUX0_CFG0:
@@ -772,6 +774,9 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
case CDC_TX_INP_MUX_ADC_MUX7_CFG0:
mic_sel_reg = CDC_TX7_TX_PATH_CFG0;
break;
+ default:
+ dev_err(component->dev, "Error in configuration!!\n");
+ return -EINVAL;
}
if (val != 0) {
@@ -785,10 +790,16 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
snd_soc_component_write_field(component, mic_sel_reg,
CDC_TXn_ADC_DMIC_SEL_MASK, 1);
dmic = TX_ADC_TO_DMIC(val);
- dmic_clk_reg = CDC_TX_TOP_CSR_SWR_DMICn_CTL(dmic);
- snd_soc_component_write_field(component, dmic_clk_reg,
- CDC_TX_SWR_DMIC_CLK_SEL_MASK,
- tx->dmic_clk_div);
+ if (dmic < 4) {
+ dmic_clk_reg = CDC_TX_TOP_CSR_SWR_DMICn_CTL(dmic);
+ snd_soc_component_write_field(component, dmic_clk_reg,
+ CDC_TX_SWR_DMIC_CLK_SEL_MASK,
+ tx->dmic_clk_div);
+ } else {
+ dev_err(component->dev, "Error in dmic configuration!!\n");
+ return -EINVAL;
+ }
+
}
}
--
2.17.1
1
0
This is the initial codec driver for rt722-sdca.
Signed-off-by: Jack Yu <jack.yu(a)realtek.com>
---
Patch v2 : To fix warning message from kernel test robot.
Patch v3 : To add information for port configuration and separate
DAIs for dmic/speaker, hw_params settings are separated as well.
---
sound/soc/codecs/Kconfig | 7 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/rt722-sdca-sdw.c | 510 ++++++++++
sound/soc/codecs/rt722-sdca-sdw.h | 124 +++
sound/soc/codecs/rt722-sdca.c | 1555 +++++++++++++++++++++++++++++
sound/soc/codecs/rt722-sdca.h | 238 +++++
6 files changed, 2436 insertions(+)
create mode 100644 sound/soc/codecs/rt722-sdca-sdw.c
create mode 100644 sound/soc/codecs/rt722-sdca-sdw.h
create mode 100644 sound/soc/codecs/rt722-sdca.c
create mode 100644 sound/soc/codecs/rt722-sdca.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 79d2362ad055..a163e2afdf72 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -207,6 +207,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT712_SDCA_DMIC_SDW
imply SND_SOC_RT715_SDW
imply SND_SOC_RT715_SDCA_SDW
+ imply SND_SOC_RT722_SDCA_SDW
imply SND_SOC_RT1308_SDW
imply SND_SOC_RT1316_SDW
imply SND_SOC_RT1318_SDW
@@ -1539,6 +1540,12 @@ config SND_SOC_RT712_SDCA_DMIC_SDW
select REGMAP_SOUNDWIRE
select REGMAP_SOUNDWIRE_MBQ
+config SND_SOC_RT722_SDCA_SDW
+ tristate "Realtek RT722 SDCA Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+
config SND_SOC_RT715
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 5cdbae88e6e3..cd799306331c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -237,6 +237,7 @@ snd-soc-rt712-sdca-objs := rt712-sdca.o rt712-sdca-sdw.o
snd-soc-rt712-sdca-dmic-objs := rt712-sdca-dmic.o
snd-soc-rt715-objs := rt715.o rt715-sdw.o
snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o
+snd-soc-rt722-sdca-objs := rt722-sdca.o rt722-sdca-sdw.o
snd-soc-rt9120-objs := rt9120.o
snd-soc-sdw-mockup-objs := sdw-mockup.o
snd-soc-sgtl5000-objs := sgtl5000.o
@@ -607,6 +608,7 @@ obj-$(CONFIG_SND_SOC_RT712_SDCA_SDW) += snd-soc-rt712-sdca.o
obj-$(CONFIG_SND_SOC_RT712_SDCA_DMIC_SDW) += snd-soc-rt712-sdca-dmic.o
obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o
obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o
+obj-$(CONFIG_SND_SOC_RT722_SDCA_SDW) += snd-soc-rt722-sdca.o
obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o
obj-$(CONFIG_SND_SOC_SDW_MOCKUP) += snd-soc-sdw-mockup.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
new file mode 100644
index 000000000000..0a791a14215e
--- /dev/null
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -0,0 +1,510 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt722-sdca-sdw.c -- rt722 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2023 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm_runtime.h>
+#include <linux/soundwire/sdw_registers.h>
+
+#include "rt722-sdca.h"
+#include "rt722-sdca-sdw.h"
+
+static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f01 ... 0x2f0a:
+ case 0x2f35 ... 0x2f36:
+ case 0x2f50:
+ case 0x2f54:
+ case 0x2f58 ... 0x2f5d:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_SELECTED_MODE,
+ 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE,
+ 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER,
+ 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt722_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f01:
+ case 0x2f54:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE,
+ 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER,
+ 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2000000 ... 0x2000024:
+ case 0x2000029 ... 0x200004a:
+ case 0x2000051 ... 0x2000052:
+ case 0x200005a ... 0x200005b:
+ case 0x2000061 ... 0x2000069:
+ case 0x200006b:
+ case 0x2000070:
+ case 0x200007f:
+ case 0x2000082 ... 0x200008e:
+ case 0x2000090 ... 0x2000094:
+ case 0x5300000 ... 0x5300002:
+ case 0x5400002:
+ case 0x5600000 ... 0x5600007:
+ case 0x5700000 ... 0x5700004:
+ case 0x5800000 ... 0x5800004:
+ case 0x5b00003:
+ case 0x5c00011:
+ case 0x5d00006:
+ case 0x5f00000 ... 0x5f0000d:
+ case 0x5f00030:
+ case 0x6100000 ... 0x6100051:
+ case 0x6100055 ... 0x6100057:
+ case 0x6100062:
+ case 0x6100064 ... 0x6100065:
+ case 0x6100067:
+ case 0x6100070 ... 0x610007c:
+ case 0x6100080:
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_03):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_04):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME,
+ CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME,
+ CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME,
+ CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME,
+ CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44,
+ RT722_SDCA_CTL_FU_CH_GAIN, CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44,
+ RT722_SDCA_CTL_FU_CH_GAIN, CH_R):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt722_sdca_mbq_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2000000:
+ case 0x200000d:
+ case 0x2000019:
+ case 0x2000020:
+ case 0x2000030:
+ case 0x2000046:
+ case 0x2000067:
+ case 0x2000084:
+ case 0x2000086:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt722_sdca_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt722_sdca_readable_register,
+ .volatile_reg = rt722_sdca_volatile_register,
+ .max_register = 0x44ffffff,
+ .reg_defaults = rt722_sdca_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt722_sdca_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct regmap_config rt722_sdca_mbq_regmap = {
+ .name = "sdw-mbq",
+ .reg_bits = 32,
+ .val_bits = 16,
+ .readable_reg = rt722_sdca_mbq_readable_register,
+ .volatile_reg = rt722_sdca_mbq_volatile_register,
+ .max_register = 0x41000312,
+ .reg_defaults = rt722_sdca_mbq_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt722_sdca_mbq_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt722_sdca_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(&slave->dev);
+
+ /* Update the status */
+ rt722->status = status;
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt722->hw_init = false;
+
+ if (status == SDW_SLAVE_ATTACHED) {
+ if (rt722->hs_jack) {
+ /*
+ * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then
+ * if the device attached again, we will need to set the setting back.
+ * It could avoid losing the jack detection interrupt.
+ * This also could sync with the cache value as the rt722_sdca_jack_init set.
+ */
+ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6);
+ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ }
+ }
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt722->hw_init || rt722->status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt722_sdca_io_init(&slave->dev, slave);
+}
+
+static int rt722_sdca_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int nval;
+ int i, j;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+
+ prop->paging_support = true;
+
+ /*
+ * port = 1 for headphone playback
+ * port = 2 for headset-mic capture
+ * port = 3 for speaker playback
+ * port = 6 for digital-mic capture
+ */
+ prop->source_ports = BIT(6) | BIT(2); /* BITMAP: 01000100 */
+ prop->sink_ports = BIT(3) | BIT(1); /* BITMAP: 00001010 */
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].simple_ch_prep_sm = true;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* do this again for sink now */
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ j = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[j].num = bit;
+ dpn[j].type = SDW_DPN_FULL;
+ dpn[j].simple_ch_prep_sm = true;
+ dpn[j].ch_prep_timeout = 10;
+ j++;
+ }
+
+ /* set the timeout values */
+ prop->clk_stop_timeout = 200;
+
+ /* wake-up event */
+ prop->wake_capable = 1;
+
+ return 0;
+}
+
+static int rt722_sdca_interrupt_callback(struct sdw_slave *slave,
+ struct sdw_slave_intr_status *status)
+{
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(&slave->dev);
+ int ret, stat;
+ int count = 0, retry = 3;
+ unsigned int sdca_cascade, scp_sdca_stat1, scp_sdca_stat2 = 0;
+
+ if (cancel_delayed_work_sync(&rt722->jack_detect_work)) {
+ dev_warn(&slave->dev, "%s the pending delayed_work was cancelled", __func__);
+ /* avoid the HID owner doesn't change to device */
+ if (rt722->scp_sdca_stat2)
+ scp_sdca_stat2 = rt722->scp_sdca_stat2;
+ }
+
+ /*
+ * The critical section below intentionally protects a rather large piece of code.
+ * We don't want to allow the system suspend to disable an interrupt while we are
+ * processing it, which could be problematic given the quirky SoundWire interrupt
+ * scheme. We do want however to prevent new workqueues from being scheduled if
+ * the disable_irq flag was set during system suspend.
+ */
+ mutex_lock(&rt722->disable_irq_lock);
+
+ ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+ rt722->scp_sdca_stat1 = ret;
+ ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+ rt722->scp_sdca_stat2 = ret;
+ if (scp_sdca_stat2)
+ rt722->scp_sdca_stat2 |= scp_sdca_stat2;
+ do {
+ /* clear flag */
+ ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+ if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) {
+ ret = sdw_update_no_pm(rt722->slave, SDW_SCP_SDCA_INT1,
+ SDW_SCP_SDCA_INT_SDCA_0, SDW_SCP_SDCA_INT_SDCA_0);
+ if (ret < 0)
+ goto io_error;
+ } else if (ret & SDW_SCP_SDCA_INTMASK_SDCA_6) {
+ ret = sdw_update_no_pm(rt722->slave, SDW_SCP_SDCA_INT1,
+ SDW_SCP_SDCA_INT_SDCA_6, SDW_SCP_SDCA_INT_SDCA_6);
+ if (ret < 0)
+ goto io_error;
+ }
+ ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+ if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) {
+ ret = sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INT2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ if (ret < 0)
+ goto io_error;
+ }
+
+ /* check if flag clear or not */
+ ret = sdw_read_no_pm(rt722->slave, SDW_DP0_INT);
+ if (ret < 0)
+ goto io_error;
+ sdca_cascade = ret & SDW_DP0_SDCA_CASCADE;
+
+ ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+ scp_sdca_stat1 = ret & SDW_SCP_SDCA_INTMASK_SDCA_0;
+
+ ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+ scp_sdca_stat2 = ret & SDW_SCP_SDCA_INTMASK_SDCA_8;
+
+ stat = scp_sdca_stat1 || scp_sdca_stat2 || sdca_cascade;
+
+ count++;
+ } while (stat != 0 && count < retry);
+
+ if (stat)
+ dev_warn(&slave->dev,
+ "%s scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__,
+ rt722->scp_sdca_stat1, rt722->scp_sdca_stat2);
+
+ if (status->sdca_cascade && !rt722->disable_irq)
+ mod_delayed_work(system_power_efficient_wq,
+ &rt722->jack_detect_work, msecs_to_jiffies(30));
+
+ mutex_unlock(&rt722->disable_irq_lock);
+
+ return 0;
+
+io_error:
+ mutex_unlock(&rt722->disable_irq_lock);
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+
+static struct sdw_slave_ops rt722_sdca_slave_ops = {
+ .read_prop = rt722_sdca_read_prop,
+ .interrupt_callback = rt722_sdca_interrupt_callback,
+ .update_status = rt722_sdca_update_status,
+};
+
+static int rt722_sdca_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap, *mbq_regmap;
+
+ /* Regmap Initialization */
+ mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt722_sdca_mbq_regmap);
+ if (IS_ERR(mbq_regmap))
+ return PTR_ERR(mbq_regmap);
+
+ regmap = devm_regmap_init_sdw(slave, &rt722_sdca_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt722_sdca_init(&slave->dev, regmap, mbq_regmap, slave);
+}
+
+static int rt722_sdca_sdw_remove(struct sdw_slave *slave)
+{
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(&slave->dev);
+
+ if (rt722->hw_init) {
+ cancel_delayed_work_sync(&rt722->jack_detect_work);
+ cancel_delayed_work_sync(&rt722->jack_btn_check_work);
+ }
+
+ if (rt722->first_hw_init)
+ pm_runtime_disable(&slave->dev);
+
+ mutex_destroy(&rt722->calibrate_mutex);
+ mutex_destroy(&rt722->disable_irq_lock);
+
+ return 0;
+}
+
+static const struct sdw_device_id rt722_sdca_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x722, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt722_sdca_id);
+
+static int __maybe_unused rt722_sdca_dev_suspend(struct device *dev)
+{
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
+
+ if (!rt722->hw_init)
+ return 0;
+
+ cancel_delayed_work_sync(&rt722->jack_detect_work);
+ cancel_delayed_work_sync(&rt722->jack_btn_check_work);
+
+ regcache_cache_only(rt722->regmap, true);
+ regcache_cache_only(rt722->mbq_regmap, true);
+
+ return 0;
+}
+
+static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev)
+{
+ struct rt722_sdca_priv *rt722_sdca = dev_get_drvdata(dev);
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ int ret1, ret2;
+
+ if (!rt722_sdca->hw_init)
+ return 0;
+
+ /*
+ * prevent new interrupts from being handled after the
+ * deferred work completes and before the parent disables
+ * interrupts on the link
+ */
+ mutex_lock(&rt722_sdca->disable_irq_lock);
+ rt722_sdca->disable_irq = true;
+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6, 0);
+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
+ mutex_unlock(&rt722_sdca->disable_irq_lock);
+
+ if (ret1 < 0 || ret2 < 0) {
+ /* log but don't prevent suspend from happening */
+ dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:", __func__);
+ }
+
+ return rt722_sdca_dev_suspend(dev);
+}
+
+#define RT722_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt722_sdca_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
+ unsigned long time;
+
+ if (!rt722->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT722_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt722->regmap, false);
+ regcache_sync(rt722->regmap);
+ regcache_cache_only(rt722->mbq_regmap, false);
+ regcache_sync(rt722->mbq_regmap);
+ return 0;
+}
+
+static const struct dev_pm_ops rt722_sdca_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt722_sdca_dev_system_suspend, rt722_sdca_dev_resume)
+ SET_RUNTIME_PM_OPS(rt722_sdca_dev_suspend, rt722_sdca_dev_resume, NULL)
+};
+
+static struct sdw_driver rt722_sdca_sdw_driver = {
+ .driver = {
+ .name = "rt722-sdca",
+ .owner = THIS_MODULE,
+ .pm = &rt722_sdca_pm,
+ },
+ .probe = rt722_sdca_sdw_probe,
+ .remove = rt722_sdca_sdw_remove,
+ .ops = &rt722_sdca_slave_ops,
+ .id_table = rt722_sdca_id,
+};
+module_sdw_driver(rt722_sdca_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT722 SDCA SDW driver");
+MODULE_AUTHOR("Jack Yu <jack.yu(a)realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt722-sdca-sdw.h b/sound/soc/codecs/rt722-sdca-sdw.h
new file mode 100644
index 000000000000..5b43e86f75d1
--- /dev/null
+++ b/sound/soc/codecs/rt722-sdca-sdw.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt722-sdca-sdw.h -- RT722 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2023 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT722_SDW_H__
+#define __RT722_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw_registers.h>
+
+static const struct reg_default rt722_sdca_reg_defaults[] = {
+ { 0x202d, 0x00 },
+ { 0x2f01, 0x00 },
+ { 0x2f02, 0x09 },
+ { 0x2f03, 0x00 },
+ { 0x2f04, 0x00 },
+ { 0x2f05, 0x0b },
+ { 0x2f06, 0x01 },
+ { 0x2f08, 0x00 },
+ { 0x2f09, 0x00 },
+ { 0x2f0a, 0x00 },
+ { 0x2f35, 0x00 },
+ { 0x2f36, 0x00 },
+ { 0x2f50, 0xf0 },
+ { 0x2f58, 0x07 },
+ { 0x2f59, 0x07 },
+ { 0x2f5a, 0x07 },
+ { 0x2f5b, 0x07 },
+ { 0x2f5c, 0x27 },
+ { 0x2f5d, 0x07 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
+ 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
+ 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, RT722_SDCA_CTL_REQ_POWER_STATE,
+ 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, RT722_SDCA_CTL_REQ_POWER_STATE,
+ 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_L),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_R),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_L),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_R),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
+ 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_01),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_02),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_03),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_04),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, RT722_SDCA_CTL_REQ_POWER_STATE, 0),
+ 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, RT722_SDCA_CTL_VENDOR_DEF, 0),
+ 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_L),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_R),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, RT722_SDCA_CTL_REQ_POWER_STATE, 0),
+ 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, RT722_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
+};
+
+static const struct reg_default rt722_sdca_mbq_defaults[] = {
+ { 0x200003c, 0xc214 },
+ { 0x2000046, 0x8004 },
+ { 0x6100006, 0x0005 },
+ { 0x6100010, 0x2630 },
+ { 0x6100011, 0x152f },
+ { 0x6100013, 0x0102 },
+ { 0x6100015, 0x2200 },
+ { 0x6100017, 0x0102 },
+ { 0x6100025, 0x2a29 },
+ { 0x6100026, 0x2a00 },
+ { 0x6100028, 0x2a2a },
+ { 0x6100029, 0x4141 },
+ { 0x6100055, 0x0000 },
+ { 0x5810000, 0x702d },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME,
+ CH_L), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME,
+ CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME,
+ CH_L), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME,
+ CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, RT722_SDCA_CTL_FU_CH_GAIN,
+ CH_L), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, RT722_SDCA_CTL_FU_CH_GAIN,
+ CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_03), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_04), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_01),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_02),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_03),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_04),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_L),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_R),
+ 0x0000 },
+};
+
+#endif /* __RT722_SDW_H__ */
diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c
new file mode 100644
index 000000000000..9c0d34366c9e
--- /dev/null
+++ b/sound/soc/codecs/rt722-sdca.c
@@ -0,0 +1,1555 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt722-sdca.c -- rt722 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2023 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/bitops.h>
+#include <sound/core.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <sound/initval.h>
+#include <sound/jack.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/pcm.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/slab.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "rt722-sdca.h"
+
+int rt722_sdca_index_write(struct rt722_sdca_priv *rt722,
+ unsigned int nid, unsigned int reg, unsigned int value)
+{
+ struct regmap *regmap = rt722->mbq_regmap;
+ unsigned int addr = (nid << 20) | reg;
+ int ret;
+
+ ret = regmap_write(regmap, addr, value);
+ if (ret < 0)
+ dev_err(&rt722->slave->dev,
+ "Failed to set private value: %06x <= %04x ret=%d\n",
+ addr, value, ret);
+
+ return ret;
+}
+
+int rt722_sdca_index_read(struct rt722_sdca_priv *rt722,
+ unsigned int nid, unsigned int reg, unsigned int *value)
+{
+ int ret;
+ struct regmap *regmap = rt722->mbq_regmap;
+ unsigned int addr = (nid << 20) | reg;
+
+ ret = regmap_read(regmap, addr, value);
+ if (ret < 0)
+ dev_err(&rt722->slave->dev,
+ "Failed to get private value: %06x => %04x ret=%d\n",
+ addr, *value, ret);
+
+ return ret;
+}
+
+static int rt722_sdca_index_update_bits(struct rt722_sdca_priv *rt722,
+ unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val)
+{
+ unsigned int tmp;
+ int ret;
+
+ ret = rt722_sdca_index_read(rt722, nid, reg, &tmp);
+ if (ret < 0)
+ return ret;
+
+ set_mask_bits(&tmp, mask, val);
+ return rt722_sdca_index_write(rt722, nid, reg, tmp);
+}
+
+static int rt722_sdca_btn_type(unsigned char *buffer)
+{
+ if ((*buffer & 0xf0) == 0x10 || (*buffer & 0x0f) == 0x01 || (*(buffer + 1) == 0x01) ||
+ (*(buffer + 1) == 0x10))
+ return SND_JACK_BTN_2;
+ else if ((*buffer & 0xf0) == 0x20 || (*buffer & 0x0f) == 0x02 || (*(buffer + 1) == 0x02) ||
+ (*(buffer + 1) == 0x20))
+ return SND_JACK_BTN_3;
+ else if ((*buffer & 0xf0) == 0x40 || (*buffer & 0x0f) == 0x04 || (*(buffer + 1) == 0x04) ||
+ (*(buffer + 1) == 0x40))
+ return SND_JACK_BTN_0;
+ else if ((*buffer & 0xf0) == 0x80 || (*buffer & 0x0f) == 0x08 || (*(buffer + 1) == 0x08) ||
+ (*(buffer + 1) == 0x80))
+ return SND_JACK_BTN_1;
+
+ return 0;
+}
+
+static unsigned int rt722_sdca_button_detect(struct rt722_sdca_priv *rt722)
+{
+ unsigned int btn_type = 0, offset, idx, val, owner;
+ int ret;
+ unsigned char buf[3];
+
+ /* get current UMP message owner */
+ ret = regmap_read(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), &owner);
+ if (ret < 0)
+ return 0;
+
+ /* if owner is device then there is no button event from device */
+ if (owner == 1)
+ return 0;
+
+ /* read UMP message offset */
+ ret = regmap_read(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset);
+ if (ret < 0)
+ goto _end_btn_det_;
+
+ for (idx = 0; idx < sizeof(buf); idx++) {
+ ret = regmap_read(rt722->regmap,
+ RT722_BUF_ADDR_HID1 + offset + idx, &val);
+ if (ret < 0)
+ goto _end_btn_det_;
+ buf[idx] = val & 0xff;
+ }
+
+ if (buf[0] == 0x11)
+ btn_type = rt722_sdca_btn_type(&buf[1]);
+
+_end_btn_det_:
+ /* Host is owner, so set back to device */
+ if (owner == 0)
+ /* set owner to device */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01);
+
+ return btn_type;
+}
+
+static int rt722_sdca_headset_detect(struct rt722_sdca_priv *rt722)
+{
+ unsigned int det_mode;
+ int ret;
+
+ /* get detected_mode */
+ ret = regmap_read(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49,
+ RT722_SDCA_CTL_DETECTED_MODE, 0), &det_mode);
+ if (ret < 0)
+ goto io_error;
+
+ switch (det_mode) {
+ case 0x00:
+ rt722->jack_type = 0;
+ break;
+ case 0x03:
+ rt722->jack_type = SND_JACK_HEADPHONE;
+ break;
+ case 0x05:
+ rt722->jack_type = SND_JACK_HEADSET;
+ break;
+ }
+
+ /* write selected_mode */
+ if (det_mode) {
+ ret = regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49,
+ RT722_SDCA_CTL_SELECTED_MODE, 0), det_mode);
+ if (ret < 0)
+ goto io_error;
+ }
+
+ dev_dbg(&rt722->slave->dev,
+ "%s, detected_mode=0x%x\n", __func__, det_mode);
+
+ return 0;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+
+static void rt722_sdca_jack_detect_handler(struct work_struct *work)
+{
+ struct rt722_sdca_priv *rt722 =
+ container_of(work, struct rt722_sdca_priv, jack_detect_work.work);
+ int btn_type = 0, ret;
+
+ if (!rt722->hs_jack)
+ return;
+
+ if (!rt722->component->card || !rt722->component->card->instantiated)
+ return;
+
+ /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */
+ if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6 ||
+ rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) {
+ ret = rt722_sdca_headset_detect(rt722);
+ if (ret < 0)
+ return;
+ }
+
+ /* SDW_SCP_SDCA_INT_SDCA_8 is used for button detection */
+ if (rt722->scp_sdca_stat2 & SDW_SCP_SDCA_INT_SDCA_8)
+ btn_type = rt722_sdca_button_detect(rt722);
+
+ if (rt722->jack_type == 0)
+ btn_type = 0;
+
+ dev_dbg(&rt722->slave->dev,
+ "in %s, jack_type=%d\n", __func__, rt722->jack_type);
+ dev_dbg(&rt722->slave->dev,
+ "in %s, btn_type=0x%x\n", __func__, btn_type);
+ dev_dbg(&rt722->slave->dev,
+ "in %s, scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__,
+ rt722->scp_sdca_stat1, rt722->scp_sdca_stat2);
+
+ snd_soc_jack_report(rt722->hs_jack, rt722->jack_type | btn_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ if (btn_type) {
+ /* button released */
+ snd_soc_jack_report(rt722->hs_jack, rt722->jack_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ mod_delayed_work(system_power_efficient_wq,
+ &rt722->jack_btn_check_work, msecs_to_jiffies(200));
+ }
+}
+
+static void rt722_sdca_btn_check_handler(struct work_struct *work)
+{
+ struct rt722_sdca_priv *rt722 =
+ container_of(work, struct rt722_sdca_priv, jack_btn_check_work.work);
+ int btn_type = 0, ret, idx;
+ unsigned int det_mode, offset, val;
+ unsigned char buf[3];
+
+ ret = regmap_read(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49,
+ RT722_SDCA_CTL_DETECTED_MODE, 0), &det_mode);
+ if (ret < 0)
+ goto io_error;
+
+ /* pin attached */
+ if (det_mode) {
+ /* read UMP message offset */
+ ret = regmap_read(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset);
+ if (ret < 0)
+ goto io_error;
+
+ for (idx = 0; idx < sizeof(buf); idx++) {
+ ret = regmap_read(rt722->regmap,
+ RT722_BUF_ADDR_HID1 + offset + idx, &val);
+ if (ret < 0)
+ goto io_error;
+ buf[idx] = val & 0xff;
+ }
+
+ if (buf[0] == 0x11)
+ btn_type = rt722_sdca_btn_type(&buf[1]);
+ } else
+ rt722->jack_type = 0;
+
+ dev_dbg(&rt722->slave->dev, "%s, btn_type=0x%x\n", __func__, btn_type);
+ snd_soc_jack_report(rt722->hs_jack, rt722->jack_type | btn_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ if (btn_type) {
+ /* button released */
+ snd_soc_jack_report(rt722->hs_jack, rt722->jack_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ mod_delayed_work(system_power_efficient_wq,
+ &rt722->jack_btn_check_work, msecs_to_jiffies(200));
+ }
+
+ return;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+}
+
+static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722)
+{
+ mutex_lock(&rt722->calibrate_mutex);
+ if (rt722->hs_jack) {
+ /* set SCP_SDCA_IntMask1[0]=1 */
+ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6);
+ /* set SCP_SDCA_IntMask2[0]=1 */
+ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ dev_dbg(&rt722->slave->dev, "in %s enable\n", __func__);
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_HDA_LEGACY_UNSOL_CTL, 0x016E);
+ /* set XU(et03h) & XU(et0Dh) to Not bypassed */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU03,
+ RT722_SDCA_CTL_SELECTED_MODE, 0), 0);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D,
+ RT722_SDCA_CTL_SELECTED_MODE, 0), 0);
+ /* trigger GE interrupt */
+ rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_GE_RELATED_CTL2, 0x4000, 0x4000);
+ }
+ mutex_unlock(&rt722->calibrate_mutex);
+}
+
+static int rt722_sdca_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+{
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ rt722->hs_jack = hs_jack;
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret < 0) {
+ if (ret != -EACCES) {
+ dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+ return ret;
+ }
+ /* pm_runtime not enabled yet */
+ dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
+ return 0;
+ }
+
+ rt722_sdca_jack_init(rt722);
+
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
+
+ return 0;
+}
+
+/* For SDCA control DAC/ADC Gain */
+static int rt722_sdca_set_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned int read_l, read_r, gain_l_val, gain_r_val;
+ unsigned int adc_vol_flag = 0, changed = 0;
+ unsigned int lvalue, rvalue;
+ const unsigned int interval_offset = 0xc0;
+ const unsigned int tendB = 0xa00;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume") ||
+ strstr(ucontrol->id.name, "FU0F Capture Volume"))
+ adc_vol_flag = 1;
+
+ regmap_read(rt722->mbq_regmap, mc->reg, &lvalue);
+ regmap_read(rt722->mbq_regmap, mc->rreg, &rvalue);
+
+ /* L Channel */
+ gain_l_val = ucontrol->value.integer.value[0];
+ if (gain_l_val > mc->max)
+ gain_l_val = mc->max;
+
+ if (mc->shift == 8) /* boost gain */
+ gain_l_val = gain_l_val * tendB;
+ else {
+ /* ADC/DAC gain */
+ if (adc_vol_flag)
+ gain_l_val = 0x1e00 - ((mc->max - gain_l_val) * interval_offset);
+ else
+ gain_l_val = 0 - ((mc->max - gain_l_val) * interval_offset);
+ gain_l_val &= 0xffff;
+ }
+
+ /* R Channel */
+ gain_r_val = ucontrol->value.integer.value[1];
+ if (gain_r_val > mc->max)
+ gain_r_val = mc->max;
+
+ if (mc->shift == 8) /* boost gain */
+ gain_r_val = gain_r_val * tendB;
+ else {
+ /* ADC/DAC gain */
+ if (adc_vol_flag)
+ gain_r_val = 0x1e00 - ((mc->max - gain_r_val) * interval_offset);
+ else
+ gain_r_val = 0 - ((mc->max - gain_r_val) * interval_offset);
+ gain_r_val &= 0xffff;
+ }
+
+ if (lvalue != gain_l_val || rvalue != gain_r_val)
+ changed = 1;
+ else
+ return 0;
+
+ /* Lch*/
+ regmap_write(rt722->mbq_regmap, mc->reg, gain_l_val);
+
+ /* Rch */
+ regmap_write(rt722->mbq_regmap, mc->rreg, gain_r_val);
+
+ regmap_read(rt722->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt722->mbq_regmap, mc->rreg, &read_r);
+ if (read_r == gain_r_val && read_l == gain_l_val)
+ return changed;
+
+ return -EIO;
+}
+
+static int rt722_sdca_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0;
+ unsigned int adc_vol_flag = 0;
+ const unsigned int interval_offset = 0xc0;
+ const unsigned int tendB = 0xa00;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume") ||
+ strstr(ucontrol->id.name, "FU0F Capture Volume"))
+ adc_vol_flag = 1;
+
+ regmap_read(rt722->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt722->mbq_regmap, mc->rreg, &read_r);
+
+ if (mc->shift == 8) /* boost gain */
+ ctl_l = read_l / tendB;
+ else {
+ if (adc_vol_flag)
+ ctl_l = mc->max - (((0x1e00 - read_l) & 0xffff) / interval_offset);
+ else
+ ctl_l = mc->max - (((0 - read_l) & 0xffff) / interval_offset);
+ }
+
+ if (read_l != read_r) {
+ if (mc->shift == 8) /* boost gain */
+ ctl_r = read_r / tendB;
+ else { /* ADC/DAC gain */
+ if (adc_vol_flag)
+ ctl_r = mc->max - (((0x1e00 - read_r) & 0xffff) / interval_offset);
+ else
+ ctl_r = mc->max - (((0 - read_r) & 0xffff) / interval_offset);
+ }
+ } else {
+ ctl_r = ctl_l;
+ }
+
+ ucontrol->value.integer.value[0] = ctl_l;
+ ucontrol->value.integer.value[1] = ctl_r;
+
+ return 0;
+}
+
+static int rt722_sdca_set_fu1e_capture_ctl(struct rt722_sdca_priv *rt722)
+{
+ int err, i;
+ unsigned int ch_mute;
+
+ for (i = 0; i < ARRAY_SIZE(rt722->fu1e_mixer_mute); i++) {
+ ch_mute = rt722->fu1e_dapm_mute || rt722->fu1e_mixer_mute[i];
+ err = regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
+ RT722_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int rt722_sdca_fu1e_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ struct rt722_sdca_dmic_kctrl_priv *p =
+ (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++)
+ ucontrol->value.integer.value[i] = !rt722->fu1e_mixer_mute[i];
+
+ return 0;
+}
+
+static int rt722_sdca_fu1e_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ struct rt722_sdca_dmic_kctrl_priv *p =
+ (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ int err, changed = 0, i;
+
+ for (i = 0; i < p->count; i++) {
+ if (rt722->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i])
+ changed = 1;
+ rt722->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i];
+ }
+
+ err = rt722_sdca_set_fu1e_capture_ctl(rt722);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt722_sdca_set_fu0f_capture_ctl(struct rt722_sdca_priv *rt722)
+{
+ int err;
+ unsigned int ch_l, ch_r;
+
+ ch_l = (rt722->fu0f_dapm_mute || rt722->fu0f_mixer_l_mute) ? 0x01 : 0x00;
+ ch_r = (rt722->fu0f_dapm_mute || rt722->fu0f_mixer_r_mute) ? 0x01 : 0x00;
+
+ err = regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_MUTE, CH_L), ch_l);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_MUTE, CH_R), ch_r);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int rt722_sdca_fu0f_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt722->fu0f_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt722->fu0f_mixer_r_mute;
+ return 0;
+}
+
+static int rt722_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ int err, changed = 0;
+
+ if (rt722->fu0f_mixer_l_mute != !ucontrol->value.integer.value[0] ||
+ rt722->fu0f_mixer_r_mute != !ucontrol->value.integer.value[1])
+ changed = 1;
+
+ rt722->fu0f_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt722->fu0f_mixer_r_mute = !ucontrol->value.integer.value[1];
+ err = rt722_sdca_set_fu0f_capture_ctl(rt722);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt722_sdca_fu_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct rt722_sdca_dmic_kctrl_priv *p =
+ (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+
+ if (p->max == 1)
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = p->count;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = p->max;
+ return 0;
+}
+
+static int rt722_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ struct rt722_sdca_dmic_kctrl_priv *p =
+ (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int boost_step = 0x0a00;
+ unsigned int vol_max = 0x1e00;
+ unsigned int regvalue, ctl, i;
+ unsigned int adc_vol_flag = 0;
+ const unsigned int interval_offset = 0xc0;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+ adc_vol_flag = 1;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt722->mbq_regmap, p->reg_base + i, ®value);
+
+ if (!adc_vol_flag) /* boost gain */
+ ctl = regvalue / boost_step;
+ else { /* ADC gain */
+ if (adc_vol_flag)
+ ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset);
+ else
+ ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset);
+ }
+
+ ucontrol->value.integer.value[i] = ctl;
+ }
+
+ return 0;
+}
+
+static int rt722_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_dmic_kctrl_priv *p =
+ (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned int boost_step = 0x0a00;
+ unsigned int vol_max = 0x1e00;
+ unsigned int gain_val[4];
+ unsigned int i, adc_vol_flag = 0, changed = 0;
+ unsigned int regvalue[4];
+ const unsigned int interval_offset = 0xc0;
+ int err;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+ adc_vol_flag = 1;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt722->mbq_regmap, p->reg_base + i, ®value[i]);
+
+ gain_val[i] = ucontrol->value.integer.value[i];
+ if (gain_val[i] > p->max)
+ gain_val[i] = p->max;
+
+ if (!adc_vol_flag) /* boost gain */
+ gain_val[i] = gain_val[i] * boost_step;
+ else { /* ADC gain */
+ gain_val[i] = vol_max - ((p->max - gain_val[i]) * interval_offset);
+ gain_val[i] &= 0xffff;
+ }
+
+ if (regvalue[i] != gain_val[i])
+ changed = 1;
+ }
+
+ if (!changed)
+ return 0;
+
+ for (i = 0; i < p->count; i++) {
+ err = regmap_write(rt722->mbq_regmap, p->reg_base + i, gain_val[i]);
+ if (err < 0)
+ dev_err(&rt722->slave->dev, "%#08x can't be set\n", p->reg_base + i);
+ }
+
+ return changed;
+}
+
+#define RT722_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \
+ ((unsigned long)&(struct rt722_sdca_dmic_kctrl_priv) \
+ {.reg_base = xreg_base, .count = xcount, .max = xmax, \
+ .invert = xinvert})
+
+#define RT722_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = rt722_sdca_fu_info, \
+ .get = rt722_sdca_fu1e_capture_get, \
+ .put = rt722_sdca_fu1e_capture_put, \
+ .private_value = RT722_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)}
+
+#define RT722_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\
+ xhandler_put, xcount, xmax, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = rt722_sdca_fu_info, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = RT722_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) }
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt722_sdca_controls[] = {
+ /* Headphone playback settings */
+ SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0,
+ rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, out_vol_tlv),
+ /* Headset mic capture settings */
+ SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt722_sdca_fu0f_capture_get, rt722_sdca_fu0f_capture_put),
+ SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x3f, 0,
+ rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, mic_vol_tlv),
+ SOC_DOUBLE_R_EXT_TLV("FU33 Boost Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44,
+ RT722_SDCA_CTL_FU_CH_GAIN, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44,
+ RT722_SDCA_CTL_FU_CH_GAIN, CH_R), 8, 3, 0,
+ rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, boost_vol_tlv),
+ /* AMP playback settings */
+ SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0,
+ rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, out_vol_tlv),
+ /* DMIC capture settings */
+ RT722_SDCA_FU_CTRL("FU1E Capture Switch",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
+ RT722_SDCA_CTL_FU_MUTE, CH_01), 1, 1, 4),
+ RT722_SDCA_EXT_TLV("FU1E Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
+ RT722_SDCA_CTL_FU_VOLUME, CH_01),
+ rt722_sdca_dmic_set_gain_get, rt722_sdca_dmic_set_gain_put,
+ 4, 0x3f, mic_vol_tlv),
+ RT722_SDCA_EXT_TLV("FU15 Boost Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15,
+ RT722_SDCA_CTL_FU_CH_GAIN, CH_01),
+ rt722_sdca_dmic_set_gain_get, rt722_sdca_dmic_set_gain_put,
+ 4, 3, boost_vol_tlv),
+};
+
+static int rt722_sdca_adc_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_kcontrol_component(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned int val = 0, mask_sft;
+
+ if (strstr(ucontrol->id.name, "ADC 22 Mux"))
+ mask_sft = 12;
+ else if (strstr(ucontrol->id.name, "ADC 24 Mux"))
+ mask_sft = 4;
+ else if (strstr(ucontrol->id.name, "ADC 25 Mux"))
+ mask_sft = 0;
+ else
+ return -EINVAL;
+
+ rt722_sdca_index_read(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_HDA_LEGACY_MUX_CTL0, &val);
+
+ ucontrol->value.enumerated.item[0] = (val >> mask_sft) & 0x7;
+
+ return 0;
+}
+
+static int rt722_sdca_adc_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ unsigned int val, val2 = 0, change, mask_sft;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+
+ if (strstr(ucontrol->id.name, "ADC 22 Mux"))
+ mask_sft = 12;
+ else if (strstr(ucontrol->id.name, "ADC 24 Mux"))
+ mask_sft = 4;
+ else if (strstr(ucontrol->id.name, "ADC 25 Mux"))
+ mask_sft = 0;
+ else
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+ rt722_sdca_index_read(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_HDA_LEGACY_MUX_CTL0, &val2);
+ val2 = (0x7 << mask_sft) & val2;
+
+ if (val == val2)
+ change = 0;
+ else
+ change = 1;
+
+ if (change)
+ rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_HDA_LEGACY_MUX_CTL0, 0x7 << mask_sft,
+ val << mask_sft);
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol,
+ item[0], e, NULL);
+
+ return change;
+}
+
+static const char * const adc22_mux_text[] = {
+ "MIC2",
+ "LINE1",
+ "LINE2",
+};
+
+static const char * const adc07_10_mux_text[] = {
+ "DMIC1",
+ "DMIC2",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt722_adc22_enum, SND_SOC_NOPM, 0, adc22_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt722_adc24_enum, SND_SOC_NOPM, 0, adc07_10_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt722_adc25_enum, SND_SOC_NOPM, 0, adc07_10_mux_text);
+
+static const struct snd_kcontrol_new rt722_sdca_adc22_mux =
+ SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt722_adc22_enum,
+ rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put);
+
+static const struct snd_kcontrol_new rt722_sdca_adc24_mux =
+ SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt722_adc24_enum,
+ rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put);
+
+static const struct snd_kcontrol_new rt722_sdca_adc25_mux =
+ SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt722_adc25_enum,
+ rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put);
+
+static int rt722_sdca_fu42_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char unmute = 0x0, mute = 0x1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_L), unmute);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_R), unmute);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_L), mute);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_R), mute);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_fu21_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char unmute = 0x0, mute = 0x1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_L), unmute);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_R), unmute);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_L), mute);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_R), mute);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_fu113_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt722->fu1e_dapm_mute = false;
+ rt722_sdca_set_fu1e_capture_ctl(rt722);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt722->fu1e_dapm_mute = true;
+ rt722_sdca_set_fu1e_capture_ctl(rt722);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_fu36_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt722->fu0f_dapm_mute = false;
+ rt722_sdca_set_fu0f_capture_ctl(rt722);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt722->fu0f_dapm_mute = true;
+ rt722_sdca_set_fu0f_capture_ctl(rt722);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_pde47_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_pde23_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_pde11_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_pde12_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt722_sdca_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("HP"),
+ SND_SOC_DAPM_OUTPUT("SPK"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("LINE1"),
+ SND_SOC_DAPM_INPUT("LINE2"),
+ SND_SOC_DAPM_INPUT("DMIC1_2"),
+ SND_SOC_DAPM_INPUT("DMIC3_4"),
+
+ SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
+ rt722_sdca_pde23_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 47", SND_SOC_NOPM, 0, 0,
+ rt722_sdca_pde47_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+ rt722_sdca_pde11_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 12", SND_SOC_NOPM, 0, 0,
+ rt722_sdca_pde12_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_DAC_E("FU 21", NULL, SND_SOC_NOPM, 0, 0,
+ rt722_sdca_fu21_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("FU 42", NULL, SND_SOC_NOPM, 0, 0,
+ rt722_sdca_fu42_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 36", NULL, SND_SOC_NOPM, 0, 0,
+ rt722_sdca_fu36_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 113", NULL, SND_SOC_NOPM, 0, 0,
+ rt722_sdca_fu113_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0,
+ &rt722_sdca_adc22_mux),
+ SND_SOC_DAPM_MUX("ADC 24 Mux", SND_SOC_NOPM, 0, 0,
+ &rt722_sdca_adc24_mux),
+ SND_SOC_DAPM_MUX("ADC 25 Mux", SND_SOC_NOPM, 0, 0,
+ &rt722_sdca_adc25_mux),
+
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Headphone Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Headset Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Speaker Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 DMic Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt722_sdca_audio_map[] = {
+ {"FU 42", NULL, "DP1RX"},
+ {"FU 21", NULL, "DP3RX"},
+
+ {"ADC 22 Mux", "MIC2", "MIC2"},
+ {"ADC 22 Mux", "LINE1", "LINE1"},
+ {"ADC 22 Mux", "LINE2", "LINE2"},
+ {"ADC 24 Mux", "DMIC1", "DMIC1_2"},
+ {"ADC 24 Mux", "DMIC2", "DMIC3_4"},
+ {"ADC 25 Mux", "DMIC1", "DMIC1_2"},
+ {"ADC 25 Mux", "DMIC2", "DMIC3_4"},
+ {"FU 36", NULL, "PDE 12"},
+ {"FU 36", NULL, "ADC 22 Mux"},
+ {"FU 113", NULL, "PDE 11"},
+ {"FU 113", NULL, "ADC 24 Mux"},
+ {"FU 113", NULL, "ADC 25 Mux"},
+ {"DP2TX", NULL, "FU 36"},
+ {"DP6TX", NULL, "FU 113"},
+
+ {"HP", NULL, "PDE 47"},
+ {"HP", NULL, "FU 42"},
+ {"SPK", NULL, "PDE 23"},
+ {"SPK", NULL, "FU 21"},
+};
+
+static int rt722_sdca_parse_dt(struct rt722_sdca_priv *rt722, struct device *dev)
+{
+ device_property_read_u32(dev, "realtek,jd-src", &rt722->jd_src);
+
+ return 0;
+}
+
+static int rt722_sdca_probe(struct snd_soc_component *component)
+{
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ rt722_sdca_parse_dt(rt722, &rt722->slave->dev);
+ rt722->component = component;
+
+ ret = pm_runtime_resume(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_sdca_dev_rt722 = {
+ .probe = rt722_sdca_probe,
+ .controls = rt722_sdca_controls,
+ .num_controls = ARRAY_SIZE(rt722_sdca_controls),
+ .dapm_widgets = rt722_sdca_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt722_sdca_dapm_widgets),
+ .dapm_routes = rt722_sdca_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt722_sdca_audio_map),
+ .set_jack = rt722_sdca_set_jack_detect,
+ .endianness = 1,
+};
+
+static int rt722_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+
+ return 0;
+}
+
+static void rt722_sdca_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ enum sdw_data_direction direction;
+ struct sdw_stream_runtime *sdw_stream;
+ int retval, port, num_channels;
+ unsigned int sampling_rate;
+
+ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ if (!rt722->slave)
+ return -EINVAL;
+
+ /*
+ * RT722_AIF1 with port = 1 for headphone playback
+ * RT722_AIF1 with port = 2 for headset-mic capture
+ * RT722_AIF2 with port = 3 for speaker playback
+ * RT722_AIF3 with port = 6 for digital-mic capture
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ if (dai->id == RT722_AIF1)
+ port = 1;
+ else if (dai->id == RT722_AIF2)
+ port = 3;
+ else
+ return -EINVAL;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ if (dai->id == RT722_AIF1)
+ port = 2;
+ else if (dai->id == RT722_AIF3)
+ port = 6;
+ else
+ return -EINVAL;
+ }
+ stream_config.frame_rate = params_rate(params);
+ stream_config.ch_count = params_channels(params);
+ stream_config.bps = snd_pcm_format_width(params_format(params));
+ stream_config.direction = direction;
+
+ num_channels = params_channels(params);
+ port_config.ch_mask = GENMASK(num_channels - 1, 0);
+ port_config.num = port;
+
+ retval = sdw_stream_add_slave(rt722->slave, &stream_config,
+ &port_config, 1, sdw_stream);
+ if (retval) {
+ dev_err(dai->dev, "Unable to configure port\n");
+ return retval;
+ }
+
+ if (params_channels(params) > 16) {
+ dev_err(component->dev, "Unsupported channels %d\n",
+ params_channels(params));
+ return -EINVAL;
+ }
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 44100:
+ sampling_rate = RT722_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT722_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT722_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT722_SDCA_RATE_192000HZ;
+ break;
+ default:
+ dev_err(component->dev, "Rate %d is not supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ if (dai->id == RT722_AIF1) {
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+ }
+
+ if (dai->id == RT722_AIF2)
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+
+ if (dai->id == RT722_AIF3)
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+
+ return 0;
+}
+
+static int rt722_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_runtime *sdw_stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt722->slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt722->slave, sdw_stream);
+ return 0;
+}
+
+#define RT722_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT722_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops rt722_sdca_ops = {
+ .hw_params = rt722_sdca_pcm_hw_params,
+ .hw_free = rt722_sdca_pcm_hw_free,
+ .set_stream = rt722_sdca_set_sdw_stream,
+ .shutdown = rt722_sdca_shutdown,
+};
+
+static struct snd_soc_dai_driver rt722_sdca_dai[] = {
+ {
+ .name = "rt722-sdca-aif1",
+ .id = RT722_AIF1,
+ .playback = {
+ .stream_name = "DP1 Headphone Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT722_STEREO_RATES,
+ .formats = RT722_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP2 Headset Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT722_STEREO_RATES,
+ .formats = RT722_FORMATS,
+ },
+ .ops = &rt722_sdca_ops,
+ },
+ {
+ .name = "rt722-sdca-aif2",
+ .id = RT722_AIF2,
+ .playback = {
+ .stream_name = "DP3 Speaker Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT722_STEREO_RATES,
+ .formats = RT722_FORMATS,
+ },
+ .ops = &rt722_sdca_ops,
+ },
+ {
+ .name = "rt722-sdca-aif3",
+ .id = RT722_AIF3,
+ .capture = {
+ .stream_name = "DP6 DMic Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT722_STEREO_RATES,
+ .formats = RT722_FORMATS,
+ },
+ .ops = &rt722_sdca_ops,
+ }
+};
+
+int rt722_sdca_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave)
+{
+ struct rt722_sdca_priv *rt722;
+
+ rt722 = devm_kzalloc(dev, sizeof(*rt722), GFP_KERNEL);
+ if (!rt722)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt722);
+ rt722->slave = slave;
+ rt722->regmap = regmap;
+ rt722->mbq_regmap = mbq_regmap;
+
+ mutex_init(&rt722->calibrate_mutex);
+ mutex_init(&rt722->disable_irq_lock);
+
+ INIT_DELAYED_WORK(&rt722->jack_detect_work, rt722_sdca_jack_detect_handler);
+ INIT_DELAYED_WORK(&rt722->jack_btn_check_work, rt722_sdca_btn_check_handler);
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt722->hw_init = false;
+ rt722->first_hw_init = false;
+ rt722->fu1e_dapm_mute = true;
+ rt722->fu0f_dapm_mute = true;
+ rt722->fu0f_mixer_l_mute = rt722->fu0f_mixer_r_mute = true;
+ rt722->fu1e_mixer_mute[0] = rt722->fu1e_mixer_mute[1] =
+ rt722->fu1e_mixer_mute[2] = rt722->fu1e_mixer_mute[3] = true;
+
+ return devm_snd_soc_register_component(dev,
+ &soc_sdca_dev_rt722, rt722_sdca_dai, ARRAY_SIZE(rt722_sdca_dai));
+}
+
+static void rt722_sdca_dmic_preset(struct rt722_sdca_priv *rt722)
+{
+ /* Set AD07 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC0A_08_PDE_FLOAT_CTL, 0x2a29);
+ /* Set AD10 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC10_PDE_FLOAT_CTL, 0x2a00);
+ /* Set DMIC1/DMIC2 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC1_2_PDE_FLOAT_CTL, 0x2a2a);
+ /* Set DMIC2 IT entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC_ENT_FLOAT_CTL, 0x2626);
+ /* Set AD10 FU entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC_ENT_FLOAT_CTL, 0x1e00);
+ /* Set DMIC2 FU entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC_GAIN_ENT_FLOAT_CTL0, 0x1515);
+ /* Set AD10 FU channel floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC_VOL_CH_FLOAT_CTL, 0x0304);
+ /* Set DMIC2 FU channel floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC_GAIN_ENT_FLOAT_CTL2, 0x0304);
+ /* vf71f_r12_07_06 and vf71f_r13_07_06 = 2’b00 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_HDA_LEGACY_CONFIG_CTL0, 0x0000);
+ /* Enable vf707_r12_05/vf707_r13_05 */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26,
+ RT722_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+ /* Fine tune PDE2A latency */
+ regmap_write(rt722->regmap, 0x2f5c, 0x25);
+}
+
+static void rt722_sdca_amp_preset(struct rt722_sdca_priv *rt722)
+{
+ /* Set DVQ=01 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL6,
+ 0xc215);
+ /* Reset dc_cal_top */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DC_CALIB_CTRL,
+ 0x702c);
+ /* W1C Trigger Calibration */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DC_CALIB_CTRL,
+ 0xf02d);
+ /* Set DAC02/ClassD power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_AMP_PDE_FLOAT_CTL,
+ 0x2323);
+ /* Set EAPD high */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_EAPD_CTL,
+ 0x0002);
+ /* Enable vf707_r14 */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23,
+ RT722_SDCA_CTL_VENDOR_DEF, CH_08), 0x04);
+}
+
+static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722)
+{
+ int loop_check, chk_cnt = 100, ret;
+ unsigned int calib_status = 0;
+
+ /* Read eFuse */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_SPK_EFUSE, RT722_DC_CALIB_CTRL,
+ 0x4808);
+ /* Button A, B, C, D bypass mode */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL4,
+ 0xcf00);
+ /* HID1 slot enable */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL5,
+ 0x000f);
+ /* Report ID for HID1 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL0,
+ 0x1100);
+ /* OSC/OOC for slot 2, 3 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL7,
+ 0x0c12);
+ /* Set JD de-bounce clock control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_JD_CTRL1,
+ 0x7002);
+ /* Set DVQ=01 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL6,
+ 0xc215);
+ /* FSM switch to calibration manual mode */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_FSM_CTL,
+ 0x4100);
+ /* W1C Trigger DC calibration (HP) */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DAC_DC_CALI_CTL3,
+ 0x008d);
+ /* check HP calibration FSM status */
+ for (loop_check = 0; loop_check < chk_cnt; loop_check++) {
+ ret = rt722_sdca_index_read(rt722, RT722_VENDOR_CALI,
+ RT722_DAC_DC_CALI_CTL3, &calib_status);
+ if (ret < 0 || loop_check == chk_cnt)
+ dev_dbg(&rt722->slave->dev, "calibration failed!, ret=%d\n", ret);
+ if ((calib_status & 0x0040) == 0x0)
+ break;
+ }
+ /* Release HP-JD, EN_CBJ_TIE_GL/R open, en_osw gating auto done bit */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4,
+ 0x0010);
+ /* Set ADC09 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ADC0A_08_PDE_FLOAT_CTL,
+ 0x2a12);
+ /* Set MIC2 and LINE1 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_MIC2_LINE2_PDE_FLOAT_CTL,
+ 0x3429);
+ /* Set ET41h and LINE2 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ET41_LINE2_PDE_FLOAT_CTL,
+ 0x4112);
+ /* Set DAC03 and HP power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_DAC03_HP_PDE_FLOAT_CTL,
+ 0x4040);
+ /* Fine tune PDE40 latency */
+ regmap_write(rt722->regmap, 0x2f58, 0x07);
+}
+
+int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
+
+ rt722->disable_irq = false;
+
+ if (rt722->hw_init)
+ return 0;
+
+ if (rt722->first_hw_init) {
+ regcache_cache_only(rt722->regmap, false);
+ regcache_cache_bypass(rt722->regmap, true);
+ regcache_cache_only(rt722->mbq_regmap, false);
+ regcache_cache_bypass(rt722->mbq_regmap, true);
+ } else {
+ /*
+ * PM runtime is only enabled when a Slave reports as Attached
+ */
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+ pm_runtime_use_autosuspend(&slave->dev);
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(&slave->dev);
+
+ pm_runtime_enable(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ rt722_sdca_dmic_preset(rt722);
+ rt722_sdca_amp_preset(rt722);
+ rt722_sdca_jack_preset(rt722);
+
+ if (rt722->first_hw_init) {
+ regcache_cache_bypass(rt722->regmap, false);
+ regcache_mark_dirty(rt722->regmap);
+ regcache_cache_bypass(rt722->mbq_regmap, false);
+ regcache_mark_dirty(rt722->mbq_regmap);
+ } else
+ rt722->first_hw_init = true;
+
+ /* Mark Slave initialization complete */
+ rt722->hw_init = true;
+
+ pm_runtime_mark_last_busy(&slave->dev);
+ pm_runtime_put_autosuspend(&slave->dev);
+
+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+ return 0;
+}
+
+MODULE_DESCRIPTION("ASoC RT722 SDCA SDW driver");
+MODULE_AUTHOR("Jack Yu <jack.yu(a)realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt722-sdca.h b/sound/soc/codecs/rt722-sdca.h
new file mode 100644
index 000000000000..5bc6184d09aa
--- /dev/null
+++ b/sound/soc/codecs/rt722-sdca.h
@@ -0,0 +1,238 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt722-sdca.h -- RT722 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2023 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT722_H__
+#define __RT722_H__
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc.h>
+#include <linux/workqueue.h>
+
+struct rt722_sdca_priv {
+ struct regmap *regmap;
+ struct regmap *mbq_regmap;
+ struct snd_soc_component *component;
+ struct sdw_slave *slave;
+ enum sdw_slave_status status;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_hw_init;
+ struct mutex calibrate_mutex;
+ struct mutex disable_irq_lock;
+ bool disable_irq;
+ /* For Headset jack & Headphone */
+ unsigned int scp_sdca_stat1;
+ unsigned int scp_sdca_stat2;
+ struct snd_soc_jack *hs_jack;
+ struct delayed_work jack_detect_work;
+ struct delayed_work jack_btn_check_work;
+ int jack_type;
+ int jd_src;
+ bool fu0f_dapm_mute;
+ bool fu0f_mixer_l_mute;
+ bool fu0f_mixer_r_mute;
+ /* For DMIC */
+ bool fu1e_dapm_mute;
+ bool fu1e_mixer_mute[4];
+};
+
+struct rt722_sdca_dmic_kctrl_priv {
+ unsigned int reg_base;
+ unsigned int count;
+ unsigned int max;
+ unsigned int invert;
+};
+
+/* NID */
+#define RT722_VENDOR_REG 0x20
+#define RT722_VENDOR_CALI 0x58
+#define RT722_VENDOR_SPK_EFUSE 0x5c
+#define RT722_VENDOR_IMS_DRE 0x5b
+#define RT722_VENDOR_ANALOG_CTL 0x5f
+#define RT722_VENDOR_HDA_CTL 0x61
+
+/* Index (NID:20h) */
+#define RT722_JD_PRODUCT_NUM 0x00
+#define RT722_ANALOG_BIAS_CTL3 0x04
+#define RT722_JD_CTRL1 0x09
+#define RT722_LDO2_3_CTL1 0x0e
+#define RT722_LDO1_CTL 0x1a
+#define RT722_HP_JD_CTRL 0x24
+#define RT722_CLSD_CTRL6 0x3c
+#define RT722_COMBO_JACK_AUTO_CTL1 0x45
+#define RT722_COMBO_JACK_AUTO_CTL2 0x46
+#define RT722_COMBO_JACK_AUTO_CTL3 0x47
+#define RT722_DIGITAL_MISC_CTRL4 0x4a
+#define RT722_FSM_CTL 0x67
+#define RT722_SDCA_INTR_REC 0x82
+#define RT722_SW_CONFIG1 0x8a
+#define RT722_SW_CONFIG2 0x8b
+
+/* Index (NID:58h) */
+#define RT722_DAC_DC_CALI_CTL0 0x00
+#define RT722_DAC_DC_CALI_CTL1 0x01
+#define RT722_DAC_DC_CALI_CTL2 0x02
+#define RT722_DAC_DC_CALI_CTL3 0x03
+
+/* Index (NID:59h) */
+#define RT722_ULTRA_SOUND_DETECTOR6 0x1e
+
+/* Index (NID:5bh) */
+#define RT722_IMS_DIGITAL_CTL1 0x00
+#define RT722_IMS_DIGITAL_CTL5 0x05
+#define RT722_HP_DETECT_RLDET_CTL1 0x29
+#define RT722_HP_DETECT_RLDET_CTL2 0x2a
+
+/* Index (NID:5fh) */
+#define RT722_MISC_POWER_CTL0 0x00
+#define RT722_MISC_POWER_CTL7 0x08
+
+/* Index (NID:61h) */
+#define RT722_HDA_LEGACY_MUX_CTL0 0x00
+#define RT722_HDA_LEGACY_UNSOL_CTL 0x03
+#define RT722_HDA_LEGACY_CONFIG_CTL0 0x06
+#define RT722_HDA_LEGACY_RESET_CTL 0x08
+#define RT722_HDA_LEGACY_GPIO_WAKE_EN_CTL 0x0e
+#define RT722_DMIC_ENT_FLOAT_CTL 0x10
+#define RT722_DMIC_GAIN_ENT_FLOAT_CTL0 0x11
+#define RT722_DMIC_GAIN_ENT_FLOAT_CTL2 0x13
+#define RT722_ADC_ENT_FLOAT_CTL 0x15
+#define RT722_ADC_VOL_CH_FLOAT_CTL 0x17
+#define RT722_ADC_SAMPLE_RATE_FLOAT 0x18
+#define RT722_DAC03_HP_PDE_FLOAT_CTL 0x22
+#define RT722_MIC2_LINE2_PDE_FLOAT_CTL 0x23
+#define RT722_ET41_LINE2_PDE_FLOAT_CTL 0x24
+#define RT722_ADC0A_08_PDE_FLOAT_CTL 0x25
+#define RT722_ADC10_PDE_FLOAT_CTL 0x26
+#define RT722_DMIC1_2_PDE_FLOAT_CTL 0x28
+#define RT722_AMP_PDE_FLOAT_CTL 0x29
+#define RT722_I2S_IN_OUT_PDE_FLOAT_CTL 0x2f
+#define RT722_GE_RELATED_CTL1 0x45
+#define RT722_GE_RELATED_CTL2 0x46
+#define RT722_MIXER_CTL0 0x52
+#define RT722_MIXER_CTL1 0x53
+#define RT722_EAPD_CTL 0x55
+#define RT722_UMP_HID_CTL0 0x60
+#define RT722_UMP_HID_CTL1 0x61
+#define RT722_UMP_HID_CTL2 0x62
+#define RT722_UMP_HID_CTL3 0x63
+#define RT722_UMP_HID_CTL4 0x64
+#define RT722_UMP_HID_CTL5 0x65
+#define RT722_UMP_HID_CTL6 0x66
+#define RT722_UMP_HID_CTL7 0x67
+#define RT722_UMP_HID_CTL8 0x68
+
+/* Parameter & Verb control 01 (0x1a)(NID:20h) */
+#define RT722_HIDDEN_REG_SW_RESET (0x1 << 14)
+
+/* combo jack auto switch control 2 (0x46)(NID:20h) */
+#define RT722_COMBOJACK_AUTO_DET_STATUS (0x1 << 11)
+#define RT722_COMBOJACK_AUTO_DET_TRS (0x1 << 10)
+#define RT722_COMBOJACK_AUTO_DET_CTIA (0x1 << 9)
+#define RT722_COMBOJACK_AUTO_DET_OMTP (0x1 << 8)
+
+/* DAC calibration control (0x00)(NID:58h) */
+#define RT722_DC_CALIB_CTRL (0x1 << 16)
+/* DAC DC offset calibration control-1 (0x01)(NID:58h) */
+#define RT722_PDM_DC_CALIB_STATUS (0x1 << 15)
+
+#define RT722_EAPD_HIGH 0x2
+#define RT722_EAPD_LOW 0x0
+
+/* Buffer address for HID */
+#define RT722_BUF_ADDR_HID1 0x44030000
+#define RT722_BUF_ADDR_HID2 0x44030020
+
+/* RT722 SDCA Control - function number */
+#define FUNC_NUM_JACK_CODEC 0x01
+#define FUNC_NUM_MIC_ARRAY 0x02
+#define FUNC_NUM_HID 0x03
+#define FUNC_NUM_AMP 0x04
+
+/* RT722 SDCA entity */
+#define RT722_SDCA_ENT_HID01 0x01
+#define RT722_SDCA_ENT_GE49 0x49
+#define RT722_SDCA_ENT_USER_FU05 0x05
+#define RT722_SDCA_ENT_USER_FU06 0x06
+#define RT722_SDCA_ENT_USER_FU0F 0x0f
+#define RT722_SDCA_ENT_USER_FU10 0x19
+#define RT722_SDCA_ENT_USER_FU1E 0x1e
+#define RT722_SDCA_ENT_FU15 0x15
+#define RT722_SDCA_ENT_PDE23 0x23
+#define RT722_SDCA_ENT_PDE40 0x40
+#define RT722_SDCA_ENT_PDE11 0x11
+#define RT722_SDCA_ENT_PDE12 0x12
+#define RT722_SDCA_ENT_PDE2A 0x2a
+#define RT722_SDCA_ENT_CS01 0x01
+#define RT722_SDCA_ENT_CS11 0x11
+#define RT722_SDCA_ENT_CS1F 0x1f
+#define RT722_SDCA_ENT_CS1C 0x1c
+#define RT722_SDCA_ENT_CS31 0x31
+#define RT722_SDCA_ENT_OT23 0x42
+#define RT722_SDCA_ENT_IT26 0x26
+#define RT722_SDCA_ENT_IT09 0x09
+#define RT722_SDCA_ENT_PLATFORM_FU15 0x15
+#define RT722_SDCA_ENT_PLATFORM_FU44 0x44
+#define RT722_SDCA_ENT_XU03 0x03
+#define RT722_SDCA_ENT_XU0D 0x0d
+
+/* RT722 SDCA control */
+#define RT722_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT722_SDCA_CTL_FU_MUTE 0x01
+#define RT722_SDCA_CTL_FU_VOLUME 0x02
+#define RT722_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10
+#define RT722_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE 0x11
+#define RT722_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12
+#define RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH 0x13
+#define RT722_SDCA_CTL_SELECTED_MODE 0x01
+#define RT722_SDCA_CTL_DETECTED_MODE 0x02
+#define RT722_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT722_SDCA_CTL_VENDOR_DEF 0x30
+#define RT722_SDCA_CTL_FU_CH_GAIN 0x0b
+
+/* RT722 SDCA channel */
+#define CH_L 0x01
+#define CH_R 0x02
+#define CH_01 0x01
+#define CH_02 0x02
+#define CH_03 0x03
+#define CH_04 0x04
+#define CH_08 0x08
+
+/* sample frequency index */
+#define RT722_SDCA_RATE_16000HZ 0x04
+#define RT722_SDCA_RATE_32000HZ 0x07
+#define RT722_SDCA_RATE_44100HZ 0x08
+#define RT722_SDCA_RATE_48000HZ 0x09
+#define RT722_SDCA_RATE_96000HZ 0x0b
+#define RT722_SDCA_RATE_192000HZ 0x0d
+
+enum {
+ RT722_AIF1, /* For headset mic and headphone */
+ RT722_AIF2, /* For speaker */
+ RT722_AIF3, /* For dmic */
+ RT722_AIFS,
+};
+
+enum rt722_sdca_jd_src {
+ RT722_JD_NULL,
+ RT722_JD1,
+};
+
+int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave);
+int rt722_sdca_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave);
+int rt722_sdca_index_write(struct rt722_sdca_priv *rt722,
+ unsigned int nid, unsigned int reg, unsigned int value);
+int rt722_sdca_index_read(struct rt722_sdca_priv *rt722,
+ unsigned int nid, unsigned int reg, unsigned int *value);
+
+int rt722_sdca_jack_detect(struct rt722_sdca_priv *rt722, bool *hp, bool *mic);
+#endif /* __RT722_H__ */
--
2.40.0
2
1
[PATCH] ASoC: SOF: amd: Fix NULL pointer crash in acp_sof_ipc_msg_data function
by V sujith kumar Reddy 09 May '23
by V sujith kumar Reddy 09 May '23
09 May '23
Check substream and runtime variables before assigning.
Signed-off-by: V sujith kumar Reddy <Vsujithkumar.Reddy(a)amd.com>
---
sound/soc/sof/amd/acp-ipc.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c
index 4e0c48a36159..749e856dc601 100644
--- a/sound/soc/sof/amd/acp-ipc.c
+++ b/sound/soc/sof/amd/acp-ipc.c
@@ -209,7 +209,12 @@ int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sp
acp_mailbox_read(sdev, offset, p, sz);
} else {
struct snd_pcm_substream *substream = sps->substream;
- struct acp_dsp_stream *stream = substream->runtime->private_data;
+ struct acp_dsp_stream *stream;
+
+ if (!substream || !substream->runtime)
+ return -ESTRPIPE;
+
+ stream = substream->runtime->private_data;
if (!stream)
return -ESTRPIPE;
--
2.25.1
2
1