ALSA: pcxhr - add support for gpio ports and minor bug fix
authorMarkus Bollinger <bollinger@digigram.com>
Fri, 23 Jan 2009 13:45:41 +0000 (14:45 +0100)
committerTakashi Iwai <tiwai@suse.de>
Fri, 23 Jan 2009 13:45:41 +0000 (14:45 +0100)
- add support for gpio ports (2 GPI, 2 GPO) of pcxhr stereo cards
- minor bugfixes : allow setting clock to internal by the mixer
                   even if there is no stream (but monitoring)

Signed-off-by: Markus Bollinger <bollinger@digigram.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/pcxhr/pcxhr.c
sound/pci/pcxhr/pcxhr.h
sound/pci/pcxhr/pcxhr_mix22.c
sound/pci/pcxhr/pcxhr_mix22.h
sound/pci/pcxhr/pcxhr_mixer.c

index 27cf2c28d1131eac14cf96ac3b55eb34c51ec543..ca89106f8c5da255f1f0562ec2ae66fcb27512fc 100644 (file)
@@ -1334,6 +1334,40 @@ static void pcxhr_proc_sync(struct snd_info_entry *entry,
        snd_iprintf(buffer, "\n");
 }
 
+static void pcxhr_proc_gpio_read(struct snd_info_entry *entry,
+                                struct snd_info_buffer *buffer)
+{
+       struct snd_pcxhr *chip = entry->private_data;
+       struct pcxhr_mgr *mgr = chip->mgr;
+       /* commands available when embedded DSP is running */
+       if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
+               /* gpio ports on stereo boards only available */
+               int value = 0;
+               hr222_read_gpio(mgr, 1, &value);        /* GPI */
+               snd_iprintf(buffer, "GPI: 0x%x\n", value);
+               hr222_read_gpio(mgr, 0, &value);        /* GP0 */
+               snd_iprintf(buffer, "GPO: 0x%x\n", value);
+       } else
+               snd_iprintf(buffer, "no firmware loaded\n");
+       snd_iprintf(buffer, "\n");
+}
+static void pcxhr_proc_gpo_write(struct snd_info_entry *entry,
+                                struct snd_info_buffer *buffer)
+{
+       struct snd_pcxhr *chip = entry->private_data;
+       struct pcxhr_mgr *mgr = chip->mgr;
+       char line[64];
+       int value;
+       /* commands available when embedded DSP is running */
+       if (!(mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)))
+               return;
+       while (!snd_info_get_line(buffer, line, sizeof(line))) {
+               if (sscanf(line, "GPO: 0x%x", &value) != 1)
+                       continue;
+               hr222_write_gpo(mgr, value);    /* GP0 */
+       }
+}
+
 static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip)
 {
        struct snd_info_entry *entry;
@@ -1342,6 +1376,13 @@ static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip)
                snd_info_set_text_ops(entry, chip, pcxhr_proc_info);
        if (! snd_card_proc_new(chip->card, "sync", &entry))
                snd_info_set_text_ops(entry, chip, pcxhr_proc_sync);
+       /* gpio available on stereo sound cards only */
+       if (chip->mgr->is_hr_stereo &&
+           !snd_card_proc_new(chip->card, "gpio", &entry)) {
+               snd_info_set_text_ops(entry, chip, pcxhr_proc_gpio_read);
+               entry->c.text.write = pcxhr_proc_gpo_write;
+               entry->mode |= S_IWUSR;
+       }
 }
 /* end of proc interface */
 
index 84131a916c92bc379ec1f07cdb515fc37ae13749..ac9c3b3bb4e8c2911722f7f42f57a9f016d69435 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/mutex.h>
 #include <sound/pcm.h>
 
-#define PCXHR_DRIVER_VERSION           0x000905        /* 0.9.5 */
-#define PCXHR_DRIVER_VERSION_STRING    "0.9.5"         /* 0.9.5 */
+#define PCXHR_DRIVER_VERSION           0x000906        /* 0.9.6 */
+#define PCXHR_DRIVER_VERSION_STRING    "0.9.6"         /* 0.9.6 */
 
 
 #define PCXHR_MAX_CARDS                6
@@ -124,6 +124,7 @@ struct pcxhr_mgr {
 
        unsigned char xlx_cfg;          /* copy of PCXHR_XLX_CFG register */
        unsigned char xlx_selmic;       /* copy of PCXHR_XLX_SELMIC register */
+       unsigned char dsp_reset;        /* copy of PCXHR_DSP_RESET register */
 };
 
 
index ff019126b672e4743fba7385134ae7a39e3b873d..1cb82c0a9cb3f4942b258464af2163aa7a0f5064 100644 (file)
@@ -53,6 +53,8 @@
 #define PCXHR_DSP_RESET_DSP    0x01
 #define PCXHR_DSP_RESET_MUTE   0x02
 #define PCXHR_DSP_RESET_CODEC  0x08
+#define PCXHR_DSP_RESET_GPO_OFFSET     5
+#define PCXHR_DSP_RESET_GPO_MASK       0x60
 
 /* values for PCHR_XLX_CFG register */
 #define PCXHR_CFG_SYNCDSP_MASK         0x80
@@ -81,6 +83,8 @@
 /* values for PCHR_XLX_STATUS register - READ */
 #define PCXHR_STAT_SRC_LOCK            0x01
 #define PCXHR_STAT_LEVEL_IN            0x02
+#define PCXHR_STAT_GPI_OFFSET          2
+#define PCXHR_STAT_GPI_MASK            0x0C
 #define PCXHR_STAT_MIC_CAPS            0x10
 /* values for PCHR_XLX_STATUS register - WRITE */
 #define PCXHR_STAT_FREQ_SYNC_MASK      0x01
@@ -291,10 +295,11 @@ int hr222_sub_init(struct pcxhr_mgr *mgr)
        PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
                    PCXHR_DSP_RESET_DSP);
        msleep(5);
-       PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
-                   PCXHR_DSP_RESET_DSP  |
-                   PCXHR_DSP_RESET_MUTE |
-                   PCXHR_DSP_RESET_CODEC);
+       mgr->dsp_reset = PCXHR_DSP_RESET_DSP  |
+                        PCXHR_DSP_RESET_MUTE |
+                        PCXHR_DSP_RESET_CODEC;
+       PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset);
+       /* hr222_write_gpo(mgr, 0); does the same */
        msleep(5);
 
        /* config AKM */
@@ -496,6 +501,33 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr,
 }
 
 
+int hr222_read_gpio(struct pcxhr_mgr *mgr, int is_gpi, int *value)
+{
+       if (is_gpi) {
+               unsigned char reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS);
+               *value = (int)(reg & PCXHR_STAT_GPI_MASK) >>
+                             PCXHR_STAT_GPI_OFFSET;
+       } else {
+               *value = (int)(mgr->dsp_reset & PCXHR_DSP_RESET_GPO_MASK) >>
+                        PCXHR_DSP_RESET_GPO_OFFSET;
+       }
+       return 0;
+}
+
+
+int hr222_write_gpo(struct pcxhr_mgr *mgr, int value)
+{
+       unsigned char reg = mgr->dsp_reset & ~PCXHR_DSP_RESET_GPO_MASK;
+
+       reg |= (unsigned char)(value << PCXHR_DSP_RESET_GPO_OFFSET) &
+              PCXHR_DSP_RESET_GPO_MASK;
+
+       PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, reg);
+       mgr->dsp_reset = reg;
+       return 0;
+}
+
+
 int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
                                    int is_capture, int channel)
 {
index 6b318b2f0100af693bdf8a4a3798d25671a3e179..5a37a0007e8fd071cc430ad67bfe5853bfef15c6 100644 (file)
@@ -32,6 +32,9 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr,
                             enum pcxhr_clock_type clock_type,
                             int *sample_rate);
 
+int hr222_read_gpio(struct pcxhr_mgr *mgr, int is_gpi, int *value);
+int hr222_write_gpo(struct pcxhr_mgr *mgr, int value);
+
 #define HR222_LINE_PLAYBACK_LEVEL_MIN          0       /* -25.5 dB */
 #define HR222_LINE_PLAYBACK_ZERO_LEVEL         51      /* 0.0 dB */
 #define HR222_LINE_PLAYBACK_LEVEL_MAX          99      /* +24.0 dB */
index 2436e374586f84aada1cc71c9fa565a4e9b72d85..fec049344621ef97f922c395e8ff5693e3c48945 100644 (file)
@@ -789,11 +789,15 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol,
        if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) {
                mutex_lock(&mgr->setup_mutex);
                mgr->use_clock_type = ucontrol->value.enumerated.item[0];
-               if (mgr->use_clock_type)
+               rate = 0;
+               if (mgr->use_clock_type != PCXHR_CLOCK_TYPE_INTERNAL) {
                        pcxhr_get_external_clock(mgr, mgr->use_clock_type,
                                                 &rate);
-               else
+               } else {
                        rate = mgr->sample_rate;
+                       if (!rate)
+                               rate = 48000;
+               }
                if (rate) {
                        pcxhr_set_clock(mgr, rate);
                        if (mgr->sample_rate)
This page took 0.02867 seconds and 5 git commands to generate.