Commit 55aef450 authored by Markus Bollinger's avatar Markus Bollinger Committed by Takashi Iwai

ALSA: pcxhr - add support for gpio ports and minor bug fix

- 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: default avatarMarkus Bollinger <bollinger@digigram.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 1de9e8e7
...@@ -1334,6 +1334,40 @@ static void pcxhr_proc_sync(struct snd_info_entry *entry, ...@@ -1334,6 +1334,40 @@ static void pcxhr_proc_sync(struct snd_info_entry *entry,
snd_iprintf(buffer, "\n"); 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) static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip)
{ {
struct snd_info_entry *entry; struct snd_info_entry *entry;
...@@ -1342,6 +1376,13 @@ static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip) ...@@ -1342,6 +1376,13 @@ static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip)
snd_info_set_text_ops(entry, chip, pcxhr_proc_info); snd_info_set_text_ops(entry, chip, pcxhr_proc_info);
if (! snd_card_proc_new(chip->card, "sync", &entry)) if (! snd_card_proc_new(chip->card, "sync", &entry))
snd_info_set_text_ops(entry, chip, pcxhr_proc_sync); 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 */ /* end of proc interface */
......
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#define PCXHR_DRIVER_VERSION 0x000905 /* 0.9.5 */ #define PCXHR_DRIVER_VERSION 0x000906 /* 0.9.6 */
#define PCXHR_DRIVER_VERSION_STRING "0.9.5" /* 0.9.5 */ #define PCXHR_DRIVER_VERSION_STRING "0.9.6" /* 0.9.6 */
#define PCXHR_MAX_CARDS 6 #define PCXHR_MAX_CARDS 6
...@@ -124,6 +124,7 @@ struct pcxhr_mgr { ...@@ -124,6 +124,7 @@ struct pcxhr_mgr {
unsigned char xlx_cfg; /* copy of PCXHR_XLX_CFG register */ unsigned char xlx_cfg; /* copy of PCXHR_XLX_CFG register */
unsigned char xlx_selmic; /* copy of PCXHR_XLX_SELMIC register */ unsigned char xlx_selmic; /* copy of PCXHR_XLX_SELMIC register */
unsigned char dsp_reset; /* copy of PCXHR_DSP_RESET register */
}; };
......
...@@ -53,6 +53,8 @@ ...@@ -53,6 +53,8 @@
#define PCXHR_DSP_RESET_DSP 0x01 #define PCXHR_DSP_RESET_DSP 0x01
#define PCXHR_DSP_RESET_MUTE 0x02 #define PCXHR_DSP_RESET_MUTE 0x02
#define PCXHR_DSP_RESET_CODEC 0x08 #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 */ /* values for PCHR_XLX_CFG register */
#define PCXHR_CFG_SYNCDSP_MASK 0x80 #define PCXHR_CFG_SYNCDSP_MASK 0x80
...@@ -81,6 +83,8 @@ ...@@ -81,6 +83,8 @@
/* values for PCHR_XLX_STATUS register - READ */ /* values for PCHR_XLX_STATUS register - READ */
#define PCXHR_STAT_SRC_LOCK 0x01 #define PCXHR_STAT_SRC_LOCK 0x01
#define PCXHR_STAT_LEVEL_IN 0x02 #define PCXHR_STAT_LEVEL_IN 0x02
#define PCXHR_STAT_GPI_OFFSET 2
#define PCXHR_STAT_GPI_MASK 0x0C
#define PCXHR_STAT_MIC_CAPS 0x10 #define PCXHR_STAT_MIC_CAPS 0x10
/* values for PCHR_XLX_STATUS register - WRITE */ /* values for PCHR_XLX_STATUS register - WRITE */
#define PCXHR_STAT_FREQ_SYNC_MASK 0x01 #define PCXHR_STAT_FREQ_SYNC_MASK 0x01
...@@ -291,10 +295,11 @@ int hr222_sub_init(struct pcxhr_mgr *mgr) ...@@ -291,10 +295,11 @@ int hr222_sub_init(struct pcxhr_mgr *mgr)
PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
PCXHR_DSP_RESET_DSP); PCXHR_DSP_RESET_DSP);
msleep(5); msleep(5);
PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset = PCXHR_DSP_RESET_DSP |
PCXHR_DSP_RESET_DSP | PCXHR_DSP_RESET_MUTE |
PCXHR_DSP_RESET_MUTE | PCXHR_DSP_RESET_CODEC;
PCXHR_DSP_RESET_CODEC); PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset);
/* hr222_write_gpo(mgr, 0); does the same */
msleep(5); msleep(5);
/* config AKM */ /* config AKM */
...@@ -496,6 +501,33 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr, ...@@ -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 hr222_update_analog_audio_level(struct snd_pcxhr *chip,
int is_capture, int channel) int is_capture, int channel)
{ {
......
...@@ -32,6 +32,9 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr, ...@@ -32,6 +32,9 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr,
enum pcxhr_clock_type clock_type, enum pcxhr_clock_type clock_type,
int *sample_rate); 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_LEVEL_MIN 0 /* -25.5 dB */
#define HR222_LINE_PLAYBACK_ZERO_LEVEL 51 /* 0.0 dB */ #define HR222_LINE_PLAYBACK_ZERO_LEVEL 51 /* 0.0 dB */
#define HR222_LINE_PLAYBACK_LEVEL_MAX 99 /* +24.0 dB */ #define HR222_LINE_PLAYBACK_LEVEL_MAX 99 /* +24.0 dB */
......
...@@ -789,11 +789,15 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, ...@@ -789,11 +789,15 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol,
if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) { if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) {
mutex_lock(&mgr->setup_mutex); mutex_lock(&mgr->setup_mutex);
mgr->use_clock_type = ucontrol->value.enumerated.item[0]; 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, pcxhr_get_external_clock(mgr, mgr->use_clock_type,
&rate); &rate);
else } else {
rate = mgr->sample_rate; rate = mgr->sample_rate;
if (!rate)
rate = 48000;
}
if (rate) { if (rate) {
pcxhr_set_clock(mgr, rate); pcxhr_set_clock(mgr, rate);
if (mgr->sample_rate) if (mgr->sample_rate)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment