* [PATCH v3 02/16] ALSA: Oxygen: Modify the SPI writing function
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-17 15:08 ` [PATCH v3 03/16] ALSA: Oxygen: Add mute mask for the OXYGEN_PLAY_ROUTING register Roman Volkov
` (14 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
The SPI writing function modified to use the new
waiting function. Return value changed from void
to int, so it can return error codes. Older drivers
just ignore that return value, the Xonar DG/DGX
driver handles this value. We need to wait AFTER
initiating the SPI transaction, otherwise read
operation will not work.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/oxygen.h | 2 +-
sound/pci/oxygen/oxygen_io.c | 15 ++++-----------
2 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index 09a24b2..c10ab07 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -198,7 +198,7 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec,
void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
unsigned int index, u16 data, u16 mask);
-void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
+int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
void oxygen_reset_uart(struct oxygen *chip);
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index a917f37..fb9c826 100644
--- a/sound/pci/oxygen/oxygen_io.c
+++ b/sound/pci/oxygen/oxygen_io.c
@@ -209,23 +209,16 @@ static int oxygen_wait_spi(struct oxygen *chip)
return -EIO;
}
-void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
+int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
{
- unsigned int count;
-
- /* should not need more than 30.72 us (24 * 1.28 us) */
- count = 10;
- while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY)
- && count > 0) {
- udelay(4);
- --count;
- }
-
+ /* We need to wait AFTER initiating the SPI transaction,
+ otherwise read operations will not work */
oxygen_write8(chip, OXYGEN_SPI_DATA1, data);
oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8);
if (control & OXYGEN_SPI_DATA_LENGTH_3)
oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16);
oxygen_write8(chip, OXYGEN_SPI_CONTROL, control);
+ return oxygen_wait_spi(chip);
}
EXPORT_SYMBOL(oxygen_write_spi);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 03/16] ALSA: Oxygen: Add mute mask for the OXYGEN_PLAY_ROUTING register
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
2014-01-17 15:08 ` [PATCH v3 02/16] ALSA: Oxygen: Modify the SPI writing function Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-17 15:08 ` [PATCH v3 04/16] ALSA: Oxygen: Add CS4245_SPI_READ constant Roman Volkov
` (13 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
The Xonar DG/DGX driver needs this mask to mute unnecessary
channels.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/oxygen_regs.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h
index 63dc7a0..8c191ba 100644
--- a/sound/pci/oxygen/oxygen_regs.h
+++ b/sound/pci/oxygen/oxygen_regs.h
@@ -318,6 +318,7 @@
#define OXYGEN_PLAY_MUTE23 0x0002
#define OXYGEN_PLAY_MUTE45 0x0004
#define OXYGEN_PLAY_MUTE67 0x0008
+#define OXYGEN_PLAY_MUTE_MASK 0x000f
#define OXYGEN_PLAY_MULTICH_MASK 0x0010
#define OXYGEN_PLAY_MULTICH_I2S_DAC 0x0000
#define OXYGEN_PLAY_MULTICH_AC97 0x0010
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 04/16] ALSA: Oxygen: Add CS4245_SPI_READ constant
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
2014-01-17 15:08 ` [PATCH v3 02/16] ALSA: Oxygen: Modify the SPI writing function Roman Volkov
2014-01-17 15:08 ` [PATCH v3 03/16] ALSA: Oxygen: Add mute mask for the OXYGEN_PLAY_ROUTING register Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-18 10:29 ` Clemens Ladisch
2014-01-17 15:08 ` [PATCH v3 05/16] ALSA: Oxygen: Export oxygen_update_dac_routing symbol Roman Volkov
` (12 subsequent siblings)
15 siblings, 1 reply; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
The driver needs this constant to perform SPI read operations.
The shift from CS4245_SPI_ADDRESS and CS4245_SPI_WRITE constants
removed, since when we need to send two bytes instead of three
in the SPI packet, we need to shift left by 8 instead of 16.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/cs4245.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sound/pci/oxygen/cs4245.h b/sound/pci/oxygen/cs4245.h
index 5e0197e..3dd487a 100644
--- a/sound/pci/oxygen/cs4245.h
+++ b/sound/pci/oxygen/cs4245.h
@@ -103,5 +103,6 @@
#define CS4245_ADC_UNDRFL 0x01
-#define CS4245_SPI_ADDRESS (0x9e << 16)
-#define CS4245_SPI_WRITE (0 << 16)
+#define CS4245_SPI_ADDRESS 0x9e
+#define CS4245_SPI_WRITE 0
+#define CS4245_SPI_READ 1
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH v3 04/16] ALSA: Oxygen: Add CS4245_SPI_READ constant
2014-01-17 15:08 ` [PATCH v3 04/16] ALSA: Oxygen: Add CS4245_SPI_READ constant Roman Volkov
@ 2014-01-18 10:29 ` Clemens Ladisch
0 siblings, 0 replies; 24+ messages in thread
From: Clemens Ladisch @ 2014-01-18 10:29 UTC (permalink / raw)
To: Roman Volkov; +Cc: alsa-devel
Roman Volkov wrote:
> The driver needs this constant to perform SPI read operations.
> The shift from CS4245_SPI_ADDRESS and CS4245_SPI_WRITE constants
> removed, since when we need to send two bytes instead of three
> in the SPI packet, we need to shift left by 8 instead of 16.
>
> -#define CS4245_SPI_ADDRESS (0x9e << 16)
> -#define CS4245_SPI_WRITE (0 << 16)
> +#define CS4245_SPI_ADDRESS 0x9e
> +#define CS4245_SPI_WRITE 0
This change alone breaks the driver.
All patches must be self-contained, which is important to be able to
apply the patch series partially during debugging.
Please merge this with the patch that changes the SPI code.
Regards,
Clemens
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v3 05/16] ALSA: Oxygen: Export oxygen_update_dac_routing symbol
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (2 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 04/16] ALSA: Oxygen: Add CS4245_SPI_READ constant Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-17 15:08 ` [PATCH v3 06/16] ALSA: Oxygen: Change description of the xonar_dg.c file Roman Volkov
` (11 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
When the user switches stereo output to multichannel or vice versa,
the driver needs to update the channel routing. Instead of
creating additional subroutines, I better export existing
oxygen_update_dac_routing symbol from the oxygen mixer
and call this function. It calls model.adjust_dac_routing()
and my function does the work.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/oxygen_mixer.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index c0dbb52..5988e04 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -190,6 +190,7 @@ void oxygen_update_dac_routing(struct oxygen *chip)
if (chip->model.update_center_lfe_mix)
chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2);
}
+EXPORT_SYMBOL(oxygen_update_dac_routing);
static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
{
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 06/16] ALSA: Oxygen: Change description of the xonar_dg.c file
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (3 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 05/16] ALSA: Oxygen: Export oxygen_update_dac_routing symbol Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-17 15:08 ` [PATCH v3 07/16] ALSA: Oxygen: Additional definitions for the Xonar DG/DGX card Roman Volkov
` (10 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
Some additional information in comments and my copyright added.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/xonar_dg.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index 77acd79..b806cc1 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -1,8 +1,8 @@
/*
- * card driver for the Xonar DG/DGX
+ * Card driver for the Xonar DG/DGX
*
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- *
+ * Copyright (c) Roman Volkov <v1ron@mail.ru>
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.
@@ -20,27 +20,35 @@
* Xonar DG/DGX
* ------------
*
+ * CS4245 and CS4361 both will mute all outputs if any clock ratio
+ * is invalid.
+ *
* CMI8788:
*
* SPI 0 -> CS4245
*
+ * Playback:
* I²S 1 -> CS4245
* I²S 2 -> CS4361 (center/LFE)
* I²S 3 -> CS4361 (surround)
* I²S 4 -> CS4361 (front)
+ * Capture:
+ * I²S ADC 1 <- CS4245
*
* GPIO 3 <- ?
* GPIO 4 <- headphone detect
- * GPIO 5 -> route input jack to line-in (0) or mic-in (1)
- * GPIO 6 -> route input jack to line-in (0) or mic-in (1)
- * GPIO 7 -> enable rear headphone amp
+ * GPIO 5 -> enable ADC analog circuit for the left channel
+ * GPIO 6 -> enable ADC analog circuit for the right channel
+ * GPIO 7 -> switch green rear output jack between CS4245 and
+ * and the first channel of CS4361 (mechanical relay)
* GPIO 8 -> enable output to speakers
*
* CS4245:
*
+ * input 0 <- mic
* input 1 <- aux
* input 2 <- front mic
- * input 4 <- line/mic
+ * input 4 <- line
* DAC out -> headphones
* aux out -> front panel headphones
*/
--
1.7.10.4
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 07/16] ALSA: Oxygen: Additional definitions for the Xonar DG/DGX card
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (4 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 06/16] ALSA: Oxygen: Change description of the xonar_dg.c file Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-17 15:08 ` [PATCH v3 08/16] ALSA: Oxygen: Add new CS4245 SPI functions Roman Volkov
` (9 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
Some additional constants added to the xonar_dg.h file:
capture and playback sources. GPIO_* constants and the
dg struct moved to the header file from the xonar_dg.c file.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/xonar_dg.c | 14 --------------
sound/pci/oxygen/xonar_dg.h | 23 +++++++++++++++++++++++
2 files changed, 23 insertions(+), 14 deletions(-)
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index b806cc1..2a0ad6e 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -64,20 +64,6 @@
#include "xonar_dg.h"
#include "cs4245.h"
-#define GPIO_MAGIC 0x0008
-#define GPIO_HP_DETECT 0x0010
-#define GPIO_INPUT_ROUTE 0x0060
-#define GPIO_HP_REAR 0x0080
-#define GPIO_OUTPUT_ENABLE 0x0100
-
-struct dg {
- unsigned int output_sel;
- s8 input_vol[4][2];
- unsigned int input_sel;
- u8 hp_vol_att;
- u8 cs4245_regs[0x11];
-};
-
static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
{
struct dg *data = chip->model_data;
diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h
index 5688d78..0812692 100644
--- a/sound/pci/oxygen/xonar_dg.h
+++ b/sound/pci/oxygen/xonar_dg.h
@@ -3,6 +3,29 @@
#include "oxygen.h"
+#define GPIO_MAGIC 0x0008
+#define GPIO_HP_DETECT 0x0010
+#define GPIO_INPUT_ROUTE 0x0060
+#define GPIO_HP_REAR 0x0080
+#define GPIO_OUTPUT_ENABLE 0x0100
+
+#define CAPTURE_SRC_MIC 0
+#define CAPTURE_SRC_FP_MIC 1
+#define CAPTURE_SRC_LINE 2
+#define CAPTURE_SRC_AUX 3
+
+#define PLAYBACK_DST_HP 0
+#define PLAYBACK_DST_HP_FP 1
+#define PLAYBACK_DST_MULTICH 2
+
+struct dg {
+ unsigned int output_sel;
+ s8 input_vol[4][2];
+ unsigned int input_sel;
+ u8 hp_vol_att;
+ u8 cs4245_regs[0x11];
+};
+
extern struct oxygen_model model_xonar_dg;
#endif
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 08/16] ALSA: Oxygen: Add new CS4245 SPI functions
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (5 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 07/16] ALSA: Oxygen: Additional definitions for the Xonar DG/DGX card Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-18 10:36 ` Clemens Ladisch
2014-01-17 15:08 ` [PATCH v3 09/16] ALSA: Oxygen: Modify initialization functions Roman Volkov
` (8 subsequent siblings)
15 siblings, 1 reply; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
The existing write function slightly changed. The new
read function added. This read function used for creating
initial registers dump and may be used for debugging
purposes. SPI operations are cached, so there is a new
function to work with the cache (shadow).
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/xonar_dg.c | 60 +++++++++++++++++++++++++++++++++++++++++++
sound/pci/oxygen/xonar_dg.h | 7 +++++
2 files changed, 67 insertions(+)
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index 2a0ad6e..0a8ebe1 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -64,6 +64,66 @@
#include "xonar_dg.h"
#include "cs4245.h"
+int cs4245_write_spi(struct oxygen *chip, u8 reg)
+{
+ struct dg *data = chip->model_data;
+ register unsigned int packet;
+
+ packet = (u32)reg;
+ packet <<= 8;
+ packet |= (CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 16;
+ packet |= data->cs4245_shadow[reg];
+
+ return oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+ OXYGEN_SPI_DATA_LENGTH_3 |
+ OXYGEN_SPI_CLOCK_1280 |
+ (0 << OXYGEN_SPI_CODEC_SHIFT) |
+ OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
+ packet);
+}
+
+int cs4245_read_spi(struct oxygen *chip, u8 addr)
+{
+ struct dg *data = chip->model_data;
+ int ret;
+
+ ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+ OXYGEN_SPI_DATA_LENGTH_2 |
+ OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
+ OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
+ ((CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 8) | addr);
+ if (ret < 0)
+ return ret;
+
+ ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+ OXYGEN_SPI_DATA_LENGTH_2 |
+ OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
+ OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
+ (CS4245_SPI_ADDRESS | CS4245_SPI_READ) << 8);
+ if (ret < 0)
+ return ret;
+
+ data->cs4245_shadow[addr] = oxygen_read8(chip, OXYGEN_SPI_DATA1);
+
+ return 0;
+}
+
+int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op)
+{
+ unsigned char addr;
+ int ret;
+
+ for (addr = 1; addr < ARRAY_SIZE((((struct dg *)0)->cs4245_shadow));
+ addr++) {
+ ret = (op == CS4245_SAVE_TO_SHADOW ?
+ cs4245_read_spi(chip, addr) :
+ cs4245_write_spi(chip, addr));
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
{
struct dg *data = chip->model_data;
diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h
index 0812692..f861a4c 100644
--- a/sound/pci/oxygen/xonar_dg.h
+++ b/sound/pci/oxygen/xonar_dg.h
@@ -18,7 +18,14 @@
#define PLAYBACK_DST_HP_FP 1
#define PLAYBACK_DST_MULTICH 2
+enum cs4245_shadow_operation {
+ CS4245_SAVE_TO_SHADOW,
+ CS4245_LOAD_FROM_SHADOW
+};
+
struct dg {
+ /* The shadow copy of the CS4245 register space */
+ unsigned char cs4245_shadow[17];
unsigned int output_sel;
s8 input_vol[4][2];
unsigned int input_sel;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 09/16] ALSA: Oxygen: Modify initialization functions
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (6 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 08/16] ALSA: Oxygen: Add new CS4245 SPI functions Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-18 10:50 ` Clemens Ladisch
2014-01-17 15:08 ` [PATCH v3 10/16] ALSA: Oxygen: Modify DAC/ADC parameters function Roman Volkov
` (7 subsequent siblings)
15 siblings, 1 reply; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
Changes in GPIO values and sequence at startup, CS4245
initialization changed and simplified, according to
datasheets and reverse-engineering information.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/xonar_dg.c | 88 ++++++++++++++++---------------------------
1 file changed, 33 insertions(+), 55 deletions(-)
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index 0a8ebe1..d6a8c72 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -147,50 +147,31 @@ static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value)
cs4245_write(chip, reg, value);
}
-static void cs4245_registers_init(struct oxygen *chip)
-{
- struct dg *data = chip->model_data;
-
- cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN);
- cs4245_write(chip, CS4245_DAC_CTRL_1,
- data->cs4245_regs[CS4245_DAC_CTRL_1]);
- cs4245_write(chip, CS4245_ADC_CTRL,
- data->cs4245_regs[CS4245_ADC_CTRL]);
- cs4245_write(chip, CS4245_SIGNAL_SEL,
- data->cs4245_regs[CS4245_SIGNAL_SEL]);
- cs4245_write(chip, CS4245_PGA_B_CTRL,
- data->cs4245_regs[CS4245_PGA_B_CTRL]);
- cs4245_write(chip, CS4245_PGA_A_CTRL,
- data->cs4245_regs[CS4245_PGA_A_CTRL]);
- cs4245_write(chip, CS4245_ANALOG_IN,
- data->cs4245_regs[CS4245_ANALOG_IN]);
- cs4245_write(chip, CS4245_DAC_A_CTRL,
- data->cs4245_regs[CS4245_DAC_A_CTRL]);
- cs4245_write(chip, CS4245_DAC_B_CTRL,
- data->cs4245_regs[CS4245_DAC_B_CTRL]);
- cs4245_write(chip, CS4245_DAC_CTRL_2,
- CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC);
- cs4245_write(chip, CS4245_INT_MASK, 0);
- cs4245_write(chip, CS4245_POWER_CTRL, 0);
-}
-
static void cs4245_init(struct oxygen *chip)
{
struct dg *data = chip->model_data;
- data->cs4245_regs[CS4245_DAC_CTRL_1] =
- CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
- data->cs4245_regs[CS4245_ADC_CTRL] =
- CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
- data->cs4245_regs[CS4245_SIGNAL_SEL] =
- CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH;
- data->cs4245_regs[CS4245_PGA_B_CTRL] = 0;
- data->cs4245_regs[CS4245_PGA_A_CTRL] = 0;
- data->cs4245_regs[CS4245_ANALOG_IN] =
- CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4;
- data->cs4245_regs[CS4245_DAC_A_CTRL] = 0;
- data->cs4245_regs[CS4245_DAC_B_CTRL] = 0;
- cs4245_registers_init(chip);
+ /* Save the initial state: codec version, registers */
+ cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW);
+
+ /*
+ * Power up the CODEC internals, enable soft ramp & zero cross, work
+ * in async. mode,
+ * Enable aux output from DAC. Invert DAC output as in the Windows
+ * driver
+ */
+ data->cs4245_shadow[CS4245_POWER_CTRL] = 0;
+ data->cs4245_shadow[CS4245_SIGNAL_SEL] = CS4245_A_OUT_SEL_DAC |
+ CS4245_ASYNCH;
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] = 0;
+ data->cs4245_shadow[CS4245_DAC_CTRL_2] = CS4245_DAC_SOFT |
+ CS4245_DAC_ZERO | CS4245_INVERT_DAC;
+ data->cs4245_shadow[CS4245_ADC_CTRL] = 0;
+ data->cs4245_shadow[CS4245_ANALOG_IN] = CS4245_PGA_SOFT |
+ CS4245_PGA_ZERO;
+
+ cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
+
snd_component_add(chip->card, "CS4245");
}
@@ -200,23 +181,20 @@ static void dg_output_enable(struct oxygen *chip)
oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
}
-static void dg_init(struct oxygen *chip)
+void dg_init(struct oxygen *chip)
{
- struct dg *data = chip->model_data;
-
- data->output_sel = 0;
- data->input_sel = 3;
- data->hp_vol_att = 2 * 16;
+ /*
+ * The pin XGPIO1 as XGPIO1, gpios 8,7,6,5,1,0 as outputs.
+ */
cs4245_init(chip);
-
- oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
- GPIO_MAGIC | GPIO_HP_DETECT);
- oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
- GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE);
- oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
- GPIO_INPUT_ROUTE | GPIO_HP_REAR);
- dg_output_enable(chip);
+ oxygen_write16(chip, OXYGEN_GPIO_CONTROL, GPIO_OUTPUT_ENABLE |
+ GPIO_HP_REAR | GPIO_INPUT_ROUTE);
+ oxygen_write16(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR | GPIO_INPUT_ROUTE);
+ /* Anti-pop delay */
+ msleep(2500);
+ oxygen_write16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE |
+ GPIO_HP_REAR | GPIO_INPUT_ROUTE);
}
static void dg_cleanup(struct oxygen *chip)
@@ -231,7 +209,7 @@ static void dg_suspend(struct oxygen *chip)
static void dg_resume(struct oxygen *chip)
{
- cs4245_registers_init(chip);
+ /*cs4245_registers_init(chip);*/
dg_output_enable(chip);
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH v3 09/16] ALSA: Oxygen: Modify initialization functions
2014-01-17 15:08 ` [PATCH v3 09/16] ALSA: Oxygen: Modify initialization functions Roman Volkov
@ 2014-01-18 10:50 ` Clemens Ladisch
2014-01-20 14:14 ` Roman Volkov
0 siblings, 1 reply; 24+ messages in thread
From: Clemens Ladisch @ 2014-01-18 10:50 UTC (permalink / raw)
To: Roman Volkov; +Cc: alsa-devel
Roman Volkov wrote:
> Changes in GPIO values and sequence at startup, CS4245
> initialization changed and simplified, according to
> datasheets and reverse-engineering information.
>
> static void cs4245_init(struct oxygen *chip)
> {
> struct dg *data = chip->model_data;
>
> - data->cs4245_regs[CS4245_DAC_CTRL_1] =
> - CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
> - data->cs4245_regs[CS4245_ADC_CTRL] =
> - CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
> - data->cs4245_regs[CS4245_SIGNAL_SEL] =
> - CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH;
> - data->cs4245_regs[CS4245_PGA_B_CTRL] = 0;
> - data->cs4245_regs[CS4245_PGA_A_CTRL] = 0;
> - data->cs4245_regs[CS4245_ANALOG_IN] =
> - CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4;
> - data->cs4245_regs[CS4245_DAC_A_CTRL] = 0;
> - data->cs4245_regs[CS4245_DAC_B_CTRL] = 0;
> - cs4245_registers_init(chip);
> + /* Save the initial state: codec version, registers */
> + cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW);
> +
> + data->cs4245_shadow[CS4245_POWER_CTRL] = 0;
> + data->cs4245_shadow[CS4245_SIGNAL_SEL] = CS4245_A_OUT_SEL_DAC |
> + CS4245_ASYNCH;
> + data->cs4245_shadow[CS4245_DAC_CTRL_1] = 0;
> + data->cs4245_shadow[CS4245_DAC_CTRL_2] = CS4245_DAC_SOFT |
> + CS4245_DAC_ZERO | CS4245_INVERT_DAC;
> + data->cs4245_shadow[CS4245_ADC_CTRL] = 0;
> + data->cs4245_shadow[CS4245_ANALOG_IN] = CS4245_PGA_SOFT |
> + CS4245_PGA_ZERO;
Please don't remove symbols like "CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST";
this would imply that you don't care about these settings.
Why don't you initialize registers like PGA/DAC_A/B?
> +void dg_init(struct oxygen *chip)
> {
> - data->output_sel = 0;
> - data->input_sel = 3;
> - data->hp_vol_att = 2 * 16;
These initializations should not be removed until all the other code
that uses them is also removed.
> - oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
> - GPIO_INPUT_ROUTE | GPIO_HP_REAR);
> + oxygen_write16(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR | GPIO_INPUT_ROUTE);
Why are these bits now initialized to the opposite value?
Regards,
Clemens
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH v3 09/16] ALSA: Oxygen: Modify initialization functions
2014-01-18 10:50 ` Clemens Ladisch
@ 2014-01-20 14:14 ` Roman Volkov
0 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-20 14:14 UTC (permalink / raw)
To: Clemens Ladisch; +Cc: alsa-devel
В Sat, 18 Jan 2014 11:50:52 +0100
Clemens Ladisch <clemens@ladisch.de> пишет:
> Roman Volkov wrote:
> > Changes in GPIO values and sequence at startup, CS4245
> > initialization changed and simplified, according to
> > datasheets and reverse-engineering information.
> >
> > static void cs4245_init(struct oxygen *chip)
> > {
> > struct dg *data = chip->model_data;
> >
> > - data->cs4245_regs[CS4245_DAC_CTRL_1] =
> > - CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
> > - data->cs4245_regs[CS4245_ADC_CTRL] =
> > - CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
> > - data->cs4245_regs[CS4245_SIGNAL_SEL] =
> > - CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH;
> > - data->cs4245_regs[CS4245_PGA_B_CTRL] = 0;
> > - data->cs4245_regs[CS4245_PGA_A_CTRL] = 0;
> > - data->cs4245_regs[CS4245_ANALOG_IN] =
> > - CS4245_PGA_SOFT | CS4245_PGA_ZERO |
> > CS4245_SEL_INPUT_4;
> > - data->cs4245_regs[CS4245_DAC_A_CTRL] = 0;
> > - data->cs4245_regs[CS4245_DAC_B_CTRL] = 0;
> > - cs4245_registers_init(chip);
> > + /* Save the initial state: codec version, registers */
> > + cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW);
> > +
> > + data->cs4245_shadow[CS4245_POWER_CTRL] = 0;
> > + data->cs4245_shadow[CS4245_SIGNAL_SEL] =
> > CS4245_A_OUT_SEL_DAC |
> > + CS4245_ASYNCH;
> > + data->cs4245_shadow[CS4245_DAC_CTRL_1] = 0;
> > + data->cs4245_shadow[CS4245_DAC_CTRL_2] = CS4245_DAC_SOFT |
> > + CS4245_DAC_ZERO | CS4245_INVERT_DAC;
> > + data->cs4245_shadow[CS4245_ADC_CTRL] = 0;
> > + data->cs4245_shadow[CS4245_ANALOG_IN] = CS4245_PGA_SOFT |
> > + CS4245_PGA_ZERO;
>
> Please don't remove symbols like "CS4245_DAC_FM_SINGLE |
> CS4245_DAC_DIF_LJUST"; this would imply that you don't care about
> these settings.
Okay, will remain these settings. It is better to configure them
manually.
> Why don't you initialize registers like PGA/DAC_A/B?
If you meant volume control, the mixer performs initialization of these
settings. Probably they can be initalized to 30% volume, 100% by
default.
> > - oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
> > - GPIO_INPUT_ROUTE | GPIO_HP_REAR);
> > + oxygen_write16(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR |
> > GPIO_INPUT_ROUTE);
>
> Why are these bits now initialized to the opposite value?
>
As I can recall, if GPIOs 5,6 are cleared, the audio input will be
inactive and we can't record anything. HP_REAR switches CS4245 to the
rear jack. I tried any sequences to minimize clicks\pops. Will try to
don't touch the GPIO_HP_REAR, perhaps this reduce the number of relay
switches at startup.
>
> Regards,
> Clemens
>
--
Kind regards,
Roman Volkov,
v1ron@mail.ru
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v3 10/16] ALSA: Oxygen: Modify DAC/ADC parameters function
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (7 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 09/16] ALSA: Oxygen: Modify initialization functions Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-17 15:08 ` [PATCH v3 11/16] ALSA: Oxygen: Modify adjust_dg_dac_routing function Roman Volkov
` (6 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
When selecting the audio sample rate for CS4245,
the MCLK divider should also be changed.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/xonar_dg.c | 62 ++++++++++++++++++++++++++++---------------
1 file changed, 40 insertions(+), 22 deletions(-)
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index d6a8c72..7dcca01 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -213,36 +213,54 @@ static void dg_resume(struct oxygen *chip)
dg_output_enable(chip);
}
-static void set_cs4245_dac_params(struct oxygen *chip,
+void set_cs4245_dac_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
struct dg *data = chip->model_data;
- u8 value;
-
- value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
- if (params_rate(params) <= 50000)
- value |= CS4245_DAC_FM_SINGLE;
- else if (params_rate(params) <= 100000)
- value |= CS4245_DAC_FM_DOUBLE;
- else
- value |= CS4245_DAC_FM_QUAD;
- cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value);
+ unsigned char dac_ctrl;
+ unsigned char mclk_freq;
+
+ dac_ctrl = data->cs4245_shadow[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
+ mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK1_MASK;
+ if (params_rate(params) <= 50000) {
+ dac_ctrl |= CS4245_DAC_FM_SINGLE;
+ mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
+ } else if (params_rate(params) <= 100000) {
+ dac_ctrl |= CS4245_DAC_FM_DOUBLE;
+ mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
+ } else {
+ dac_ctrl |= CS4245_DAC_FM_QUAD;
+ mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK1_SHIFT;
+ }
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] = dac_ctrl;
+ data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
+ cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
+ cs4245_write_spi(chip, CS4245_MCLK_FREQ);
}
-static void set_cs4245_adc_params(struct oxygen *chip,
+void set_cs4245_adc_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
struct dg *data = chip->model_data;
- u8 value;
-
- value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
- if (params_rate(params) <= 50000)
- value |= CS4245_ADC_FM_SINGLE;
- else if (params_rate(params) <= 100000)
- value |= CS4245_ADC_FM_DOUBLE;
- else
- value |= CS4245_ADC_FM_QUAD;
- cs4245_write_cached(chip, CS4245_ADC_CTRL, value);
+ unsigned char adc_ctrl;
+ unsigned char mclk_freq;
+
+ adc_ctrl = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
+ mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK2_MASK;
+ if (params_rate(params) <= 50000) {
+ adc_ctrl |= CS4245_ADC_FM_SINGLE;
+ mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
+ } else if (params_rate(params) <= 100000) {
+ adc_ctrl |= CS4245_ADC_FM_DOUBLE;
+ mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
+ } else {
+ adc_ctrl |= CS4245_ADC_FM_QUAD;
+ mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK2_SHIFT;
+ }
+ data->cs4245_shadow[CS4245_ADC_CTRL] = adc_ctrl;
+ data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
+ cs4245_write_spi(chip, CS4245_ADC_CTRL);
+ cs4245_write_spi(chip, CS4245_MCLK_FREQ);
}
static inline unsigned int shift_bits(unsigned int value,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 11/16] ALSA: Oxygen: Modify adjust_dg_dac_routing function
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (8 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 10/16] ALSA: Oxygen: Modify DAC/ADC parameters function Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-17 15:08 ` [PATCH v3 12/16] ALSA: Oxygen: Modify CS4245 register dumping function Roman Volkov
` (5 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
When selecting the audio output destinations (headphones,
FP headphones, multichannel output), the channel routing
should be changed depending on what destination selected.
Also unnecessary I2S channels are digitally muted. This
function called when the user selects the destination
in the ALSA mixer.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/xonar_dg.c | 35 +++++++++++++++++++++--------------
sound/pci/oxygen/xonar_dg.h | 2 ++
2 files changed, 23 insertions(+), 14 deletions(-)
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index 7dcca01..3f3201e 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -274,22 +274,29 @@ static inline unsigned int shift_bits(unsigned int value,
return (value >> (shift_from - shift_to)) & mask;
}
-static unsigned int adjust_dg_dac_routing(struct oxygen *chip,
+unsigned int adjust_dg_dac_routing(struct oxygen *chip,
unsigned int play_routing)
{
- return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
- shift_bits(play_routing,
- OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC1_SOURCE_MASK) |
- shift_bits(play_routing,
- OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC2_SOURCE_MASK) |
- shift_bits(play_routing,
- OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC3_SOURCE_MASK);
+ struct dg *data = chip->model_data;
+ unsigned int routing = 0;
+
+ switch (data->pcm_output) {
+ case PLAYBACK_DST_HP:
+ case PLAYBACK_DST_HP_FP:
+ oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
+ OXYGEN_PLAY_MUTE23 | OXYGEN_PLAY_MUTE45 |
+ OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK);
+ break;
+ case PLAYBACK_DST_MULTICH:
+ routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+ (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+ (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+ (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
+ oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
+ OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK);
+ break;
+ }
+ return routing;
}
static int output_switch_info(struct snd_kcontrol *ctl,
diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h
index f861a4c..844a67b 100644
--- a/sound/pci/oxygen/xonar_dg.h
+++ b/sound/pci/oxygen/xonar_dg.h
@@ -26,6 +26,8 @@ enum cs4245_shadow_operation {
struct dg {
/* The shadow copy of the CS4245 register space */
unsigned char cs4245_shadow[17];
+ /* Output select: headphone/speakers */
+ unsigned char pcm_output;
unsigned int output_sel;
s8 input_vol[4][2];
unsigned int input_sel;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 12/16] ALSA: Oxygen: Modify CS4245 register dumping function
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (9 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 11/16] ALSA: Oxygen: Modify adjust_dg_dac_routing function Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-17 15:08 ` [PATCH v3 13/16] ALSA: Oxygen: Modify suspend, resume, and cleanup functions Roman Volkov
` (4 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
Change the function to read the data from the new
shadow buffer.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/xonar_dg.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index 3f3201e..953ef09 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -625,15 +625,16 @@ static int dg_mixer_init(struct oxygen *chip)
return 0;
}
-static void dump_cs4245_registers(struct oxygen *chip,
- struct snd_info_buffer *buffer)
+void dump_cs4245_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
{
struct dg *data = chip->model_data;
- unsigned int i;
+ unsigned int addr;
snd_iprintf(buffer, "\nCS4245:");
- for (i = 1; i <= 0x10; ++i)
- snd_iprintf(buffer, " %02x", data->cs4245_regs[i]);
+ cs4245_read_spi(chip, CS4245_INT_STATUS);
+ for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++)
+ snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]);
snd_iprintf(buffer, "\n");
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 13/16] ALSA: Oxygen: Modify suspend, resume, and cleanup functions
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (10 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 12/16] ALSA: Oxygen: Modify CS4245 register dumping function Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-17 15:08 ` [PATCH v3 14/16] ALSA: Oxygen: Remove code from the xonar_dg.c file Roman Volkov
` (3 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
When putting the card into suspended
mode, just disable the audio output. There is no
need to do more actions, since PCI slot will be
already disabled (AFAIK). When resume, we need to
restore erased registers of CS4245 from the
memory. When cleanup, just do the same as in
suspend.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/xonar_dg.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index 953ef09..80fc099 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -197,20 +197,21 @@ void dg_init(struct oxygen *chip)
GPIO_HP_REAR | GPIO_INPUT_ROUTE);
}
-static void dg_cleanup(struct oxygen *chip)
+void dg_suspend(struct oxygen *chip)
{
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
}
-static void dg_suspend(struct oxygen *chip)
+void dg_resume(struct oxygen *chip)
{
- dg_cleanup(chip);
+ cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
+ msleep(2500);
+ oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
}
-static void dg_resume(struct oxygen *chip)
+void dg_cleanup(struct oxygen *chip)
{
- /*cs4245_registers_init(chip);*/
- dg_output_enable(chip);
+ dg_suspend(chip);
}
void set_cs4245_dac_params(struct oxygen *chip,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 14/16] ALSA: Oxygen: Remove code from the xonar_dg.c file
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (11 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 13/16] ALSA: Oxygen: Modify suspend, resume, and cleanup functions Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-18 11:08 ` Clemens Ladisch
2014-01-17 15:08 ` [PATCH v3 15/16] ALSA: Oxygen: Additional declarations for the new mixer implementation Roman Volkov
` (2 subsequent siblings)
15 siblings, 1 reply; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
The mixer code and other system structures will come
to the separate file. Some unused code also removed.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/xonar_dg.c | 393 -------------------------------------------
1 file changed, 393 deletions(-)
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index 80fc099..b0dc16e 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -124,29 +124,6 @@ int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op)
return 0;
}
-static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
-{
- struct dg *data = chip->model_data;
-
- oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
- OXYGEN_SPI_DATA_LENGTH_3 |
- OXYGEN_SPI_CLOCK_1280 |
- (0 << OXYGEN_SPI_CODEC_SHIFT) |
- OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
- CS4245_SPI_ADDRESS |
- CS4245_SPI_WRITE |
- (reg << 8) | value);
- data->cs4245_regs[reg] = value;
-}
-
-static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value)
-{
- struct dg *data = chip->model_data;
-
- if (value != data->cs4245_regs[reg])
- cs4245_write(chip, reg, value);
-}
-
static void cs4245_init(struct oxygen *chip)
{
struct dg *data = chip->model_data;
@@ -175,12 +152,6 @@ static void cs4245_init(struct oxygen *chip)
snd_component_add(chip->card, "CS4245");
}
-static void dg_output_enable(struct oxygen *chip)
-{
- msleep(2500);
- oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
-}
-
void dg_init(struct oxygen *chip)
{
/*
@@ -264,17 +235,6 @@ void set_cs4245_adc_params(struct oxygen *chip,
cs4245_write_spi(chip, CS4245_MCLK_FREQ);
}
-static inline unsigned int shift_bits(unsigned int value,
- unsigned int shift_from,
- unsigned int shift_to,
- unsigned int mask)
-{
- if (shift_from < shift_to)
- return (value << (shift_to - shift_from)) & mask;
- else
- return (value >> (shift_from - shift_to)) & mask;
-}
-
unsigned int adjust_dg_dac_routing(struct oxygen *chip,
unsigned int play_routing)
{
@@ -300,332 +260,6 @@ unsigned int adjust_dg_dac_routing(struct oxygen *chip,
return routing;
}
-static int output_switch_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- static const char *const names[3] = {
- "Speakers", "Headphones", "FP Headphones"
- };
-
- return snd_ctl_enum_info(info, 1, 3, names);
-}
-
-static int output_switch_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
-
- mutex_lock(&chip->mutex);
- value->value.enumerated.item[0] = data->output_sel;
- mutex_unlock(&chip->mutex);
- return 0;
-}
-
-static int output_switch_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- u8 reg;
- int changed;
-
- if (value->value.enumerated.item[0] > 2)
- return -EINVAL;
-
- mutex_lock(&chip->mutex);
- changed = value->value.enumerated.item[0] != data->output_sel;
- if (changed) {
- data->output_sel = value->value.enumerated.item[0];
-
- reg = data->cs4245_regs[CS4245_SIGNAL_SEL] &
- ~CS4245_A_OUT_SEL_MASK;
- reg |= data->output_sel == 2 ?
- CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ;
- cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg);
-
- cs4245_write_cached(chip, CS4245_DAC_A_CTRL,
- data->output_sel ? data->hp_vol_att : 0);
- cs4245_write_cached(chip, CS4245_DAC_B_CTRL,
- data->output_sel ? data->hp_vol_att : 0);
-
- oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
- data->output_sel == 1 ? GPIO_HP_REAR : 0,
- GPIO_HP_REAR);
- }
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static int hp_volume_offset_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- static const char *const names[3] = {
- "< 64 ohms", "64-150 ohms", "150-300 ohms"
- };
-
- return snd_ctl_enum_info(info, 1, 3, names);
-}
-
-static int hp_volume_offset_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
-
- mutex_lock(&chip->mutex);
- if (data->hp_vol_att > 2 * 7)
- value->value.enumerated.item[0] = 0;
- else if (data->hp_vol_att > 0)
- value->value.enumerated.item[0] = 1;
- else
- value->value.enumerated.item[0] = 2;
- mutex_unlock(&chip->mutex);
- return 0;
-}
-
-static int hp_volume_offset_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- static const s8 atts[3] = { 2 * 16, 2 * 7, 0 };
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- s8 att;
- int changed;
-
- if (value->value.enumerated.item[0] > 2)
- return -EINVAL;
- att = atts[value->value.enumerated.item[0]];
- mutex_lock(&chip->mutex);
- changed = att != data->hp_vol_att;
- if (changed) {
- data->hp_vol_att = att;
- if (data->output_sel) {
- cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att);
- cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att);
- }
- }
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static int input_vol_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- info->count = 2;
- info->value.integer.min = 2 * -12;
- info->value.integer.max = 2 * 12;
- return 0;
-}
-
-static int input_vol_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- unsigned int idx = ctl->private_value;
-
- mutex_lock(&chip->mutex);
- value->value.integer.value[0] = data->input_vol[idx][0];
- value->value.integer.value[1] = data->input_vol[idx][1];
- mutex_unlock(&chip->mutex);
- return 0;
-}
-
-static int input_vol_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- unsigned int idx = ctl->private_value;
- int changed = 0;
-
- if (value->value.integer.value[0] < 2 * -12 ||
- value->value.integer.value[0] > 2 * 12 ||
- value->value.integer.value[1] < 2 * -12 ||
- value->value.integer.value[1] > 2 * 12)
- return -EINVAL;
- mutex_lock(&chip->mutex);
- changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
- data->input_vol[idx][1] != value->value.integer.value[1];
- if (changed) {
- data->input_vol[idx][0] = value->value.integer.value[0];
- data->input_vol[idx][1] = value->value.integer.value[1];
- if (idx == data->input_sel) {
- cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
- data->input_vol[idx][0]);
- cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
- data->input_vol[idx][1]);
- }
- }
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0);
-
-static int input_sel_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- static const char *const names[4] = {
- "Mic", "Aux", "Front Mic", "Line"
- };
-
- return snd_ctl_enum_info(info, 1, 4, names);
-}
-
-static int input_sel_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
-
- mutex_lock(&chip->mutex);
- value->value.enumerated.item[0] = data->input_sel;
- mutex_unlock(&chip->mutex);
- return 0;
-}
-
-static int input_sel_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- static const u8 sel_values[4] = {
- CS4245_SEL_MIC,
- CS4245_SEL_INPUT_1,
- CS4245_SEL_INPUT_2,
- CS4245_SEL_INPUT_4
- };
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- int changed;
-
- if (value->value.enumerated.item[0] > 3)
- return -EINVAL;
-
- mutex_lock(&chip->mutex);
- changed = value->value.enumerated.item[0] != data->input_sel;
- if (changed) {
- data->input_sel = value->value.enumerated.item[0];
-
- cs4245_write(chip, CS4245_ANALOG_IN,
- (data->cs4245_regs[CS4245_ANALOG_IN] &
- ~CS4245_SEL_MASK) |
- sel_values[data->input_sel]);
-
- cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
- data->input_vol[data->input_sel][0]);
- cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
- data->input_vol[data->input_sel][1]);
-
- oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
- data->input_sel ? 0 : GPIO_INPUT_ROUTE,
- GPIO_INPUT_ROUTE);
- }
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
-{
- static const char *const names[2] = { "Active", "Frozen" };
-
- return snd_ctl_enum_info(info, 1, 2, names);
-}
-
-static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
-
- value->value.enumerated.item[0] =
- !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
- return 0;
-}
-
-static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- u8 reg;
- int changed;
-
- mutex_lock(&chip->mutex);
- reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
- if (value->value.enumerated.item[0])
- reg |= CS4245_HPF_FREEZE;
- changed = reg != data->cs4245_regs[CS4245_ADC_CTRL];
- if (changed)
- cs4245_write(chip, CS4245_ADC_CTRL, reg);
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-#define INPUT_VOLUME(xname, index) { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .info = input_vol_info, \
- .get = input_vol_get, \
- .put = input_vol_put, \
- .tlv = { .p = cs4245_pga_db_scale }, \
- .private_value = index, \
-}
-static const struct snd_kcontrol_new dg_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Output Playback Enum",
- .info = output_switch_info,
- .get = output_switch_get,
- .put = output_switch_put,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Headphones Impedance Playback Enum",
- .info = hp_volume_offset_info,
- .get = hp_volume_offset_get,
- .put = hp_volume_offset_put,
- },
- INPUT_VOLUME("Mic Capture Volume", 0),
- INPUT_VOLUME("Aux Capture Volume", 1),
- INPUT_VOLUME("Front Mic Capture Volume", 2),
- INPUT_VOLUME("Line Capture Volume", 3),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .info = input_sel_info,
- .get = input_sel_get,
- .put = input_sel_put,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "ADC High-pass Filter Capture Enum",
- .info = hpf_info,
- .get = hpf_get,
- .put = hpf_put,
- },
-};
-
-static int dg_control_filter(struct snd_kcontrol_new *template)
-{
- if (!strncmp(template->name, "Master Playback ", 16))
- return 1;
- return 0;
-}
-
-static int dg_mixer_init(struct oxygen *chip)
-{
- unsigned int i;
- int err;
-
- for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
- err = snd_ctl_add(chip->card,
- snd_ctl_new1(&dg_controls[i], chip));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
void dump_cs4245_registers(struct oxygen *chip,
struct snd_info_buffer *buffer)
{
@@ -638,30 +272,3 @@ void dump_cs4245_registers(struct oxygen *chip,
snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]);
snd_iprintf(buffer, "\n");
}
-
-struct oxygen_model model_xonar_dg = {
- .longname = "C-Media Oxygen HD Audio",
- .chip = "CMI8786",
- .init = dg_init,
- .control_filter = dg_control_filter,
- .mixer_init = dg_mixer_init,
- .cleanup = dg_cleanup,
- .suspend = dg_suspend,
- .resume = dg_resume,
- .set_dac_params = set_cs4245_dac_params,
- .set_adc_params = set_cs4245_adc_params,
- .adjust_dac_routing = adjust_dg_dac_routing,
- .dump_registers = dump_cs4245_registers,
- .model_data_size = sizeof(struct dg),
- .device_config = PLAYBACK_0_TO_I2S |
- PLAYBACK_1_TO_SPDIF |
- CAPTURE_0_FROM_I2S_2 |
- CAPTURE_1_FROM_SPDIF,
- .dac_channels_pcm = 6,
- .dac_channels_mixer = 0,
- .function_flags = OXYGEN_FUNCTION_SPI,
- .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
- .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
- .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
- .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 15/16] ALSA: Oxygen: Additional declarations for the new mixer implementation
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (12 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 14/16] ALSA: Oxygen: Remove code from the xonar_dg.c file Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-17 15:08 ` [PATCH v3 16/16] ALSA: Oxygen: The " Roman Volkov
2014-01-18 10:26 ` [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Clemens Ladisch
15 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
The 'dg' struct changed, contains new values for the
mixer controls. Functions declared in the header file
to call them from the mixer.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/xonar_dg.h | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h
index 844a67b..636890a 100644
--- a/sound/pci/oxygen/xonar_dg.h
+++ b/sound/pci/oxygen/xonar_dg.h
@@ -28,13 +28,31 @@ struct dg {
unsigned char cs4245_shadow[17];
/* Output select: headphone/speakers */
unsigned char pcm_output;
- unsigned int output_sel;
- s8 input_vol[4][2];
- unsigned int input_sel;
- u8 hp_vol_att;
- u8 cs4245_regs[0x11];
+ /* Input select: Mic, FP Mic, Line, Aux */
+ unsigned char pga_source;
+ /* Independent capture volume control values */
+ char cap_vol[4][2];
+ /* Independent mute control values */
+ bool cap_mute[4];
};
+/* Xonar DG control routines */
+int cs4245_write_spi(struct oxygen *chip, u8 reg);
+int cs4245_read_spi(struct oxygen *chip, u8 reg);
+int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op);
+void dg_init(struct oxygen *chip);
+void set_cs4245_dac_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params);
+void set_cs4245_adc_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params);
+unsigned int adjust_dg_dac_routing(struct oxygen *chip,
+ unsigned int play_routing);
+void dump_cs4245_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer);
+void dg_suspend(struct oxygen *chip);
+void dg_resume(struct oxygen *chip);
+void dg_cleanup(struct oxygen *chip);
+
extern struct oxygen_model model_xonar_dg;
#endif
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 16/16] ALSA: Oxygen: The new mixer implementation
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (13 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 15/16] ALSA: Oxygen: Additional declarations for the new mixer implementation Roman Volkov
@ 2014-01-17 15:08 ` Roman Volkov
2014-01-18 10:26 ` [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Clemens Ladisch
15 siblings, 0 replies; 24+ messages in thread
From: Roman Volkov @ 2014-01-17 15:08 UTC (permalink / raw)
To: patch; +Cc: alsa-devel, Roman Volkov
The mixer changed. In the new implementation, the headphone
volume changes instead of having the 'impedance control'.
This allows to use headphones without builtin volume control
and without software volume control. Four input sources with
independent mute and volume controls, but only one source can
be selected.
Signed-off-by: Roman Volkov <v1ron@mail.ru>
---
sound/pci/oxygen/Makefile | 2 +-
sound/pci/oxygen/xonar_dg_mixer.c | 483 +++++++++++++++++++++++++++++++++++++
2 files changed, 484 insertions(+), 1 deletion(-)
create mode 100644 sound/pci/oxygen/xonar_dg_mixer.c
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile
index 0f87265..8f4c409 100644
--- a/sound/pci/oxygen/Makefile
+++ b/sound/pci/oxygen/Makefile
@@ -1,5 +1,5 @@
snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
-snd-oxygen-objs := oxygen.o xonar_dg.o
+snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o
snd-virtuoso-objs := virtuoso.o xonar_lib.o \
xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
diff --git a/sound/pci/oxygen/xonar_dg_mixer.c b/sound/pci/oxygen/xonar_dg_mixer.c
new file mode 100644
index 0000000..39a0da7
--- /dev/null
+++ b/sound/pci/oxygen/xonar_dg_mixer.c
@@ -0,0 +1,483 @@
+/*
+ * Mixer controls for the Xonar DG/DGX
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) Roman Volkov <v1ron@mail.ru>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * It is not good that we do not have software volume control
+ * as the Windows driver does. CS4361 cannot attenuate the volume.
+ * When we are switching from headphones to the speakers,
+ * which are controlled by the simple DAC CS4361, our headphones
+ * in the rear jack can stun us.
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "oxygen.h"
+#include "xonar_dg.h"
+#include "cs4245.h"
+
+/* CS4245 Headphone Channels A&B Volume Control */
+static int xonar_dg_dac_stereo_volume_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 2;
+ info->value.integer.min = 0;
+ info->value.integer.max = 255;
+ return 0;
+}
+
+static int xonar_dg_dac_stereo_volume_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ unsigned int tmp;
+
+ mutex_lock(&chip->mutex);
+ tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255;
+ val->value.integer.value[0] = tmp;
+ tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255;
+ val->value.integer.value[1] = tmp;
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int xonar_dg_dac_stereo_volume_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ if ((val->value.integer.value[0] > 255) ||
+ (val->value.integer.value[0] < 0) ||
+ (val->value.integer.value[1] > 255) ||
+ (val->value.integer.value[1] < 0)) {
+ return -EINVAL;
+ }
+ mutex_lock(&chip->mutex);
+ data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~val->value.integer.value[0];
+ data->cs4245_shadow[CS4245_DAC_B_CTRL] = ~val->value.integer.value[1];
+ cs4245_write_spi(chip, CS4245_DAC_A_CTRL);
+ cs4245_write_spi(chip, CS4245_DAC_B_CTRL);
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+/* CS4245 DAC Mute */
+static int xonar_dg_dac_mute_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ val->value.integer.value[0] = ((data->cs4245_shadow[CS4245_DAC_CTRL_1]
+ & CS4245_MUTE_DAC) == 0);
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int xonar_dg_dac_mute_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ if (val->value.integer.value[0] > 1)
+ return -EINVAL;
+ mutex_lock(&chip->mutex);
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC;
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] |=
+ (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC;
+ cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+/* Xonar DG Output Select */
+static int xonar_dg_pcm_route_apply(struct oxygen *chip)
+{
+ struct dg *data = chip->model_data;
+
+ data->cs4245_shadow[CS4245_SIGNAL_SEL] &=
+ ~CS4245_A_OUT_SEL_MASK;
+ if (data->pcm_output == PLAYBACK_DST_HP) {
+ /* Mute FP (aux output) amplifier, switch rear jack to CS4245 */
+ oxygen_set_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+ } else if (data->pcm_output == PLAYBACK_DST_HP_FP) {
+ /*
+ * Unmute FP amplifier, switch rear jack to CS4361,
+ * I2S ports 2,3,4 should be inactive
+ */
+ oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+ data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC;
+ } else {
+ /*
+ * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp.,
+ * and change playback routing / DMA channels
+ */
+ oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+ }
+ cs4245_write_spi(chip, CS4245_SIGNAL_SEL);
+ return 0;
+}
+
+static int xonar_dg_pcm_route_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[3] = {
+ "Stereo Headphones",
+ "Stereo Headphones FP",
+ "Multichannel",
+ };
+
+ return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int xonar_dg_pcm_route_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ val->value.integer.value[0] = data->pcm_output;
+ mutex_unlock(&chip->mutex);
+
+ return 0;
+}
+
+static int xonar_dg_pcm_route_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ int ret;
+
+ mutex_lock(&chip->mutex);
+ data->pcm_output = val->value.integer.value[0];
+ ret = xonar_dg_pcm_route_apply(chip);
+ oxygen_update_dac_routing(chip);
+ mutex_unlock(&chip->mutex);
+
+ return ret;
+}
+
+/* CS4245 PGA Source */
+static int xonar_dg_pga_mute_reg_toggle(struct oxygen *chip, bool mute);
+static int xonar_dg_pga_volume_reg_write(struct oxygen *chip, char left,
+ char right);
+
+static int xonar_dg_pga_source_apply(struct oxygen *chip)
+{
+ struct dg *data = chip->model_data;
+
+ data->cs4245_shadow[CS4245_ANALOG_IN] &= ~CS4245_SEL_MASK;
+ if (data->pga_source == CAPTURE_SRC_FP_MIC)
+ data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_2;
+ else if (data->pga_source == CAPTURE_SRC_LINE)
+ data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_4;
+ else if (data->pga_source != CAPTURE_SRC_MIC)
+ data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_1;
+ oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE);
+ return cs4245_write_spi(chip, CS4245_ANALOG_IN);
+}
+
+static int xonar_dg_pga_source_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const ps_names[4] = {
+ "Microphone",
+ "Microphone FP",
+ "Line In",
+ "Aux"
+ };
+
+ return snd_ctl_enum_info(info, 1, 4, ps_names);
+}
+
+static int xonar_dg_pga_source_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ val->value.integer.value[0] = data->pga_source;
+ mutex_unlock(&chip->mutex);
+
+ return 0;
+}
+
+/* Switch the source and change volume/mute */
+static int xonar_dg_pga_source_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ long route = val->value.integer.value[0];
+ int ret;
+
+ if ((route > CAPTURE_SRC_AUX) || (route < 0))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ data->pga_source = route;
+ ret = xonar_dg_pga_source_apply(chip);
+ if (ret < 0)
+ goto err;
+ ret = xonar_dg_pga_mute_reg_toggle(chip, data->cap_mute[route]);
+ if (ret < 0)
+ goto err;
+ ret = xonar_dg_pga_volume_reg_write(chip,
+ data->cap_vol[route][0],
+ data->cap_vol[route][1]);
+ if (ret < 0)
+ goto err;
+err:
+ mutex_unlock(&chip->mutex);
+
+ return ret;
+}
+
+/* Common routines to access capture volume register - Mic, Line, Aux */
+static int xonar_dg_pga_volume_reg_write(struct oxygen *chip, char left,
+ char right)
+{
+ struct dg *data = chip->model_data;
+ int ret;
+
+ data->cs4245_shadow[CS4245_PGA_A_CTRL] = left;
+ data->cs4245_shadow[CS4245_PGA_B_CTRL] = right;
+ ret = cs4245_write_spi(chip, CS4245_PGA_A_CTRL);
+ if (ret < 0)
+ return ret;
+ return cs4245_write_spi(chip, CS4245_PGA_B_CTRL);
+}
+
+static int xonar_dg_pga_volume_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 2;
+ info->value.integer.min = -24;
+ info->value.integer.max = 24;
+ return 0;
+}
+
+static int xonar_dg_pga_volume_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ val->value.integer.value[0] = data->cap_vol[ctl->private_value][0];
+ val->value.integer.value[1] = data->cap_vol[ctl->private_value][1];
+ mutex_unlock(&chip->mutex);
+
+ return 0;
+}
+
+static int xonar_dg_pga_volume_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ long left = val->value.integer.value[0];
+ long right = val->value.integer.value[1];
+ int ret = 0;
+
+ if ((left > 24) || (left < -24) || (right > 24) || (right < -24))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ data->cap_vol[ctl->private_value][0] = left;
+ data->cap_vol[ctl->private_value][1] = right;
+ ret = xonar_dg_pga_volume_reg_write(chip,
+ data->cap_vol[data->pga_source][0],
+ data->cap_vol[data->pga_source][1]);
+ mutex_unlock(&chip->mutex);
+
+ return ret;
+}
+
+/* Common routines to access capture mute register - Mic, Line, Aux */
+static int xonar_dg_pga_mute_reg_toggle(struct oxygen *chip, bool mute)
+{
+ struct dg *data = chip->model_data;
+
+ data->cs4245_shadow[CS4245_ADC_CTRL] &= ~CS4245_MUTE_ADC;
+ data->cs4245_shadow[CS4245_ADC_CTRL] |= ((mute == 0) << 2) &
+ CS4245_MUTE_ADC;
+ return cs4245_write_spi(chip, CS4245_ADC_CTRL);
+}
+
+static int xonar_dg_pga_mute_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ val->value.integer.value[0] = (long)data->cap_mute[ctl->private_value];
+ mutex_unlock(&chip->mutex);
+
+ return 0;
+}
+
+static int xonar_dg_pga_mute_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ long tmp = val->value.integer.value[0];
+ int ret = 0;
+
+ if ((tmp > 1) || (tmp < 0))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ data->cap_mute[ctl->private_value] = tmp != 0;
+ ret = xonar_dg_pga_mute_reg_toggle(chip,
+ data->cap_mute[data->pga_source]);
+ mutex_unlock(&chip->mutex);
+
+ return ret;
+}
+
+#define CAPTURE_VOLUME(xname, private) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = xonar_dg_pga_volume_info, \
+ .get = xonar_dg_pga_volume_get, \
+ .put = xonar_dg_pga_volume_put, \
+ .tlv = { .p = xonar_dg_pga_db_scale, }, \
+ .private_value = private, \
+ }
+#define CAPTURE_SWITCH(xname, private) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_ctl_boolean_mono_info, \
+ .get = xonar_dg_pga_mute_get, \
+ .put = xonar_dg_pga_mute_put, \
+ .private_value = private, \
+ }
+
+static const DECLARE_TLV_DB_MINMAX(xonar_dg_hp_db_scale, -12550, 0);
+static const DECLARE_TLV_DB_MINMAX(xonar_dg_pga_db_scale, -1200, 1200);
+static const struct snd_kcontrol_new xonar_dg_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphone Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = xonar_dg_dac_stereo_volume_info,
+ .get = xonar_dg_dac_stereo_volume_get,
+ .put = xonar_dg_dac_stereo_volume_put,
+ .tlv = { .p = xonar_dg_hp_db_scale, },
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphone Playback Switch",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_ctl_boolean_mono_info,
+ .get = xonar_dg_dac_mute_get,
+ .put = xonar_dg_dac_mute_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Output Playback Enum",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = xonar_dg_pcm_route_info,
+ .get = xonar_dg_pcm_route_get,
+ .put = xonar_dg_pcm_route_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Capture Enum",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = xonar_dg_pga_source_info,
+ .get = xonar_dg_pga_source_get,
+ .put = xonar_dg_pga_source_put,
+ },
+ CAPTURE_VOLUME("Mic Capture Volume", CAPTURE_SRC_MIC),
+ CAPTURE_SWITCH("Mic Capture Switch", CAPTURE_SRC_MIC),
+ CAPTURE_VOLUME("FP Mic Capture Volume", CAPTURE_SRC_FP_MIC),
+ CAPTURE_SWITCH("FP Mic Capture Switch", CAPTURE_SRC_FP_MIC),
+ CAPTURE_VOLUME("Line Capture Volume", CAPTURE_SRC_LINE),
+ CAPTURE_SWITCH("Line Capture Switch", CAPTURE_SRC_LINE),
+ CAPTURE_VOLUME("Aux Capture Volume", CAPTURE_SRC_AUX),
+ CAPTURE_SWITCH("Aux Capture Switch", CAPTURE_SRC_AUX),
+};
+
+int xonar_dg_mixer_init(struct oxygen *chip)
+{
+ unsigned int i;
+ int ret;
+ for (i = 0; i < ARRAY_SIZE(xonar_dg_controls); i++) {
+ ret = snd_ctl_add(chip->card,
+ snd_ctl_new1(&xonar_dg_controls[i], chip));
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+/* Disable built-in volume control, we have only headphone volume */
+static int xonar_control_filter(struct snd_kcontrol_new *template)
+{
+ if (!strncmp(template->name, "Master Playback ", 16))
+ return 1;
+ return 0;
+}
+
+struct oxygen_model model_xonar_dg = {
+ .longname = "C-Media Oxygen HD Audio",
+ .chip = "CMI8786",
+ .init = dg_init,
+ .control_filter = xonar_control_filter,
+ .mixer_init = xonar_dg_mixer_init,
+ .cleanup = dg_cleanup,
+ .suspend = dg_suspend,
+ .resume = dg_resume,
+ .set_dac_params = set_cs4245_dac_params,
+ .set_adc_params = set_cs4245_adc_params,
+ .adjust_dac_routing = adjust_dg_dac_routing,
+ .dump_registers = dump_cs4245_registers,
+ .model_data_size = sizeof(struct dg),
+ .device_config = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF |
+ CAPTURE_0_FROM_I2S_1 |
+ CAPTURE_1_FROM_SPDIF,
+ .dac_channels_pcm = 6,
+ .dac_channels_mixer = 0,
+ .function_flags = OXYGEN_FUNCTION_SPI,
+ .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function
2014-01-17 15:08 [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Roman Volkov
` (14 preceding siblings ...)
2014-01-17 15:08 ` [PATCH v3 16/16] ALSA: Oxygen: The " Roman Volkov
@ 2014-01-18 10:26 ` Clemens Ladisch
2014-01-19 8:10 ` Roman Volkov
15 siblings, 1 reply; 24+ messages in thread
From: Clemens Ladisch @ 2014-01-18 10:26 UTC (permalink / raw)
To: Roman Volkov; +Cc: alsa-devel
Roman Volkov wrote:
> This function performs waiting when the SPI bus completes
> a transaction. Timeout error checking introduced and
> the timeout increased to 400 from 40.
Why 400? SPI does not allow the codec to delay reads.
> + for (count = 100; count > 0; count--) {
> + if ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) &
> + OXYGEN_SPI_BUSY) == 0)
> + return 0;
> + udelay(4);
> + --count;
> + }
This loop waits for 200 µs.
The SPI transaction will not be finished for the first 30 µs or so, so
polling is not needed for that time.
With the wait coming after the transaction, it makes more sense to have
the busy check not before but after the udelay.
Regards,
Clemens
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function
2014-01-18 10:26 ` [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function Clemens Ladisch
@ 2014-01-19 8:10 ` Roman Volkov
2014-01-19 9:39 ` Clemens Ladisch
0 siblings, 1 reply; 24+ messages in thread
From: Roman Volkov @ 2014-01-19 8:10 UTC (permalink / raw)
To: Clemens Ladisch; +Cc: alsa-devel
В Sat, 18 Jan 2014 11:26:49 +0100
Clemens Ladisch <clemens@ladisch.de> пишет:
> > This function performs waiting when the SPI bus completes
> > a transaction. Timeout error checking introduced and
> > the timeout increased to 400 from 40.
>
> Why 400? SPI does not allow the codec to delay reads.
Yes. AFAIK, every SPI transaction will take almost the same time,
depending on the SPI clock and the number of bits to transfer,
regardless of what we're performing, reading or writing.
400 us is just the maximum time, exceeding this will cause an error.
Okay, lets calculate, in worst case (3 bytes to transfer, 1280ns clock):
1280 * 8 * 3 = 30270ns, 30,72 us. Perhaps plus some time to initiate
the transfer.
400us is greater than 40 by 10 times, but the function never waits 400
us, it always returns earlier than in 40-50 us. I always prefer to
increase these timeouts much longer than needed, this guarantees
that I never get false-positives and this wait is safe. Even if the
error occured, 400us is very small amount of time.
> > + for (count = 100; count > 0; count--) {
> > + if ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) &
> > + OXYGEN_SPI_BUSY)
> > == 0)
> > + return 0;
> > + udelay(4);
> > + --count;
> > + }
>
> This loop waits for 200 µs.
>
Ah... Thanks.
Also why I prefer higher timeouts:
http://stackoverflow.com/questions/8352812/linux-kernel-udelay-returns-too-early
Even if a mistake or a bug, this works as needed :) This driver
currently works on my PC, if the test succeeded, this decreases my
attention :)
> The SPI transaction will not be finished for the first 30 µs or so, so
> polling is not needed for that time.
We may switch the context and force CPU to
execute useful code, using something like usleep, msleep. However,
this may block the thread for too long time. Please suggest
something how to optimize this.
> With the wait coming after the transaction, it makes more sense to
> have the busy check not before but after the udelay.
Okay, this will be:
for (count = 100; count > 0; count--) {
udelay(4);
if ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) &
OXYGEN_SPI_BUSY) == 0)
return 0;
}
--
Kind regards,
Roman Volkov,
v1ron@mail.ru
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH v3 01/16] ALSA: Oxygen: Add the separate SPI waiting function
2014-01-19 8:10 ` Roman Volkov
@ 2014-01-19 9:39 ` Clemens Ladisch
0 siblings, 0 replies; 24+ messages in thread
From: Clemens Ladisch @ 2014-01-19 9:39 UTC (permalink / raw)
To: Roman Volkov; +Cc: alsa-devel
Roman Volkov wrote:
> Clemens Ladisch <clemens@ladisch.de> пишет:
>> The SPI transaction will not be finished for the first 30 µs or so, so
>> polling is not needed for that time.
>
> We may switch the context and force CPU to
> execute useful code, using something like usleep, msleep. However,
> this may block the thread for too long time. Please suggest
> something how to optimize this.
Actually, SPI transactions could use 2 bytes or a faster clock,
so I don't think this needs to be optimized.
>> With the wait coming after the transaction, it makes more sense to
>> have the busy check not before but after the udelay.
>
> Okay, this will be:
>
> for (count = 100; count > 0; count--) {
> udelay(4);
> if ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) &
> OXYGEN_SPI_BUSY) == 0)
> return 0;
> }
Yes.
Regards,
Clemens
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply [flat|nested] 24+ messages in thread