public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE
@ 2025-11-24 18:04 Harin Lee
  2025-11-24 18:04 ` [PATCH v3 1/6] ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init() Harin Lee
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Harin Lee @ 2025-11-24 18:04 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai; +Cc: linux-sound, linux-kernel, Harin Lee

I added support for the Onkyo SE-300PCIE (OK0010), a Creative X-Fi
CA20K2-based sound card with dual TI PCM1798 DACs, a single TI PCM1681
DAC for 7.1ch output, and a CS5364 ADC. This model differs
significantly from other CA20K2-based variants.

Since official driver support for this hardware was discontinued a long
time ago, this patch series enables the card to be used on modern
platforms.

This patch series was developed using QEMU vfio tracing, and PCIe BAR
dumps. Tested with analog output (up to 192kHz) and line/microphone
input (up to 96kHz) at various sample rates.

Changes in v3:
 - Patch 5: Rename ALSA mixer control to "Analog Playback Route" as
   suggested by the maintainer
 - Patch 5: Fix 'rca_state' type to 'unsigned int' in
   dedicated_rca_put()
 - Patch 6: Add comments explaining the port mapping logic for
   SE-300PCIE

Harin Lee (6):
  ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init()
  ALSA: ctxfi: Add ADC helper functions for GPIO
  ALSA: ctxfi: Use explicit output flag for DAIO resources
  ALSA: ctxfi: Refactor resource alloc for sparse mappings
  ALSA: ctxfi: Add support for dedicated RCA switching
  ALSA: ctxfi: Add support for Onkyo SE-300PCIE (OK0010)

 sound/pci/ctxfi/ctatc.c      | 97 ++++++++++++++++++++++++++----------
 sound/pci/ctxfi/ctatc.h      |  8 +--
 sound/pci/ctxfi/ctdaio.c     | 18 ++++---
 sound/pci/ctxfi/ctdaio.h     |  3 ++
 sound/pci/ctxfi/cthardware.h |  4 +-
 sound/pci/ctxfi/cthw20k1.c   |  3 +-
 sound/pci/ctxfi/cthw20k2.c   | 81 +++++++++++++++++++++++-------
 sound/pci/ctxfi/ctmixer.c    | 73 +++++++++++++++++++++++++--
 8 files changed, 225 insertions(+), 62 deletions(-)

-- 
2.52.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 1/6] ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init()
  2025-11-24 18:04 [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE Harin Lee
@ 2025-11-24 18:04 ` Harin Lee
  2025-11-24 18:04 ` [PATCH v3 2/6] ALSA: ctxfi: Add ADC helper functions for GPIO Harin Lee
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Harin Lee @ 2025-11-24 18:04 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai; +Cc: linux-sound, linux-kernel, Harin Lee

Add a hw parameter to the daio_mgr_dao_init() function to provide
access to model-specific information. This is necessary for proper
configuration of S/PDIF and I2S output ports on different hardware
variants.

Signed-off-by: Harin Lee <me@harin.net>
---
 sound/pci/ctxfi/ctdaio.c     | 2 +-
 sound/pci/ctxfi/cthardware.h | 2 +-
 sound/pci/ctxfi/cthw20k1.c   | 2 +-
 sound/pci/ctxfi/cthw20k2.c   | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index c0c3f8ab8467..10d0a7088718 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -390,7 +390,7 @@ static int dao_rsc_init(struct dao *dao,
 	hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
 
 	conf = (desc->msr & 0x7) | (desc->passthru << 3);
-	hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk,
+	hw->daio_mgr_dao_init(hw, mgr->mgr.ctrl_blk,
 			daio_device_index(dao->daio.type, hw), conf);
 	hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
 			daio_device_index(dao->daio.type, hw));
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
index 2875cec83b8f..d29b4e5b3fcc 100644
--- a/sound/pci/ctxfi/cthardware.h
+++ b/sound/pci/ctxfi/cthardware.h
@@ -167,7 +167,7 @@ struct hw {
 	int (*daio_mgr_dsb_dai)(void *blk, unsigned int idx);
 	int (*daio_mgr_enb_dao)(void *blk, unsigned int idx);
 	int (*daio_mgr_dsb_dao)(void *blk, unsigned int idx);
-	int (*daio_mgr_dao_init)(void *blk, unsigned int idx,
+	int (*daio_mgr_dao_init)(struct hw *hw, void *blk, unsigned int idx,
 						unsigned int conf);
 	int (*daio_mgr_set_imaparc)(void *blk, unsigned int slot);
 	int (*daio_mgr_set_imapnxt)(void *blk, unsigned int next);
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index 42b90c9b2ee9..60cc1d14453a 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1031,7 +1031,7 @@ static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
 	return 0;
 }
 
-static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
+static int daio_mgr_dao_init(struct hw *hw __maybe_unused, void *blk, unsigned int idx, unsigned int conf)
 {
 	struct daio_mgr_ctrl_blk *ctl = blk;
 
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 55af8ef29838..1a085e7e5786 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -985,7 +985,7 @@ static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
 	return 0;
 }
 
-static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
+static int daio_mgr_dao_init(struct hw *hw __maybe_unused, void *blk, unsigned int idx, unsigned int conf)
 {
 	struct daio_mgr_ctrl_blk *ctl = blk;
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 2/6] ALSA: ctxfi: Add ADC helper functions for GPIO
  2025-11-24 18:04 [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE Harin Lee
  2025-11-24 18:04 ` [PATCH v3 1/6] ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init() Harin Lee
@ 2025-11-24 18:04 ` Harin Lee
  2025-11-24 18:04 ` [PATCH v3 3/6] ALSA: ctxfi: Use explicit output flag for DAIO resources Harin Lee
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Harin Lee @ 2025-11-24 18:04 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai; +Cc: linux-sound, linux-kernel, Harin Lee

Add helper functions hw_adc_stop(), hw_adc_start(), and hw_adc_reset()
to encapsulate ADC reset sequence operations. These functions reduce
duplication by centralizing the GPIO-based ADC control logic.

Signed-off-by: Harin Lee <me@harin.net>
---
 sound/pci/ctxfi/cthw20k2.c | 37 ++++++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 1a085e7e5786..5d39bc943648 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -1826,6 +1826,32 @@ static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
 	return 0;
 }
 
+static void hw_adc_stop(struct hw *hw)
+{
+	u32 data;
+	/* Reset the ADC (reset is active low). */
+	data = hw_read_20kx(hw, GPIO_DATA);
+	data &= ~(0x1 << 15);
+	hw_write_20kx(hw, GPIO_DATA, data);
+	usleep_range(10000, 11000);
+}
+
+static void hw_adc_start(struct hw *hw)
+{
+	u32 data;
+	/* Return the ADC to normal operation. */
+	data = hw_read_20kx(hw, GPIO_DATA);
+	data |= (0x1 << 15);
+	hw_write_20kx(hw, GPIO_DATA, data);
+	msleep(50);
+}
+
+static void __maybe_unused hw_adc_reset(struct hw *hw)
+{
+	hw_adc_stop(hw);
+	hw_adc_start(hw);
+}
+
 static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 {
 	int err;
@@ -1843,10 +1869,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 		goto error;
 	}
 
-	/* Reset the ADC (reset is active low). */
-	data = hw_read_20kx(hw, GPIO_DATA);
-	data &= ~(0x1 << 15);
-	hw_write_20kx(hw, GPIO_DATA, data);
+	hw_adc_stop(hw);
 
 	if (hw->model == CTSB1270) {
 		/* Set up the PCM4220 ADC on Titanium HD */
@@ -1860,11 +1883,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 		hw_write_20kx(hw, GPIO_DATA, data);
 	}
 
-	usleep_range(10000, 11000);
-	/* Return the ADC to normal operation. */
-	data |= (0x1 << 15);
-	hw_write_20kx(hw, GPIO_DATA, data);
-	msleep(50);
+	hw_adc_start(hw);
 
 	/* I2C write to register offset 0x0B to set ADC LRCLK polarity */
 	/* invert bit, interface format to I2S, word length to 24-bit, */
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 3/6] ALSA: ctxfi: Use explicit output flag for DAIO resources
  2025-11-24 18:04 [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE Harin Lee
  2025-11-24 18:04 ` [PATCH v3 1/6] ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init() Harin Lee
  2025-11-24 18:04 ` [PATCH v3 2/6] ALSA: ctxfi: Add ADC helper functions for GPIO Harin Lee
@ 2025-11-24 18:04 ` Harin Lee
  2025-11-24 18:04 ` [PATCH v3 4/6] ALSA: ctxfi: Refactor resource alloc for sparse mappings Harin Lee
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Harin Lee @ 2025-11-24 18:04 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai; +Cc: linux-sound, linux-kernel, Harin Lee

Replace the index-based type check with an explicit output flag in
struct daio and struct daio_desc.

This allows handling DAIO resource types correctly regardless of their
index. This is necessary for hardware variants where resource types do
not follow a sequential order.

Signed-off-by: Harin Lee <me@harin.net>
---
 sound/pci/ctxfi/ctatc.c  |  3 ++-
 sound/pci/ctxfi/ctdaio.c | 14 +++++++-------
 sound/pci/ctxfi/ctdaio.h |  2 ++
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index 14779b383d9e..55bbeb891afc 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -1163,7 +1163,7 @@ static int atc_release_resources(struct ct_atc *atc)
 		daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
 		for (i = 0; i < atc->n_daio; i++) {
 			daio = atc->daios[i];
-			if (daio->type < LINEIM) {
+			if (daio->output) {
 				dao = container_of(daio, struct dao, daio);
 				dao->ops->clear_left_input(dao);
 				dao->ops->clear_right_input(dao);
@@ -1393,6 +1393,7 @@ static int atc_get_resources(struct ct_atc *atc)
 	for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
 		da_desc.type = (atc->model != CTSB073X) ? i :
 			     ((i == SPDIFIO) ? SPDIFI1 : i);
+		da_desc.output = i < LINEIM;
 		err = daio_mgr->get_daio(daio_mgr, &da_desc,
 					(struct daio **)&atc->daios[i]);
 		if (err) {
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index 10d0a7088718..f012d47689d1 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -18,8 +18,6 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
-#define DAIO_OUT_MAX		SPDIFOO
-
 struct daio_usage {
 	unsigned short data;
 };
@@ -329,7 +327,7 @@ static int daio_rsc_init(struct daio *daio,
 		goto error1;
 
 	/* Set daio->rscl/r->ops to daio specific ones */
-	if (desc->type <= DAIO_OUT_MAX) {
+	if (desc->output) {
 		daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;
 	} else {
 		switch (hw->chip_type) {
@@ -344,6 +342,7 @@ static int daio_rsc_init(struct daio *daio,
 		}
 	}
 	daio->type = desc->type;
+	daio->output = desc->output;
 
 	return 0;
 
@@ -433,6 +432,7 @@ static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc)
 	dsc.type = dao->daio.type;
 	dsc.msr = desc->msr;
 	dsc.passthru = desc->passthru;
+	dsc.output = dao->daio.output;
 	dao_rsc_uninit(dao);
 	return dao_rsc_init(dao, &dsc, mgr);
 }
@@ -518,7 +518,7 @@ static int get_daio_rsc(struct daio_mgr *mgr,
 
 	err = -ENOMEM;
 	/* Allocate mem for daio resource */
-	if (desc->type <= DAIO_OUT_MAX) {
+	if (desc->output) {
 		struct dao *dao = kzalloc(sizeof(*dao), GFP_KERNEL);
 		if (!dao)
 			goto error;
@@ -565,7 +565,7 @@ static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio)
 		daio_mgr_put_rsc(&mgr->mgr, daio->type);
 	}
 
-	if (daio->type <= DAIO_OUT_MAX) {
+	if (daio->output) {
 		dao_rsc_uninit(container_of(daio, struct dao, daio));
 		kfree(container_of(daio, struct dao, daio));
 	} else {
@@ -580,7 +580,7 @@ static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio)
 {
 	struct hw *hw = mgr->mgr.hw;
 
-	if (DAIO_OUT_MAX >= daio->type) {
+	if (daio->output) {
 		hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
 				daio_device_index(daio->type, hw));
 	} else {
@@ -594,7 +594,7 @@ static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio)
 {
 	struct hw *hw = mgr->mgr.hw;
 
-	if (DAIO_OUT_MAX >= daio->type) {
+	if (daio->output) {
 		hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
 				daio_device_index(daio->type, hw));
 	} else {
diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h
index 15147fe5f74a..b337da2de8b5 100644
--- a/sound/pci/ctxfi/ctdaio.h
+++ b/sound/pci/ctxfi/ctdaio.h
@@ -43,6 +43,7 @@ struct daio {
 	struct rsc rscl;	/* Basic resource info for left TX/RX */
 	struct rsc rscr;	/* Basic resource info for right TX/RX */
 	enum DAIOTYP type;
+	unsigned char output;
 };
 
 struct dao {
@@ -91,6 +92,7 @@ struct daio_desc {
 	unsigned int type:4;
 	unsigned int msr:4;
 	unsigned int passthru:1;
+	unsigned int output:1;
 };
 
 struct daio_mgr {
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 4/6] ALSA: ctxfi: Refactor resource alloc for sparse mappings
  2025-11-24 18:04 [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE Harin Lee
                   ` (2 preceding siblings ...)
  2025-11-24 18:04 ` [PATCH v3 3/6] ALSA: ctxfi: Use explicit output flag for DAIO resources Harin Lee
@ 2025-11-24 18:04 ` Harin Lee
  2025-11-24 18:05 ` [PATCH v3 5/6] ALSA: ctxfi: Add support for dedicated RCA switching Harin Lee
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Harin Lee @ 2025-11-24 18:04 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai; +Cc: linux-sound, linux-kernel, Harin Lee

Refactor atc_get_resources(), atc_connect_resources(), and
atc_release_resources() to allocate resources based on maximum type
definitions.

This allows specific resources to be conditionally skipped based on
capabilities. This is necessary for hardware variants where resource
allocations do not follow a sequential order.

Signed-off-by: Harin Lee <me@harin.net>
---
 sound/pci/ctxfi/ctatc.c | 60 ++++++++++++++++++++++++-----------------
 sound/pci/ctxfi/ctatc.h |  4 ---
 2 files changed, 35 insertions(+), 29 deletions(-)

diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index 55bbeb891afc..ce2b16722118 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -25,6 +25,9 @@
 #include <sound/control.h>
 #include <sound/asoundef.h>
 
+#define NUM_ATC_SRCS	6
+#define NUM_ATC_PCM		(2 * 4)
+
 #define MONO_SUM_SCALE	0x19a8	/* 2^(-0.5) in 14-bit floating format */
 #define MAX_MULTI_CHN	8
 
@@ -1161,8 +1164,10 @@ static int atc_release_resources(struct ct_atc *atc)
 
 	if (atc->daios) {
 		daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
-		for (i = 0; i < atc->n_daio; i++) {
+		for (i = 0; i < NUM_DAIOTYP; i++) {
 			daio = atc->daios[i];
+			if (!daio)
+				continue;
 			if (daio->output) {
 				dao = container_of(daio, struct dao, daio);
 				dao->ops->clear_left_input(dao);
@@ -1176,8 +1181,9 @@ static int atc_release_resources(struct ct_atc *atc)
 
 	if (atc->pcm) {
 		sum_mgr = atc->rsc_mgrs[SUM];
-		for (i = 0; i < atc->n_pcm; i++)
-			sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
+		for (i = 0; i < NUM_ATC_PCM; i++)
+			if (atc->pcm[i])
+				sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
 
 		kfree(atc->pcm);
 		atc->pcm = NULL;
@@ -1185,8 +1191,9 @@ static int atc_release_resources(struct ct_atc *atc)
 
 	if (atc->srcs) {
 		src_mgr = atc->rsc_mgrs[SRC];
-		for (i = 0; i < atc->n_src; i++)
-			src_mgr->put_src(src_mgr, atc->srcs[i]);
+		for (i = 0; i < NUM_ATC_SRCS; i++)
+			if (atc->srcs[i])
+				src_mgr->put_src(src_mgr, atc->srcs[i]);
 
 		kfree(atc->srcs);
 		atc->srcs = NULL;
@@ -1194,7 +1201,9 @@ static int atc_release_resources(struct ct_atc *atc)
 
 	if (atc->srcimps) {
 		srcimp_mgr = atc->rsc_mgrs[SRCIMP];
-		for (i = 0; i < atc->n_srcimp; i++) {
+		for (i = 0; i < NUM_ATC_SRCS; i++) {
+			if (!atc->srcimps[i])
+				continue;
 			srcimp = atc->srcimps[i];
 			srcimp->ops->unmap(srcimp);
 			srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
@@ -1367,30 +1376,32 @@ static int atc_get_resources(struct ct_atc *atc)
 	struct srcimp_mgr *srcimp_mgr;
 	struct sum_desc sum_dsc = {0};
 	struct sum_mgr *sum_mgr;
-	int err, i, num_srcs, num_daios;
+	struct capabilities cap;
+	int err, i;
 
-	num_daios = ((atc->model == CTSB1270) ? 8 : 7);
-	num_srcs = ((atc->model == CTSB1270) ? 6 : 4);
+	cap = atc->capabilities(atc);
 
-	atc->daios = kcalloc(num_daios, sizeof(void *), GFP_KERNEL);
+	atc->daios = kcalloc(NUM_DAIOTYP, sizeof(void *), GFP_KERNEL);
 	if (!atc->daios)
 		return -ENOMEM;
 
-	atc->srcs = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
+	atc->srcs = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL);
 	if (!atc->srcs)
 		return -ENOMEM;
 
-	atc->srcimps = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
+	atc->srcimps = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL);
 	if (!atc->srcimps)
 		return -ENOMEM;
 
-	atc->pcm = kcalloc(2 * 4, sizeof(void *), GFP_KERNEL);
+	atc->pcm = kcalloc(NUM_ATC_PCM, sizeof(void *), GFP_KERNEL);
 	if (!atc->pcm)
 		return -ENOMEM;
 
 	daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
 	da_desc.msr = atc->msr;
-	for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
+	for (i = 0; i < NUM_DAIOTYP; i++) {
+		if ((i == MIC) && !cap.dedicated_mic)
+			continue;
 		da_desc.type = (atc->model != CTSB073X) ? i :
 			     ((i == SPDIFIO) ? SPDIFI1 : i);
 		da_desc.output = i < LINEIM;
@@ -1402,42 +1413,39 @@ static int atc_get_resources(struct ct_atc *atc)
 				i);
 			return err;
 		}
-		atc->n_daio++;
 	}
 
 	src_mgr = atc->rsc_mgrs[SRC];
 	src_dsc.multi = 1;
 	src_dsc.msr = atc->msr;
 	src_dsc.mode = ARCRW;
-	for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
+	for (i = 0; i < NUM_ATC_SRCS; i++) {
+		if (((i > 3) && !cap.dedicated_mic))
+			continue;
 		err = src_mgr->get_src(src_mgr, &src_dsc,
 					(struct src **)&atc->srcs[i]);
 		if (err)
 			return err;
-
-		atc->n_src++;
 	}
 
 	srcimp_mgr = atc->rsc_mgrs[SRCIMP];
 	srcimp_dsc.msr = 8;
-	for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
+	for (i = 0; i < NUM_ATC_SRCS; i++) {
+		if (((i > 3) && !cap.dedicated_mic))
+			continue;
 		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
 					(struct srcimp **)&atc->srcimps[i]);
 		if (err)
 			return err;
-
-		atc->n_srcimp++;
 	}
 
 	sum_mgr = atc->rsc_mgrs[SUM];
 	sum_dsc.msr = atc->msr;
-	for (i = 0, atc->n_pcm = 0; i < (2*4); i++) {
+	for (i = 0; i < NUM_ATC_PCM; i++) {
 		err = sum_mgr->get_sum(sum_mgr, &sum_dsc,
 					(struct sum **)&atc->pcm[i]);
 		if (err)
 			return err;
-
-		atc->n_pcm++;
 	}
 
 	return 0;
@@ -1490,9 +1498,11 @@ static void atc_connect_resources(struct ct_atc *atc)
 	struct sum *sum;
 	struct ct_mixer *mixer;
 	struct rsc *rscs[2] = {NULL};
+	struct capabilities cap;
 	int i, j;
 
 	mixer = atc->mixer;
+	cap = atc->capabilities(atc);
 
 	for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) {
 		mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]);
@@ -1510,7 +1520,7 @@ static void atc_connect_resources(struct ct_atc *atc)
 	src = atc->srcs[3];
 	mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
 
-	if (atc->model == CTSB1270) {
+	if (cap.dedicated_mic) {
 		/* Titanium HD has a dedicated ADC for the Mic. */
 		dai = container_of(atc->daios[MIC], struct dai, daio);
 		atc_connect_dai(atc->rsc_mgrs[SRC], dai,
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
index 0bc7b71d910b..671edc46bd50 100644
--- a/sound/pci/ctxfi/ctatc.h
+++ b/sound/pci/ctxfi/ctatc.h
@@ -132,10 +132,6 @@ struct ct_atc {
 	void **pcm;		/* SUMs for collecting all pcm stream */
 	void **srcs;		/* Sample Rate Converters for input signal */
 	void **srcimps;		/* input mappers for SRCs */
-	unsigned char n_daio;
-	unsigned char n_src;
-	unsigned char n_srcimp;
-	unsigned char n_pcm;
 
 	struct ct_timer *timer;
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 5/6] ALSA: ctxfi: Add support for dedicated RCA switching
  2025-11-24 18:04 [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE Harin Lee
                   ` (3 preceding siblings ...)
  2025-11-24 18:04 ` [PATCH v3 4/6] ALSA: ctxfi: Refactor resource alloc for sparse mappings Harin Lee
@ 2025-11-24 18:05 ` Harin Lee
  2025-11-24 18:05 ` [PATCH v3 6/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE (OK0010) Harin Lee
  2025-11-25  7:02 ` [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE Takashi Iwai
  6 siblings, 0 replies; 8+ messages in thread
From: Harin Lee @ 2025-11-24 18:05 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai; +Cc: linux-sound, linux-kernel, Harin Lee

Add feature to support switching between the dedicated RCA output and
the 7.1ch Front output. This is required for hardware that utilizes
separate DAC circuits for RCA and 7.1ch channels.

Changes:
 - Add dedicated_rca capability flag
 - Add "Analog Playback Route" mixer control
 - Implement logic to swap DAO inputs between RCA and Front ports

Signed-off-by: Harin Lee <me@harin.net>
---
 sound/pci/ctxfi/ctatc.c      | 33 +++++++++++++++-
 sound/pci/ctxfi/ctatc.h      |  4 ++
 sound/pci/ctxfi/ctdaio.c     |  2 +
 sound/pci/ctxfi/ctdaio.h     |  1 +
 sound/pci/ctxfi/cthardware.h |  1 +
 sound/pci/ctxfi/cthw20k1.c   |  1 +
 sound/pci/ctxfi/cthw20k2.c   |  1 +
 sound/pci/ctxfi/ctmixer.c    | 73 ++++++++++++++++++++++++++++++++++--
 8 files changed, 111 insertions(+), 5 deletions(-)

diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index ce2b16722118..ff3694b3021e 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -987,6 +987,24 @@ static struct capabilities atc_capabilities(struct ct_atc *atc)
 	return hw->capabilities(hw);
 }
 
+static void atc_dedicated_rca_select(struct ct_atc *atc)
+{
+	struct dao *dao;
+	struct ct_mixer *mixer = atc->mixer;
+	struct rsc *rscs[2] = {NULL};
+
+	dao = container_of(atc->daios[atc->rca_state ? RCA : LINEO1],
+		struct dao, daio);
+	dao->ops->clear_left_input(dao);
+	dao->ops->clear_right_input(dao);
+
+	mixer->get_output_ports(mixer, MIX_WAVE_FRONT, &rscs[0], &rscs[1]);
+	dao = container_of(atc->daios[atc->rca_state ? LINEO1 : RCA],
+		struct dao, daio);
+	dao->ops->set_left_input(dao, rscs[0]);
+	dao->ops->set_right_input(dao, rscs[1]);
+}
+
 static int atc_output_switch_get(struct ct_atc *atc)
 {
 	struct hw *hw = atc->hw;
@@ -1088,6 +1106,11 @@ static int atc_mic_unmute(struct ct_atc *atc, unsigned char state)
 	return atc_daio_unmute(atc, state, MIC);
 }
 
+static int atc_rca_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, RCA);
+}
+
 static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
 {
 	return atc_daio_unmute(atc, state, SPDIFOO);
@@ -1303,6 +1326,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid)
 	dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n",
 		   atc->chip_name, atc->model_name,
 		   vendor_id, device_id);
+	atc->rca_state = 0;
 	return 0;
 }
 
@@ -1400,11 +1424,11 @@ static int atc_get_resources(struct ct_atc *atc)
 	daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
 	da_desc.msr = atc->msr;
 	for (i = 0; i < NUM_DAIOTYP; i++) {
-		if ((i == MIC) && !cap.dedicated_mic)
+		if (((i == MIC) && !cap.dedicated_mic) || ((i == RCA) && !cap.dedicated_rca))
 			continue;
 		da_desc.type = (atc->model != CTSB073X) ? i :
 			     ((i == SPDIFIO) ? SPDIFI1 : i);
-		da_desc.output = i < LINEIM;
+		da_desc.output = (i < LINEIM) || (i == RCA);
 		err = daio_mgr->get_daio(daio_mgr, &da_desc,
 					(struct daio **)&atc->daios[i]);
 		if (err) {
@@ -1511,6 +1535,9 @@ static void atc_connect_resources(struct ct_atc *atc)
 		dao->ops->set_right_input(dao, rscs[1]);
 	}
 
+	if (cap.dedicated_rca)
+		atc_dedicated_rca_select(atc);
+
 	dai = container_of(atc->daios[LINEIM], struct dai, daio);
 	atc_connect_dai(atc->rsc_mgrs[SRC], dai,
 			(struct src **)&atc->srcs[2],
@@ -1643,12 +1670,14 @@ static const struct ct_atc atc_preset = {
 	.line_rear_unmute = atc_line_rear_unmute,
 	.line_in_unmute = atc_line_in_unmute,
 	.mic_unmute = atc_mic_unmute,
+	.rca_unmute = atc_rca_unmute,
 	.spdif_out_unmute = atc_spdif_out_unmute,
 	.spdif_in_unmute = atc_spdif_in_unmute,
 	.spdif_out_get_status = atc_spdif_out_get_status,
 	.spdif_out_set_status = atc_spdif_out_set_status,
 	.spdif_out_passthru = atc_spdif_out_passthru,
 	.capabilities = atc_capabilities,
+	.dedicated_rca_select = atc_dedicated_rca_select,
 	.output_switch_get = atc_output_switch_get,
 	.output_switch_put = atc_output_switch_put,
 	.mic_source_switch_get = atc_mic_source_switch_get,
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
index 671edc46bd50..ca0a9d5b86d8 100644
--- a/sound/pci/ctxfi/ctatc.h
+++ b/sound/pci/ctxfi/ctatc.h
@@ -82,6 +82,8 @@ struct ct_atc {
 	const char *chip_name;
 	const char *model_name;
 
+	unsigned char rca_state; /* 0 = dedicated RCA, 1 = 7.1ch Front */
+
 	struct ct_vm *vm; /* device virtual memory manager for this card */
 	int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
 	void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
@@ -113,12 +115,14 @@ struct ct_atc {
 	int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*mic_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*rca_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
 	int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
 	int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
 	struct capabilities (*capabilities)(struct ct_atc *atc);
+	void (*dedicated_rca_select)(struct ct_atc *atc);
 	int (*output_switch_get)(struct ct_atc *atc);
 	int (*output_switch_put)(struct ct_atc *atc, int position);
 	int (*mic_source_switch_get)(struct ct_atc *atc);
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index f012d47689d1..1c8f8efd836c 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -45,6 +45,7 @@ static const struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
 	[LINEO4] = {.left = 0x70, .right = 0x71},
 	[LINEIM] = {.left = 0x45, .right = 0xc5},
 	[MIC]	 = {.left = 0x55, .right = 0xd5},
+	[RCA]	 = {.left = 0x30, .right = 0x31},
 	[SPDIFOO] = {.left = 0x00, .right = 0x01},
 	[SPDIFIO] = {.left = 0x05, .right = 0x85},
 };
@@ -123,6 +124,7 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
 		case LINEO4:	return 6;
 		case LINEIM:	return 4;
 		case MIC:	return 5;
+		case RCA:	return 3;
 		default:	return -EINVAL;
 		}
 	default:
diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h
index b337da2de8b5..99d55f19e3ca 100644
--- a/sound/pci/ctxfi/ctdaio.h
+++ b/sound/pci/ctxfi/ctdaio.h
@@ -31,6 +31,7 @@ enum DAIOTYP {
 	LINEIM,
 	SPDIFIO,	/* S/PDIF In (Flexijack/Optical) on the card */
 	MIC,		/* Dedicated mic on Titanium HD */
+	RCA,
 	SPDIFI1,	/* S/PDIF In on internal Drive Bay */
 	NUM_DAIOTYP
 };
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
index d29b4e5b3fcc..84ea690763e7 100644
--- a/sound/pci/ctxfi/cthardware.h
+++ b/sound/pci/ctxfi/cthardware.h
@@ -62,6 +62,7 @@ struct card_conf {
 struct capabilities {
 	unsigned int digit_io_switch:1;
 	unsigned int dedicated_mic:1;
+	unsigned int dedicated_rca:1;
 	unsigned int output_switch:1;
 	unsigned int mic_source_switch:1;
 };
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index 60cc1d14453a..ea0a928937b6 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1775,6 +1775,7 @@ static struct capabilities hw_capabilities(struct hw *hw)
 	/* SB073x and Vista compatible cards have no digit IO switch */
 	cap.digit_io_switch = !(hw->model == CTSB073X || hw->model == CTUAA);
 	cap.dedicated_mic = 0;
+	cap.dedicated_rca = 0;
 	cap.output_switch = 0;
 	cap.mic_source_switch = 0;
 
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 5d39bc943648..214a83977a70 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -1930,6 +1930,7 @@ static struct capabilities hw_capabilities(struct hw *hw)
 
 	cap.digit_io_switch = 0;
 	cap.dedicated_mic = hw->model == CTSB1270;
+	cap.dedicated_rca = 0;
 	cap.output_switch = hw->model == CTSB1270;
 	cap.mic_source_switch = hw->model == CTSB1270;
 
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index 496682613db5..fc9fde284fb3 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -547,8 +547,14 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
 		atc->mic_unmute(atc, state);
 	else if (MIXER_SPDIFI_C_S == type)
 		atc->spdif_in_unmute(atc, state);
-	else if (MIXER_WAVEF_P_S == type)
-		atc->line_front_unmute(atc, state);
+	else if (MIXER_WAVEF_P_S == type) {
+		if (cap.dedicated_rca) {
+			atc->rca_unmute(atc, atc->rca_state ? 0 : state);
+			atc->line_front_unmute(atc, atc->rca_state ? state : 0);
+		} else {
+			atc->line_front_unmute(atc, state);
+		}
+	}
 	else if (MIXER_WAVES_P_S == type)
 		atc->line_surround_unmute(atc, state);
 	else if (MIXER_WAVEC_P_S == type)
@@ -612,6 +618,57 @@ static struct snd_kcontrol_new swh_ctl = {
 	.put		= ct_alsa_mix_switch_put
 };
 
+static int dedicated_rca_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *info)
+{
+	static const char *const names[2] = {
+	  "RCA", "Front"
+	};
+
+	return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int dedicated_rca_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.enumerated.item[0] = atc->rca_state;
+	return 0;
+}
+
+static int dedicated_rca_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	unsigned int rca_state = ucontrol->value.enumerated.item[0];
+	unsigned char state;
+
+	if (rca_state > 1)
+		return -EINVAL;
+
+	if (rca_state == atc->rca_state)
+		return 0;
+
+	state = get_switch_state(atc->mixer, MIXER_WAVEF_P_S);
+	do_switch(atc, MIXER_WAVEF_P_S, 0);
+
+	atc->rca_state = rca_state;
+	atc->dedicated_rca_select(atc);
+
+	do_switch(atc, MIXER_WAVEF_P_S, state);
+
+	return 1;
+}
+
+static struct snd_kcontrol_new rca_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Analog Playback Route",
+	.info = dedicated_rca_info,
+	.get = dedicated_rca_get,
+	.put = dedicated_rca_put,
+};
+
 static int ct_spdif_info(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_info *uinfo)
 {
@@ -784,7 +841,17 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
 		if (err)
 			return err;
 	}
-	atc->line_front_unmute(atc, 1);
+
+	if (cap.dedicated_rca) {
+		err = ct_mixer_kcontrol_new(mixer, &rca_ctl);
+		if (err)
+			return err;
+
+		atc->line_front_unmute(atc, 0);
+		atc->rca_unmute(atc, 1);
+	} else {
+		atc->line_front_unmute(atc, 1);
+	}
 	set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
 	atc->line_surround_unmute(atc, 0);
 	set_switch_state(mixer, MIXER_WAVES_P_S, 0);
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 6/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE (OK0010)
  2025-11-24 18:04 [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE Harin Lee
                   ` (4 preceding siblings ...)
  2025-11-24 18:05 ` [PATCH v3 5/6] ALSA: ctxfi: Add support for dedicated RCA switching Harin Lee
@ 2025-11-24 18:05 ` Harin Lee
  2025-11-25  7:02 ` [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE Takashi Iwai
  6 siblings, 0 replies; 8+ messages in thread
From: Harin Lee @ 2025-11-24 18:05 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai; +Cc: linux-sound, linux-kernel, Harin Lee

Add support for the Onkyo SE-300PCIE, a Creative X-Fi CA20K2-based
sound card with a custom hardware implementation that differs
significantly from other CA20K2-based variants.

Changes:
 - PCI quirk entry for OK0010
 - Port 0x3 is utilized for dedicated RCA output (configured as I2S)
 - Modified GPIO pin mappings and states
 - 4-channel simultaneous ADC input support for line and microphone
   capture without input switching (similar to SB1270)
 - Simplified ADC initialization (no manual setup required)

Signed-off-by: Harin Lee <me@harin.net>
---
 sound/pci/ctxfi/ctatc.c      |  7 +++++-
 sound/pci/ctxfi/ctdaio.h     |  2 +-
 sound/pci/ctxfi/cthardware.h |  1 +
 sound/pci/ctxfi/cthw20k2.c   | 47 +++++++++++++++++++++++++++---------
 4 files changed, 43 insertions(+), 14 deletions(-)

diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index ff3694b3021e..227d8c8490e1 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -63,6 +63,7 @@ static const struct snd_pci_quirk subsys_20k2_list[] = {
 	SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000,
 			   PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX",
 			   CTHENDRIX),
+	SND_PCI_QUIRK(0x160b, 0x0101, "OK0010", CTOK0010),
 	{ } /* terminator */
 };
 
@@ -78,6 +79,7 @@ static const char *ct_subsys_name[NUM_CTCARDS] = {
 	[CTHENDRIX]	= "Hendrix",
 	[CTSB0880]	= "SB0880",
 	[CTSB1270]      = "SB1270",
+	[CTOK0010]    = "OK0010",
 	[CT20K2_UNKNOWN] = "Unknown",
 };
 
@@ -1535,8 +1537,10 @@ static void atc_connect_resources(struct ct_atc *atc)
 		dao->ops->set_right_input(dao, rscs[1]);
 	}
 
-	if (cap.dedicated_rca)
+	if (cap.dedicated_rca) {
+		/* SE-300PCIE has a dedicated DAC for the RCA. */
 		atc_dedicated_rca_select(atc);
+	}
 
 	dai = container_of(atc->daios[LINEIM], struct dai, daio);
 	atc_connect_dai(atc->rsc_mgrs[SRC], dai,
@@ -1549,6 +1553,7 @@ static void atc_connect_resources(struct ct_atc *atc)
 
 	if (cap.dedicated_mic) {
 		/* Titanium HD has a dedicated ADC for the Mic. */
+		/* SE-300PCIE has a 4-channel ADC. */
 		dai = container_of(atc->daios[MIC], struct dai, daio);
 		atc_connect_dai(atc->rsc_mgrs[SRC], dai,
 			(struct src **)&atc->srcs[4],
diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h
index 99d55f19e3ca..ff77d55539a5 100644
--- a/sound/pci/ctxfi/ctdaio.h
+++ b/sound/pci/ctxfi/ctdaio.h
@@ -31,7 +31,7 @@ enum DAIOTYP {
 	LINEIM,
 	SPDIFIO,	/* S/PDIF In (Flexijack/Optical) on the card */
 	MIC,		/* Dedicated mic on Titanium HD */
-	RCA,
+	RCA,		/* Dedicated RCA on SE-300PCIE */
 	SPDIFI1,	/* S/PDIF In on internal Drive Bay */
 	NUM_DAIOTYP
 };
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
index 84ea690763e7..a3051fdd31f6 100644
--- a/sound/pci/ctxfi/cthardware.h
+++ b/sound/pci/ctxfi/cthardware.h
@@ -38,6 +38,7 @@ enum CTCARDS {
 	CTHENDRIX,
 	CTSB0880,
 	CTSB1270,
+	CTOK0010,
 	CT20K2_UNKNOWN,
 	NUM_CTCARDS		/* This should always be the last */
 };
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 214a83977a70..fac88f5590c9 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -910,7 +910,7 @@ static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
 	struct dao_ctrl_blk *ctl = blk;
 
 	if (ctl->dirty.bf.atxcsl) {
-		if (idx < 4) {
+		if ((idx < 4) && ((hw->model != CTOK0010) || (idx < 3))) {
 			/* S/PDIF SPOSx */
 			hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+0x40*idx,
 							ctl->atxcsl);
@@ -985,11 +985,12 @@ static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
 	return 0;
 }
 
-static int daio_mgr_dao_init(struct hw *hw __maybe_unused, void *blk, unsigned int idx, unsigned int conf)
+static int daio_mgr_dao_init(struct hw *hw, void *blk, unsigned int idx, unsigned int conf)
 {
 	struct daio_mgr_ctrl_blk *ctl = blk;
 
-	if (idx < 4) {
+	/* Port 3 is dedicated to RCA on SE-300PCIE */
+	if ((idx < 4) && ((hw->model != CTOK0010) || (idx < 3))) {
 		/* S/PDIF output */
 		switch ((conf & 0xf)) {
 		case 1:
@@ -1176,6 +1177,10 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
 		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111);
 		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+	} else if ((4 == info->msr) && (hw->model == CTOK0010)) {
+		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21212121);
+		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
+		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
 	} else {
 		dev_alert(hw->card->dev,
 			  "ERROR!!! Invalid sampling rate!!!\n");
@@ -1183,7 +1188,8 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
 	}
 
 	for (i = 0; i < 8; i++) {
-		if (i <= 3) {
+		/* Port 3 is configured as I2S on SE-300PCIE */
+		if ((i < 4) && ((hw->model != CTOK0010) || (i < 3))) {
 			/* This comment looks wrong since loop is over 4  */
 			/* channels and emu20k2 supports 4 spdif IOs.     */
 			/* 1st 3 channels are SPDIFs (SB0960) */
@@ -1637,6 +1643,13 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
 		hw_write_20kx(hw, GPIO_DATA, data);
 		hw_dac_start(hw);
 		return 0;
+	} else if (hw->model == CTOK0010) {
+		hw_dac_stop(hw);
+		data = hw_read_20kx(hw, GPIO_DATA);
+		data |= 0x1000;
+		hw_write_20kx(hw, GPIO_DATA, data);
+		hw_dac_start(hw);
+		return 0;
 	}
 
 	/* Set DAC reset bit as output */
@@ -1756,9 +1769,11 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
 static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
 {
 	u32 data;
-	if (hw->model == CTSB1270) {
+	if ((hw->model == CTSB1270) || (hw->model == CTOK0010)) {
 		/* Titanium HD has two ADC chips, one for line in and one */
-		/* for MIC. We don't need to switch the ADC input. */
+		/* for MIC. Also, SE-300PCIE has a single ADC chip that */
+		/* simultaneously supports 4-channel input. We don't need */
+		/* to switch the ADC input. */
 		return 1;
 	}
 	data = hw_read_20kx(hw, GPIO_DATA);
@@ -1846,7 +1861,7 @@ static void hw_adc_start(struct hw *hw)
 	msleep(50);
 }
 
-static void __maybe_unused hw_adc_reset(struct hw *hw)
+static void hw_adc_reset(struct hw *hw)
 {
 	hw_adc_stop(hw);
 	hw_adc_start(hw);
@@ -1862,6 +1877,12 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 	data |= (0x1 << 15);
 	hw_write_20kx(hw, GPIO_CTRL, data);
 
+	if (hw->model == CTOK0010) {
+		/* Manual ADC setup for SE-300PCIE is not needed. */
+		hw_adc_reset(hw);
+		return 0;
+	}
+
 	/* Initialize I2C */
 	err = hw20k2_i2c_init(hw, 0x1A, 1, 1);
 	if (err < 0) {
@@ -1929,8 +1950,8 @@ static struct capabilities hw_capabilities(struct hw *hw)
 	struct capabilities cap;
 
 	cap.digit_io_switch = 0;
-	cap.dedicated_mic = hw->model == CTSB1270;
-	cap.dedicated_rca = 0;
+	cap.dedicated_mic = (hw->model == CTSB1270) || (hw->model == CTOK0010);
+	cap.dedicated_rca = hw->model == CTOK0010;
 	cap.output_switch = hw->model == CTSB1270;
 	cap.mic_source_switch = hw->model == CTSB1270;
 
@@ -2167,15 +2188,17 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
 	/* Reset all SRC pending interrupts */
 	hw_write_20kx(hw, SRC_IP, 0);
 
-	if (hw->model != CTSB1270) {
+	if (hw->model == CTSB1270) {
+		hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
+	} else if (hw->model == CTOK0010) {
+		hw_write_20kx(hw, GPIO_CTRL, 0x9902);
+	} else {
 		/* TODO: detect the card ID and configure GPIO accordingly. */
 		/* Configures GPIO (0xD802 0x98028) */
 		/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
 		/* Configures GPIO (SB0880) */
 		/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
 		hw_write_20kx(hw, GPIO_CTRL, 0xD802);
-	} else {
-		hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
 	}
 	/* Enable audio ring */
 	hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE
  2025-11-24 18:04 [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE Harin Lee
                   ` (5 preceding siblings ...)
  2025-11-24 18:05 ` [PATCH v3 6/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE (OK0010) Harin Lee
@ 2025-11-25  7:02 ` Takashi Iwai
  6 siblings, 0 replies; 8+ messages in thread
From: Takashi Iwai @ 2025-11-25  7:02 UTC (permalink / raw)
  To: Harin Lee; +Cc: Jaroslav Kysela, Takashi Iwai, linux-sound, linux-kernel

On Mon, 24 Nov 2025 19:04:55 +0100,
Harin Lee wrote:
> 
> I added support for the Onkyo SE-300PCIE (OK0010), a Creative X-Fi
> CA20K2-based sound card with dual TI PCM1798 DACs, a single TI PCM1681
> DAC for 7.1ch output, and a CS5364 ADC. This model differs
> significantly from other CA20K2-based variants.
> 
> Since official driver support for this hardware was discontinued a long
> time ago, this patch series enables the card to be used on modern
> platforms.
> 
> This patch series was developed using QEMU vfio tracing, and PCIe BAR
> dumps. Tested with analog output (up to 192kHz) and line/microphone
> input (up to 96kHz) at various sample rates.
> 
> Changes in v3:
>  - Patch 5: Rename ALSA mixer control to "Analog Playback Route" as
>    suggested by the maintainer
>  - Patch 5: Fix 'rca_state' type to 'unsigned int' in
>    dedicated_rca_put()
>  - Patch 6: Add comments explaining the port mapping logic for
>    SE-300PCIE
> 
> Harin Lee (6):
>   ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init()
>   ALSA: ctxfi: Add ADC helper functions for GPIO
>   ALSA: ctxfi: Use explicit output flag for DAIO resources
>   ALSA: ctxfi: Refactor resource alloc for sparse mappings
>   ALSA: ctxfi: Add support for dedicated RCA switching
>   ALSA: ctxfi: Add support for Onkyo SE-300PCIE (OK0010)

All six patches applied to for-next branch now.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-11-25  7:02 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-24 18:04 [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE Harin Lee
2025-11-24 18:04 ` [PATCH v3 1/6] ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init() Harin Lee
2025-11-24 18:04 ` [PATCH v3 2/6] ALSA: ctxfi: Add ADC helper functions for GPIO Harin Lee
2025-11-24 18:04 ` [PATCH v3 3/6] ALSA: ctxfi: Use explicit output flag for DAIO resources Harin Lee
2025-11-24 18:04 ` [PATCH v3 4/6] ALSA: ctxfi: Refactor resource alloc for sparse mappings Harin Lee
2025-11-24 18:05 ` [PATCH v3 5/6] ALSA: ctxfi: Add support for dedicated RCA switching Harin Lee
2025-11-24 18:05 ` [PATCH v3 6/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE (OK0010) Harin Lee
2025-11-25  7:02 ` [PATCH v3 0/6] ALSA: ctxfi: Add support for Onkyo SE-300PCIE Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox