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
April 2023
- 110 participants
- 270 discussions
Several weeks ago, I sent a series [1] for adding a potentiometer as an
auxiliary device in ASoC. The feedback was that the potentiometer should
be directly handled in IIO (as other potentiometers) and something more
generic should be present in ASoC in order to have a binding to import
some IIO devices into sound cards.
The series related to the IIO potentiometer device is already under
review [2].
This series introduces simple-iio-aux. Its goal is to offer the binding
between IIO and ASoC.
It exposes attached IIO devices as ASoC auxiliary devices and allows to
control them through mixer controls.
On my system, the IIO device is a potentiometer and it is present in an
amplifier design present in the audio path.
Best regards,
Hervé
[1] https://lore.kernel.org/linux-kernel/20230203111422.142479-1-herve.codina@b…
[2] https://lore.kernel.org/linux-kernel/20230421085245.302169-1-herve.codina@b…
Herve Codina (4):
dt-bindings: sound: Add simple-iio-aux
iio: inkern: Add a helper to query an available minimum raw value
ASoC: soc-dapm.h: Add a helper to build a DAPM widget dynamically
ASoC: codecs: Add support for the generic IIO auxiliary devices
.../bindings/sound/simple-iio-aux.yaml | 65 ++++
drivers/iio/inkern.c | 67 ++++
include/linux/iio/consumer.h | 11 +
include/sound/soc-dapm.h | 12 +-
sound/soc/codecs/Kconfig | 12 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/simple-iio-aux.c | 307 ++++++++++++++++++
7 files changed, 475 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/sound/simple-iio-aux.yaml
create mode 100644 sound/soc/codecs/simple-iio-aux.c
--
2.39.2
5
16
[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
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
In a future patch HAS_IOPORT=n will result in inb()/outb() and friends
not being declared. We thus need to add HAS_IOPORT as dependency for
those drivers using them.
Co-developed-by: Arnd Bergmann <arnd(a)kernel.org>
Signed-off-by: Niklas Schnelle <schnelle(a)linux.ibm.com>
---
sound/drivers/Kconfig | 3 +++
sound/isa/Kconfig | 31 ++++++++++++++++++++++++++---
sound/pci/Kconfig | 45 ++++++++++++++++++++++++++++++++-----------
sound/pcmcia/Kconfig | 2 ++
4 files changed, 67 insertions(+), 14 deletions(-)
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index be3009746f3a..864991d8776d 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -128,6 +128,7 @@ config SND_VIRMIDI
config SND_MTPAV
tristate "MOTU MidiTimePiece AV multiport MIDI"
+ depends on HAS_IOPORT
select SND_RAWMIDI
help
To use a MOTU MidiTimePiece AV multiport MIDI adapter
@@ -152,6 +153,7 @@ config SND_MTS64
config SND_SERIAL_U16550
tristate "UART16550 serial MIDI driver"
+ depends on HAS_IOPORT
select SND_RAWMIDI
help
To include support for MIDI serial port interfaces, say Y here
@@ -185,6 +187,7 @@ config SND_SERIAL_GENERIC
config SND_MPU401
tristate "Generic MPU-401 UART driver"
+ depends on HAS_IOPORT
select SND_MPU401_UART
help
Say Y here to include support for MIDI ports compatible with
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 6ffa48dd5983..c7cef1e656fa 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -23,6 +23,7 @@ menuconfig SND_ISA
bool "ISA sound devices"
depends on ISA || COMPILE_TEST
depends on ISA_DMA_API
+ depends on HAS_IOPORT
default y
help
Support for sound devices connected via the ISA bus.
@@ -31,6 +32,7 @@ if SND_ISA
config SND_ADLIB
tristate "AdLib FM card"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
help
Say Y here to include support for AdLib FM cards.
@@ -41,6 +43,7 @@ config SND_ADLIB
config SND_AD1816A
tristate "Analog Devices SoundPort AD1816A"
depends on PNP
+ depends on HAS_IOPORT
select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
@@ -69,6 +72,7 @@ config SND_AD1848
config SND_ALS100
tristate "Diamond Tech. DT-019x and Avance Logic ALSxxx"
depends on PNP
+ depends on HAS_IOPORT
select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
@@ -84,6 +88,7 @@ config SND_ALS100
config SND_AZT1605
tristate "Aztech AZT1605 Driver"
depends on SND
+ depends on HAS_IOPORT
select SND_WSS_LIB
select SND_MPU401_UART
select SND_OPL3_LIB
@@ -97,6 +102,7 @@ config SND_AZT1605
config SND_AZT2316
tristate "Aztech AZT2316 Driver"
depends on SND
+ depends on HAS_IOPORT
select SND_WSS_LIB
select SND_MPU401_UART
select SND_OPL3_LIB
@@ -110,6 +116,7 @@ config SND_AZT2316
config SND_AZT2320
tristate "Aztech Systems AZT2320"
depends on PNP
+ depends on HAS_IOPORT
select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
@@ -123,6 +130,7 @@ config SND_AZT2320
config SND_CMI8328
tristate "C-Media CMI8328"
+ depends on HAS_IOPORT
select SND_WSS_LIB
select SND_OPL3_LIB
select SND_MPU401_UART
@@ -135,6 +143,7 @@ config SND_CMI8328
config SND_CMI8330
tristate "C-Media CMI8330"
+ depends on HAS_IOPORT
select SND_WSS_LIB
select SND_SB16_DSP
select SND_OPL3_LIB
@@ -148,6 +157,7 @@ config SND_CMI8330
config SND_CS4231
tristate "Generic Cirrus Logic CS4231 driver"
+ depends on HAS_IOPORT
select SND_MPU401_UART
select SND_WSS_LIB
help
@@ -159,6 +169,7 @@ config SND_CS4231
config SND_CS4236
tristate "Generic Cirrus Logic CS4232/CS4236+ driver"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_WSS_LIB
@@ -172,6 +183,7 @@ config SND_CS4236
config SND_ES1688
tristate "Generic ESS ES688/ES1688 and ES968 PnP driver"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
@@ -184,6 +196,7 @@ config SND_ES1688
config SND_ES18XX
tristate "Generic ESS ES18xx driver"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
@@ -195,7 +208,7 @@ config SND_ES18XX
config SND_SC6000
tristate "Gallant SC-6000/6600/7000 and Audio Excel DSP 16"
- depends on HAS_IOPORT_MAP
+ depends on HAS_IOPORT_MAP && HAS_IOPORT
select SND_WSS_LIB
select SND_OPL3_LIB
select SND_MPU401_UART
@@ -223,6 +236,7 @@ config SND_GUSCLASSIC
config SND_GUSEXTREME
tristate "Gravis UltraSound Extreme"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
@@ -273,6 +287,7 @@ config SND_INTERWAVE_STB
config SND_JAZZ16
tristate "Media Vision Jazz16 card and compatibles"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_SB8_DSP
@@ -289,6 +304,7 @@ config SND_JAZZ16
config SND_OPL3SA2
tristate "Yamaha OPL3-SA2/SA3"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_WSS_LIB
@@ -301,6 +317,7 @@ config SND_OPL3SA2
config SND_OPTI92X_AD1848
tristate "OPTi 82C92x - AD1848"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_OPL4_LIB
select SND_MPU401_UART
@@ -314,6 +331,7 @@ config SND_OPTI92X_AD1848
config SND_OPTI92X_CS4231
tristate "OPTi 82C92x - CS4231"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_OPL4_LIB
select SND_MPU401_UART
@@ -327,6 +345,7 @@ config SND_OPTI92X_CS4231
config SND_OPTI93X
tristate "OPTi 82C93x"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_WSS_LIB
@@ -339,6 +358,7 @@ config SND_OPTI93X
config SND_MIRO
tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver"
+ depends on HAS_IOPORT
select SND_OPL4_LIB
select SND_WSS_LIB
select SND_MPU401_UART
@@ -352,6 +372,7 @@ config SND_MIRO
config SND_SB8
tristate "Sound Blaster 1.0/2.0/Pro (8-bit)"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_RAWMIDI
select SND_SB8_DSP
@@ -364,6 +385,7 @@ config SND_SB8
config SND_SB16
tristate "Sound Blaster 16 (PnP)"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_SB16_DSP
@@ -376,6 +398,7 @@ config SND_SB16
config SND_SBAWE
tristate "Sound Blaster AWE (32,64) (PnP)"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_SB16_DSP
@@ -405,6 +428,7 @@ config SND_SB16_CSP
config SND_SSCAPE
tristate "Ensoniq SoundScape driver"
+ depends on HAS_IOPORT
select SND_MPU401_UART
select SND_WSS_LIB
select FW_LOADER
@@ -426,6 +450,7 @@ config SND_SSCAPE
config SND_WAVEFRONT
tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)"
+ depends on HAS_IOPORT
select FW_LOADER
select SND_OPL3_LIB
select SND_MPU401_UART
@@ -439,7 +464,7 @@ config SND_WAVEFRONT
config SND_MSND_PINNACLE
tristate "Turtle Beach MultiSound Pinnacle/Fiji driver"
- depends on X86
+ depends on X86 && HAS_IOPORT
select FW_LOADER
select SND_MPU401_UART
select SND_PCM
@@ -452,7 +477,7 @@ config SND_MSND_PINNACLE
config SND_MSND_CLASSIC
tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
- depends on X86
+ depends on X86 && HAS_IOPORT
select FW_LOADER
select SND_MPU401_UART
select SND_PCM
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index a55836225401..e8780bade58f 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -26,7 +26,7 @@ config SND_ALS300
select SND_PCM
select SND_AC97_CODEC
select SND_OPL3_LIB
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say 'Y' or 'M' to include support for Avance Logic ALS300/ALS300+
@@ -36,6 +36,7 @@ config SND_ALS300
config SND_ALS4000
tristate "Avance Logic ALS4000"
depends on ISA_DMA_API
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
@@ -51,7 +52,7 @@ config SND_ALI5451
tristate "ALi M5451 PCI Audio Controller"
select SND_MPU401_UART
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for the integrated AC97 sound
device on motherboards using the ALi M5451 Audio Controller
@@ -96,6 +97,7 @@ config SND_ATIIXP_MODEM
config SND_AU8810
tristate "Aureal Advantage"
+ depends on HAS_IOPORT
select SND_MPU401_UART
select SND_AC97_CODEC
help
@@ -110,6 +112,7 @@ config SND_AU8810
config SND_AU8820
tristate "Aureal Vortex"
+ depends on HAS_IOPORT
select SND_MPU401_UART
select SND_AC97_CODEC
help
@@ -123,6 +126,7 @@ config SND_AU8820
config SND_AU8830
tristate "Aureal Vortex 2"
+ depends on HAS_IOPORT
select SND_MPU401_UART
select SND_AC97_CODEC
help
@@ -157,7 +161,7 @@ config SND_AZT3328
select SND_RAWMIDI
select SND_AC97_CODEC
select SND_TIMER
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for Aztech AZF3328 (PCI168)
soundcards.
@@ -193,6 +197,7 @@ config SND_BT87X_OVERCLOCK
config SND_CA0106
tristate "SB Audigy LS / Live 24bit"
+ depends on HAS_IOPORT
select SND_AC97_CODEC
select SND_RAWMIDI
select SND_VMASTER
@@ -205,6 +210,7 @@ config SND_CA0106
config SND_CMIPCI
tristate "C-Media 8338, 8738, 8768, 8770"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
@@ -221,6 +227,7 @@ config SND_OXYGEN_LIB
config SND_OXYGEN
tristate "C-Media 8786, 8787, 8788 (Oxygen)"
+ depends on HAS_IOPORT
select SND_OXYGEN_LIB
select SND_PCM
select SND_MPU401_UART
@@ -246,6 +253,7 @@ config SND_OXYGEN
config SND_CS4281
tristate "Cirrus Logic (Sound Fusion) CS4281"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_RAWMIDI
select SND_AC97_CODEC
@@ -257,6 +265,7 @@ config SND_CS4281
config SND_CS46XX
tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x"
+ depends on HAS_IOPORT
select SND_RAWMIDI
select SND_AC97_CODEC
select FW_LOADER
@@ -290,6 +299,7 @@ config SND_CS5530
config SND_CS5535AUDIO
tristate "CS5535/CS5536 Audio"
depends on X86_32 || MIPS || COMPILE_TEST
+ depends on HAS_IOPORT
select SND_PCM
select SND_AC97_CODEC
help
@@ -307,6 +317,7 @@ config SND_CS5535AUDIO
config SND_CTXFI
tristate "Creative Sound Blaster X-Fi"
+ depends on HAS_IOPORT
select SND_PCM
help
If you want to use soundcards based on Creative Sound Blastr X-Fi
@@ -468,7 +479,7 @@ config SND_EMU10K1
select SND_AC97_CODEC
select SND_TIMER
select SND_SEQ_DEVICE if SND_SEQUENCER != n
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y to include support for Sound Blaster PCI 512, Live!,
Audigy and E-mu APS (partially supported) soundcards.
@@ -491,7 +502,7 @@ config SND_EMU10K1X
tristate "Emu10k1X (Dell OEM Version)"
select SND_AC97_CODEC
select SND_RAWMIDI
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for the Dell OEM version of the
Sound Blaster Live!.
@@ -501,6 +512,7 @@ config SND_EMU10K1X
config SND_ENS1370
tristate "(Creative) Ensoniq AudioPCI 1370"
+ depends on HAS_IOPORT
select SND_RAWMIDI
select SND_PCM
help
@@ -511,6 +523,7 @@ config SND_ENS1370
config SND_ENS1371
tristate "(Creative) Ensoniq AudioPCI 1371/1373"
+ depends on HAS_IOPORT
select SND_RAWMIDI
select SND_AC97_CODEC
help
@@ -525,7 +538,7 @@ config SND_ES1938
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on ESS Solo-1
(ES1938, ES1946, ES1969) chips.
@@ -537,7 +550,7 @@ config SND_ES1968
tristate "ESS ES1968/1978 (Maestro-1/2/2E)"
select SND_MPU401_UART
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on ESS Maestro
1/2/2E chips.
@@ -569,6 +582,7 @@ config SND_ES1968_RADIO
config SND_FM801
tristate "ForteMedia FM801"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
@@ -624,7 +638,7 @@ config SND_ICE1712
select SND_MPU401_UART
select SND_AC97_CODEC
select BITREVERSE
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on the
ICE1712 (Envy24) chip.
@@ -640,6 +654,7 @@ config SND_ICE1712
config SND_ICE1724
tristate "ICE/VT1724/1720 (Envy24HT/PT)"
+ depends on HAS_IOPORT
select SND_RAWMIDI
select SND_AC97_CODEC
select SND_VMASTER
@@ -712,7 +727,7 @@ config SND_LX6464ES
config SND_MAESTRO3
tristate "ESS Allegro/Maestro3"
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on ESS Maestro 3
(Allegro) chips.
@@ -753,6 +768,7 @@ config SND_NM256
config SND_PCXHR
tristate "Digigram PCXHR"
+ depends on HAS_IOPORT
select FW_LOADER
select SND_PCM
select SND_HWDEP
@@ -764,6 +780,7 @@ config SND_PCXHR
config SND_RIPTIDE
tristate "Conexant Riptide"
+ depends on HAS_IOPORT
select FW_LOADER
select SND_OPL3_LIB
select SND_MPU401_UART
@@ -808,6 +825,7 @@ config SND_RME9652
config SND_SE6X
tristate "Studio Evolution SE6X"
depends on SND_OXYGEN=n && SND_VIRTUOSO=n # PCI ID conflict
+ depends on HAS_IOPORT
select SND_OXYGEN_LIB
select SND_PCM
select SND_MPU401_UART
@@ -830,7 +848,7 @@ config SND_SONICVIBES
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on the S3
SonicVibes chip.
@@ -842,7 +860,7 @@ config SND_TRIDENT
tristate "Trident 4D-Wave DX/NX; SiS 7018"
select SND_MPU401_UART
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on Trident
4D-Wave DX/NX or SiS 7018 chips.
@@ -852,6 +870,7 @@ config SND_TRIDENT
config SND_VIA82XX
tristate "VIA 82C686A/B, 8233/8235 AC97 Controller"
+ depends on HAS_IOPORT
select SND_MPU401_UART
select SND_AC97_CODEC
help
@@ -863,6 +882,7 @@ config SND_VIA82XX
config SND_VIA82XX_MODEM
tristate "VIA 82C686A/B, 8233 based Modems"
+ depends on HAS_IOPORT
select SND_AC97_CODEC
help
Say Y here to include support for the integrated MC97 modem on
@@ -873,6 +893,7 @@ config SND_VIA82XX_MODEM
config SND_VIRTUOSO
tristate "Asus Virtuoso 66/100/200 (Xonar)"
+ depends on HAS_IOPORT
select SND_OXYGEN_LIB
select SND_PCM
select SND_MPU401_UART
@@ -889,6 +910,7 @@ config SND_VIRTUOSO
config SND_VX222
tristate "Digigram VX222"
+ depends on HAS_IOPORT
select SND_VX_LIB
help
Say Y here to include support for Digigram VX222 soundcards.
@@ -898,6 +920,7 @@ config SND_VX222
config SND_YMFPCI
tristate "Yamaha YMF724/740/744/754"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
diff --git a/sound/pcmcia/Kconfig b/sound/pcmcia/Kconfig
index 10291c43cb18..b133ad423f84 100644
--- a/sound/pcmcia/Kconfig
+++ b/sound/pcmcia/Kconfig
@@ -13,6 +13,7 @@ if SND_PCMCIA && PCMCIA
config SND_VXPOCKET
tristate "Digigram VXpocket"
select SND_VX_LIB
+ depends on HAS_IOPORT
help
Say Y here to include support for Digigram VXpocket and
VXpocket 440 soundcards.
@@ -22,6 +23,7 @@ config SND_VXPOCKET
config SND_PDAUDIOCF
tristate "Sound Core PDAudioCF"
+ depends on HAS_IOPORT
select SND_PCM
help
Say Y here to include support for Sound Core PDAudioCF
--
2.37.2
2
2
08 May '23
The idea to encode the bitfield manipulation in the register address is
quite clever, but it's somewhat wasteful to do these calculations at
runtime, given that they are all constants. Change that.
The added bitfield manipulation macros will be used separately as well.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen(a)gmx.de>
---
include/sound/emu10k1.h | 29 ++++++++-
sound/pci/emu10k1/emupcm.c | 31 +++++-----
sound/pci/emu10k1/emuproc.c | 4 +-
sound/pci/emu10k1/io.c | 116 +++++++++++++++++-------------------
4 files changed, 99 insertions(+), 81 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 8fe80dcee71b..fd1fe49578ce 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1773,8 +1773,33 @@ int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size);
int snd_emu10k1_done(struct snd_emu10k1 * emu);
/* I/O functions */
-unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
-void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
+
+#define REG_SHIFT(r) (((r) >> 16) & 0x1f)
+#define REG_SIZE(r) (((r) >> 24) & 0x1f)
+#define REG_MASK0(r) ((1U << REG_SIZE(r)) - 1U)
+#define REG_MASK(r) (REG_MASK0(r) << REG_SHIFT(r))
+#define REG_ADDR(r, v) ((((r) & 0xffff) << 16) | (v))
+#define REG_VAL_GET(r, v) ((v & REG_MASK(r)) >> REG_SHIFT(r))
+#define REG_VAL_PUT(r, v) ((v) << REG_SHIFT(r))
+#define snd_emu10k1_ptr_read(emu, reg, voice) \
+ ({ \
+ u32 data = snd_emu10k1_ptr_read_raw(emu, REG_ADDR(reg, voice)); \
+ if (REG_SIZE(reg)) \
+ data = REG_VAL_GET(reg, data); \
+ data; \
+ })
+#define snd_emu10k1_ptr_write(emu, reg, voice, data) \
+ do { \
+ if (REG_SIZE(reg)) \
+ snd_emu10k1_ptr_modify(emu, REG_ADDR(reg, voice), \
+ ~REG_MASK(reg), REG_VAL_PUT(reg, data)); \
+ else \
+ snd_emu10k1_ptr_write_raw(emu, REG_ADDR(reg, voice), data); \
+ } while (0)
+
+u32 snd_emu10k1_ptr_read_raw(struct snd_emu10k1 *emu, u32 reg);
+void snd_emu10k1_ptr_write_raw(struct snd_emu10k1 *emu, u32 reg, u32 data);
+void snd_emu10k1_ptr_modify(struct snd_emu10k1 *emu, u32 reg, u32 and_mask, u32 or_mask);
unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index b0c0ef342756..2baa7f01eb5b 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -528,7 +528,7 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream)
int idx;
/* zeroing the buffer size will stop capture */
- snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0);
+ snd_emu10k1_ptr_write_raw(emu, epcm->capture_bs_reg, 0);
switch (epcm->type) {
case CAPTURE_AC97ADC:
snd_emu10k1_ptr_write(emu, ADCCR, 0, 0);
@@ -543,7 +543,7 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream)
default:
break;
}
- snd_emu10k1_ptr_write(emu, epcm->capture_ba_reg, 0, runtime->dma_addr);
+ snd_emu10k1_ptr_write_raw(emu, epcm->capture_ba_reg, runtime->dma_addr);
epcm->capture_bufsize = snd_pcm_lib_buffer_bytes(substream);
epcm->capture_bs_val = 0;
for (idx = 0; idx < 31; idx++) {
@@ -771,16 +771,16 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
default:
break;
}
- snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, epcm->capture_bs_val);
+ snd_emu10k1_ptr_write_raw(emu, epcm->capture_bs_reg, epcm->capture_bs_val);
epcm->running = 1;
epcm->first_ptr = 1;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
epcm->running = 0;
snd_emu10k1_intr_disable(emu, epcm->capture_inte);
outl(epcm->capture_ipr, emu->port + IPR);
- snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0);
+ snd_emu10k1_ptr_write_raw(emu, epcm->capture_bs_reg, 0);
switch (epcm->type) {
case CAPTURE_AC97ADC:
snd_emu10k1_ptr_write(emu, ADCCR, 0, 0);
@@ -812,7 +812,7 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *
if (!epcm->running)
return 0;
- ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff;
+ ptr = snd_emu10k1_ptr_read(emu, CCCA_CURRADDR, epcm->voices[0]->number);
#if 0 /* Perex's code */
ptr += runtime->buffer_size;
ptr -= epcm->ccca_start_addr;
@@ -899,7 +899,8 @@ static snd_pcm_uframes_t snd_emu10k1_capture_pointer(struct snd_pcm_substream *s
udelay(50); /* hack, it takes awhile until capture is started */
epcm->first_ptr = 0;
}
- ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff;
+ ptr = REG_VAL_GET(FXIDX_IDX, // All *IDX_MASKs are assumed to be equal
+ snd_emu10k1_ptr_read_raw(emu, epcm->capture_idx_reg));
return bytes_to_frames(runtime, ptr);
}
@@ -1128,9 +1129,9 @@ static int snd_emu10k1_capture_open(struct snd_pcm_substream *substream)
epcm->substream = substream;
epcm->capture_ipr = IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL;
epcm->capture_inte = INTE_ADCBUFENABLE;
- epcm->capture_ba_reg = ADCBA;
- epcm->capture_bs_reg = ADCBS;
- epcm->capture_idx_reg = emu->audigy ? A_ADCIDX : ADCIDX;
+ epcm->capture_ba_reg = REG_ADDR(ADCBA, 0);
+ epcm->capture_bs_reg = REG_ADDR(ADCBS, 0);
+ epcm->capture_idx_reg = emu->audigy ? REG_ADDR(A_ADCIDX, 0) : REG_ADDR(ADCIDX, 0);
runtime->private_data = epcm;
runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_capture;
@@ -1164,9 +1165,9 @@ static int snd_emu10k1_capture_mic_open(struct snd_pcm_substream *substream)
epcm->substream = substream;
epcm->capture_ipr = IPR_MICBUFFULL|IPR_MICBUFHALFFULL;
epcm->capture_inte = INTE_MICBUFENABLE;
- epcm->capture_ba_reg = MICBA;
- epcm->capture_bs_reg = MICBS;
- epcm->capture_idx_reg = emu->audigy ? A_MICIDX : MICIDX;
+ epcm->capture_ba_reg = REG_ADDR(MICBA, 0);
+ epcm->capture_bs_reg = REG_ADDR(MICBS, 0);
+ epcm->capture_idx_reg = emu->audigy ? REG_ADDR(A_MICIDX, 0) : REG_ADDR(MICIDX, 0);
substream->runtime->private_data = epcm;
substream->runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_capture;
@@ -1204,9 +1205,9 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
epcm->substream = substream;
epcm->capture_ipr = IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL;
epcm->capture_inte = INTE_EFXBUFENABLE;
- epcm->capture_ba_reg = FXBA;
- epcm->capture_bs_reg = FXBS;
- epcm->capture_idx_reg = FXIDX;
+ epcm->capture_ba_reg = REG_ADDR(FXBA, 0);
+ epcm->capture_bs_reg = REG_ADDR(FXBS, 0);
+ epcm->capture_idx_reg = REG_ADDR(FXIDX, 0);
substream->runtime->private_data = epcm;
substream->runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_capture_efx;
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index bec72dc60a41..3a7f60d64c27 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -23,8 +23,8 @@
static void snd_emu10k1_proc_spdif_status(struct snd_emu10k1 * emu,
struct snd_info_buffer *buffer,
char *title,
- int status_reg,
- int rate_reg)
+ u8 status_reg,
+ u8 rate_reg)
{
static const char * const clkaccy[4] = { "1000ppm", "50ppm", "variable", "unknown" };
static const int samplerate[16] = { 44100, 1, 48000, 32000, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index c60573f14ea8..373c633bd88b 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -18,72 +18,64 @@
#include <linux/export.h>
#include "p17v.h"
-unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
+static inline int check_ptr_reg(struct snd_emu10k1 *emu, u32 reg)
{
- unsigned long flags;
- unsigned int regptr, val;
- unsigned int mask;
-
- mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
- regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
-
- if (reg & 0xff000000) {
- unsigned char size, offset;
-
- size = (reg >> 24) & 0x3f;
- offset = (reg >> 16) & 0x1f;
- mask = ((1 << size) - 1) << offset;
-
- spin_lock_irqsave(&emu->emu_lock, flags);
- outl(regptr, emu->port + PTR);
- val = inl(emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
-
- return (val & mask) >> offset;
- } else {
- spin_lock_irqsave(&emu->emu_lock, flags);
- outl(regptr, emu->port + PTR);
- val = inl(emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
- return val;
- }
-}
-
-EXPORT_SYMBOL(snd_emu10k1_ptr_read);
-
-void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
-{
- unsigned int regptr;
- unsigned long flags;
- unsigned int mask;
-
if (snd_BUG_ON(!emu))
- return;
- mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
- regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
-
- if (reg & 0xff000000) {
- unsigned char size, offset;
-
- size = (reg >> 24) & 0x3f;
- offset = (reg >> 16) & 0x1f;
- mask = ((1 << size) - 1) << offset;
- data = (data << offset) & mask;
-
- spin_lock_irqsave(&emu->emu_lock, flags);
- outl(regptr, emu->port + PTR);
- data |= inl(emu->port + DATA) & ~mask;
- outl(data, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
- } else {
- spin_lock_irqsave(&emu->emu_lock, flags);
- outl(regptr, emu->port + PTR);
- outl(data, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
- }
+ return 0;
+ if (snd_BUG_ON(reg & 0xffff0000 & (emu->audigy ? ~A_PTR_ADDRESS_MASK : ~PTR_ADDRESS_MASK)))
+ return 0;
+ if (snd_BUG_ON(reg & 0xffff & ~PTR_CHANNELNUM_MASK))
+ return 0;
+ return 1;
}
-EXPORT_SYMBOL(snd_emu10k1_ptr_write);
+unsigned int snd_emu10k1_ptr_read_raw(struct snd_emu10k1 *emu, u32 reg)
+{
+ unsigned long flags;
+ u32 val;
+
+ if (!check_ptr_reg(emu, reg))
+ return 0;
+
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ outl(reg, emu->port + PTR);
+ val = inl(emu->port + DATA);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+ return val;
+}
+
+EXPORT_SYMBOL(snd_emu10k1_ptr_read_raw);
+
+void snd_emu10k1_ptr_write_raw(struct snd_emu10k1 *emu, u32 reg, u32 data)
+{
+ unsigned long flags;
+
+ if (!check_ptr_reg(emu, reg))
+ return;
+
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ outl(reg, emu->port + PTR);
+ outl(data, emu->port + DATA);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
+EXPORT_SYMBOL(snd_emu10k1_ptr_write_raw);
+
+void snd_emu10k1_ptr_modify(struct snd_emu10k1 *emu, u32 reg, u32 and_mask, u32 or_mask)
+{
+ unsigned long flags;
+
+ if (!check_ptr_reg(emu, reg))
+ return;
+
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ outl(reg, emu->port + PTR);
+ or_mask |= inl(emu->port + DATA) & and_mask;
+ outl(or_mask, emu->port + DATA);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
+EXPORT_SYMBOL(snd_emu10k1_ptr_modify);
unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
unsigned int reg,
--
2.40.0.152.g15d061e6df
2
4
- Fix mixer source port names. These will require some users to
re-adjust their mixer settings, which seems acceptable:
- The S/PDIF port is on the main 1010 card, not the 0202 daughter card
- The 1616m CardBus card has all inputs on the dock, so there is
no point in specifying it
- Conversely, the 1010 card has "dispersed" inputs, so say where the
ADAT port is, consistently with the S/PDIF port
- The 1616m CardBus card is actually named E-MU 02 (due to the headphone
output jack it has)
- Fix capitalization of "E-MU"
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen(a)gmx.de>
---
sound/pci/emu10k1/emu10k1_main.c | 16 +++++++-------
sound/pci/emu10k1/emumixer.c | 36 ++++++++++++++++----------------
2 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 3abdaf1b9624..5d9d772e3a13 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1310,7 +1310,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = {
/* Does NOT support sync daughter card (obviously). */
/* Tested by James(a)superbug.co.uk 4th Nov 2007. */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102,
- .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]",
+ .driver = "Audigy2", .name = "E-MU 02 CardBus [MAEM8950]",
.id = "EMU1010",
.emu10k2_chip = 1,
.ca0108_chip = 1,
@@ -1323,7 +1323,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = {
* MicroDock[M] to make it an E-MU 1616[m]. */
/* Does NOT support sync daughter card. */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102,
- .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM8960]",
+ .driver = "Audigy2", .name = "E-MU 1010b PCI [MAEM8960]",
.id = "EMU1010",
.emu10k2_chip = 1,
.ca0108_chip = 1,
@@ -1337,48 +1337,48 @@ static const struct snd_emu_chip_details emu_chip_details[] = {
* still work. */
/* Does NOT support sync daughter card. */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40071102,
- .driver = "Audigy2", .name = "E-mu 1010 PCIe [MAEM8986]",
+ .driver = "Audigy2", .name = "E-MU 1010 PCIe [MAEM8986]",
.id = "EMU1010",
.emu10k2_chip = 1,
.ca0108_chip = 1,
.spk71 = 1,
.emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 PCIe */
/* Tested by James(a)superbug.co.uk 8th July 2005. */
/* This is MAEM8810 "Hana", 0202 is MAEM8820 "Hamoa" */
/* Attach 0202 daughter card to make it an E-MU 1212m, OR an
* AudioDock[M] to make it an E-MU 1820[m]. */
/* Supports sync daughter card. */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
- .driver = "Audigy2", .name = "E-mu 1010 [MAEM8810]",
+ .driver = "Audigy2", .name = "E-MU 1010 [MAEM8810]",
.id = "EMU1010",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.spk71 = 1,
.emu_model = EMU_MODEL_EMU1010}, /* EMU 1010 old revision */
/* This is MAEM8852 "HanaLiteLite" */
/* Supports sync daughter card. */
/* Tested by oswald.buddenhagen(a)gmx.de Mar 2023. */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102,
- .driver = "Audigy2", .name = "E-mu 0404b PCI [MAEM8852]",
+ .driver = "Audigy2", .name = "E-MU 0404b PCI [MAEM8852]",
.id = "EMU0404",
.emu10k2_chip = 1,
.ca0108_chip = 1,
.spk71 = 1,
.emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 new revision */
/* This is MAEM8850 "HanaLite" */
/* Supports sync daughter card. */
/* Tested by James(a)superbug.co.uk 20-3-2007. */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102,
- .driver = "Audigy2", .name = "E-mu 0404 [MAEM8850]",
+ .driver = "Audigy2", .name = "E-MU 0404 [MAEM8850]",
.id = "EMU0404",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.spk71 = 1,
.emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */
/* EMU0404 PCIe */
/* Does NOT support sync daughter card. */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40051102,
- .driver = "Audigy2", .name = "E-mu 0404 PCIe [MAEM8984]",
+ .driver = "Audigy2", .name = "E-MU 0404 PCIe [MAEM8984]",
.id = "EMU0404",
.emu10k2_chip = 1,
.ca0108_chip = 1,
@@ -1645,7 +1645,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = {
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102,
- .driver = "EMU10K1", .name = "E-mu APS [PC545]",
+ .driver = "EMU10K1", .name = "E-MU APS [PC545]",
.id = "APS",
.emu10k1_chip = 1,
.ecard = 1} ,
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 8fce3413f4ae..a101fe7598c4 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -81,16 +81,16 @@ static const char * const emu1010_src_texts[] = {
"Dock ADC3 Right",
"0202 ADC Left",
"0202 ADC Right",
- "0202 SPDIF Left",
- "0202 SPDIF Right",
- "ADAT 0",
- "ADAT 1",
- "ADAT 2",
- "ADAT 3",
- "ADAT 4",
- "ADAT 5",
- "ADAT 6",
- "ADAT 7",
+ "1010 SPDIF Left",
+ "1010 SPDIF Right",
+ "1010 ADAT 0",
+ "1010 ADAT 1",
+ "1010 ADAT 2",
+ "1010 ADAT 3",
+ "1010 ADAT 4",
+ "1010 ADAT 5",
+ "1010 ADAT 6",
+ "1010 ADAT 7",
"DSP 0",
"DSP 1",
"DSP 2",
@@ -129,14 +129,14 @@ static const char * const emu1010_src_texts[] = {
static const char * const emu1616_src_texts[] = {
"Silence",
- "Dock Mic A",
- "Dock Mic B",
- "Dock ADC1 Left",
- "Dock ADC1 Right",
- "Dock ADC2 Left",
- "Dock ADC2 Right",
- "Dock SPDIF Left",
- "Dock SPDIF Right",
+ "Mic A",
+ "Mic B",
+ "ADC1 Left",
+ "ADC1 Right",
+ "ADC2 Left",
+ "ADC2 Right",
+ "SPDIF Left",
+ "SPDIF Right",
"ADAT 0",
"ADAT 1",
"ADAT 2",
--
2.40.0.152.g15d061e6df
2
1
08 May '23
---
This patch series needs to be applied on top of the patch titled "ALSA:
emu10k1: use more existing defines instead of open-coded numbers".
Oswald Buddenhagen (6):
ALSA: emu10k1: remove pointless locks from timer code
ALSA: emu10k1: remove pointless locks from /proc code
ALSA: emu10k1: use the right lock in snd_emu10k1_shared_spdif_put()
ALSA: emu10k1: fix locking in snd_emu1010_fpga_link_dst_src_write()
ALSA: core: update comment on snd_card.controls_rwsem
ALSA: emu10k1: remove now superfluous mixer locking
include/sound/core.h | 2 +-
sound/pci/emu10k1/emufx.c | 7 -------
sound/pci/emu10k1/emumixer.c | 32 ++------------------------------
sound/pci/emu10k1/emupcm.c | 2 --
sound/pci/emu10k1/emuproc.c | 6 ------
sound/pci/emu10k1/io.c | 25 +++++++++++++++++--------
sound/pci/emu10k1/timer.c | 6 ------
7 files changed, 20 insertions(+), 60 deletions(-)
--
2.40.0.152.g15d061e6df
2
7
It makes sense to have only a single point responsible for ensuring
that all currently pending IRQs are handled. The current code in
sdw_handle_slave_alerts confusingly splits this process in two. This
code will loop until the asserted IRQs are cleared but it will only
handle IRQs that were already asserted when it was called. This
means the caller must also loop (either manually, or through its IRQ
mechanism) until the IRQs are all handled. It makes sense to either do
all the looping in sdw_handle_slave_alerts or do no looping there and
let the host controller repeatedly call it until things are handled.
There are realistically two sensible host controllers, those that
will generate an IRQ when the alert status changes and those
that will generate an IRQ continuously whilst the alert status
is high. The current code will work fine for the second of those
systems but not the first with out additional looping in the host
controller. Removing the code that filters out new IRQs whilst
the handler is running enables both types of host controller to be
supported and simplifies the code. The code will still only loop up to
SDW_READ_INTR_CLEAR_RETRY times, so it shouldn't be possible for it to
get completely stuck handling IRQs forever, and if you are generating
IRQs faster than you can handle them you likely have bigger problems
anyway.
This fixes an issue on the Cadence SoundWire IP, which only generates
IRQs on an alert status change, where an alert which arrives whilst
another alert is being handled will never be handled and will block
all future alerts from being handled.
Signed-off-by: Charles Keepax <ckeepax(a)opensource.cirrus.com>
---
Changes since v1:
- Update commit message
Thanks,
Charles
drivers/soundwire/bus.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 1ea6a64f8c4a5..338f4f0b5d0cc 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -1588,7 +1588,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
unsigned long port;
bool slave_notify;
u8 sdca_cascade = 0;
- u8 buf, buf2[2], _buf, _buf2[2];
+ u8 buf, buf2[2];
bool parity_check;
bool parity_quirk;
@@ -1745,9 +1745,9 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
"SDW_SCP_INT1 recheck read failed:%d\n", ret);
goto io_err;
}
- _buf = ret;
+ buf = ret;
- ret = sdw_nread_no_pm(slave, SDW_SCP_INTSTAT2, 2, _buf2);
+ ret = sdw_nread_no_pm(slave, SDW_SCP_INTSTAT2, 2, buf2);
if (ret < 0) {
dev_err(&slave->dev,
"SDW_SCP_INT2/3 recheck read failed:%d\n", ret);
@@ -1765,12 +1765,8 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
}
/*
- * Make sure no interrupts are pending, but filter to limit loop
- * to interrupts identified in the first status read
+ * Make sure no interrupts are pending
*/
- buf &= _buf;
- buf2[0] &= _buf2[0];
- buf2[1] &= _buf2[1];
stat = buf || buf2[0] || buf2[1] || sdca_cascade;
/*
--
2.30.2
3
2
[PATCH v3 0/7] soundwire: qcom: add support for SM8550 (Soundwire v2.0.0)
by Krzysztof Kozlowski 08 May '23
by Krzysztof Kozlowski 08 May '23
08 May '23
Hi,
Changes since v2:
1. Use uint16 for qcom,ports-sinterval.
DTS will be fixed in separate patchset.
2. Add tags.
Changes since v1:
1. Patch 1: Increase maxItems to 16 for port-related properties.
2. Re-order patch 1 and 2.
3. Patch 3: Drop unneeded semicolon.
4. Patch 5: Fix lang typo in subject.
Best regards,
Krzysztof
Krzysztof Kozlowski (7):
dt-bindings: soundwire: qcom: add Qualcomm Soundwire v2.0.0
dt-bindings: soundwire: qcom: add 16-bit sample interval
soundwire: qcom: allow 16-bit sample interval for ports
soundwire: qcom: use consistently 'ctrl' as state variable name
soundwire: qcom: prepare for handling different register layouts
soundwire: qcom: add support for v2.0.0 controller
soundwire: qcom: use tabs for indentation in defines
.../bindings/soundwire/qcom,soundwire.yaml | 39 +-
drivers/soundwire/qcom.c | 387 ++++++++++++------
2 files changed, 287 insertions(+), 139 deletions(-)
--
2.34.1
3
10
The series of patches consists of three major changes.
First, remove redundant supply for ADDA DAI dirver. Second, revise ETDM
control including APLL dynamic switch via DAPM, so APLL can be enabled
when it is really required. Finally, AFE probe function is updated. Bus
protection change was dropped at the previous patch because the dependent
change was not accepted.
Changes since v2:
- remove required properties in dt-binding file
Changes since v1:
- replace unnecessary dev_info with dev_dbg
- fix dt-binging ABI breaking behavior
Trevor Wu (7):
ASoC: mediatek: mt8188: remove supply AUDIO_HIRES
ASoC: mediatek: mt8188: complete set_tdm_slot function
ASoC: mediatek: mt8188: revise ETDM control flow
ASoC: mediatek: mt8188: refine APLL control
ASoC: mediatek: mt8188: combine afe component registration
ASoC: mediatek: mt8188: add bus protection
ASoC: dt-bindings: mediatek,mt8188-afe: add audio properties
.../bindings/sound/mediatek,mt8188-afe.yaml | 12 +-
sound/soc/mediatek/mt8188/mt8188-afe-clk.c | 138 ++-
sound/soc/mediatek/mt8188/mt8188-afe-clk.h | 11 +
sound/soc/mediatek/mt8188/mt8188-afe-pcm.c | 113 ++-
sound/soc/mediatek/mt8188/mt8188-dai-adda.c | 37 -
sound/soc/mediatek/mt8188/mt8188-dai-etdm.c | 922 ++++++++++--------
sound/soc/mediatek/mt8188/mt8188-reg.h | 2 +
7 files changed, 751 insertions(+), 484 deletions(-)
--
2.18.0
3
9