ALSA: pcxhr: Add LTC support
add LTC (linear timecode) read function via proc interface to the pcxhr driver Signed-off-by: Markus Bollinger <bollinger@digigram.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
d7dc9e32ae
commit
fdfbaf69e0
6 changed files with 83 additions and 1 deletions
|
@ -1368,6 +1368,67 @@ static void pcxhr_proc_gpo_write(struct snd_info_entry *entry,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Access to the results of the CMD_GET_TIME_CODE RMH */
|
||||||
|
#define TIME_CODE_VALID_MASK 0x00800000
|
||||||
|
#define TIME_CODE_NEW_MASK 0x00400000
|
||||||
|
#define TIME_CODE_BACK_MASK 0x00200000
|
||||||
|
#define TIME_CODE_WAIT_MASK 0x00100000
|
||||||
|
|
||||||
|
/* Values for the CMD_MANAGE_SIGNAL RMH */
|
||||||
|
#define MANAGE_SIGNAL_TIME_CODE 0x01
|
||||||
|
#define MANAGE_SIGNAL_MIDI 0x02
|
||||||
|
|
||||||
|
/* linear time code read proc*/
|
||||||
|
static void pcxhr_proc_ltc(struct snd_info_entry *entry,
|
||||||
|
struct snd_info_buffer *buffer)
|
||||||
|
{
|
||||||
|
struct snd_pcxhr *chip = entry->private_data;
|
||||||
|
struct pcxhr_mgr *mgr = chip->mgr;
|
||||||
|
struct pcxhr_rmh rmh;
|
||||||
|
unsigned int ltcHrs, ltcMin, ltcSec, ltcFrm;
|
||||||
|
int err;
|
||||||
|
/* commands available when embedded DSP is running */
|
||||||
|
if (!(mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX))) {
|
||||||
|
snd_iprintf(buffer, "no firmware loaded\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!mgr->capture_ltc) {
|
||||||
|
pcxhr_init_rmh(&rmh, CMD_MANAGE_SIGNAL);
|
||||||
|
rmh.cmd[0] |= MANAGE_SIGNAL_TIME_CODE;
|
||||||
|
err = pcxhr_send_msg(mgr, &rmh);
|
||||||
|
if (err) {
|
||||||
|
snd_iprintf(buffer, "ltc not activated (%d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mgr->is_hr_stereo)
|
||||||
|
hr222_manage_timecode(mgr, 1);
|
||||||
|
else
|
||||||
|
pcxhr_write_io_num_reg_cont(mgr, REG_CONT_VALSMPTE,
|
||||||
|
REG_CONT_VALSMPTE, NULL);
|
||||||
|
mgr->capture_ltc = 1;
|
||||||
|
}
|
||||||
|
pcxhr_init_rmh(&rmh, CMD_GET_TIME_CODE);
|
||||||
|
err = pcxhr_send_msg(mgr, &rmh);
|
||||||
|
if (err) {
|
||||||
|
snd_iprintf(buffer, "ltc read error (err=%d)\n", err);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
ltcHrs = 10*((rmh.stat[0] >> 8) & 0x3) + (rmh.stat[0] & 0xf);
|
||||||
|
ltcMin = 10*((rmh.stat[1] >> 16) & 0x7) + ((rmh.stat[1] >> 8) & 0xf);
|
||||||
|
ltcSec = 10*(rmh.stat[1] & 0x7) + ((rmh.stat[2] >> 16) & 0xf);
|
||||||
|
ltcFrm = 10*((rmh.stat[2] >> 8) & 0x3) + (rmh.stat[2] & 0xf);
|
||||||
|
|
||||||
|
snd_iprintf(buffer, "timecode: %02u:%02u:%02u-%02u\n",
|
||||||
|
ltcHrs, ltcMin, ltcSec, ltcFrm);
|
||||||
|
snd_iprintf(buffer, "raw: 0x%04x%06x%06x\n", rmh.stat[0] & 0x00ffff,
|
||||||
|
rmh.stat[1] & 0xffffff, rmh.stat[2] & 0xffffff);
|
||||||
|
/*snd_iprintf(buffer, "dsp ref time: 0x%06x%06x\n",
|
||||||
|
rmh.stat[3] & 0xffffff, rmh.stat[4] & 0xffffff);*/
|
||||||
|
if (!(rmh.stat[0] & TIME_CODE_VALID_MASK)) {
|
||||||
|
snd_iprintf(buffer, "warning: linear timecode not valid\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
@ -1383,6 +1444,8 @@ static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip)
|
||||||
entry->c.text.write = pcxhr_proc_gpo_write;
|
entry->c.text.write = pcxhr_proc_gpo_write;
|
||||||
entry->mode |= S_IWUSR;
|
entry->mode |= S_IWUSR;
|
||||||
}
|
}
|
||||||
|
if (!snd_card_proc_new(chip->card, "ltc", &entry))
|
||||||
|
snd_info_set_text_ops(entry, chip, pcxhr_proc_ltc);
|
||||||
}
|
}
|
||||||
/* end of proc interface */
|
/* end of proc interface */
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,7 @@ struct pcxhr_mgr {
|
||||||
unsigned int board_has_mic:1; /* if 1 the board has microphone input */
|
unsigned int board_has_mic:1; /* if 1 the board has microphone input */
|
||||||
unsigned int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */
|
unsigned int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */
|
||||||
unsigned int mono_capture:1; /* if 1 the board does mono capture */
|
unsigned int mono_capture:1; /* if 1 the board does mono capture */
|
||||||
|
unsigned int capture_ltc:1; /* if 1 the board captures LTC input */
|
||||||
|
|
||||||
struct snd_dma_buffer hostport;
|
struct snd_dma_buffer hostport;
|
||||||
|
|
||||||
|
|
|
@ -504,6 +504,8 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = {
|
||||||
[CMD_FORMAT_STREAM_IN] = { 0x870000, 0, RMH_SSIZE_FIXED },
|
[CMD_FORMAT_STREAM_IN] = { 0x870000, 0, RMH_SSIZE_FIXED },
|
||||||
[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED },
|
[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED },
|
||||||
[CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED },
|
[CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED },
|
||||||
|
[CMD_GET_TIME_CODE] = { 0x060000, 5, RMH_SSIZE_FIXED },
|
||||||
|
[CMD_MANAGE_SIGNAL] = { 0x0f0000, 0, RMH_SSIZE_FIXED },
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||||
|
@ -533,6 +535,8 @@ static char* cmd_names[] = {
|
||||||
[CMD_FORMAT_STREAM_IN] = "CMD_FORMAT_STREAM_IN",
|
[CMD_FORMAT_STREAM_IN] = "CMD_FORMAT_STREAM_IN",
|
||||||
[CMD_STREAM_SAMPLE_COUNT] = "CMD_STREAM_SAMPLE_COUNT",
|
[CMD_STREAM_SAMPLE_COUNT] = "CMD_STREAM_SAMPLE_COUNT",
|
||||||
[CMD_AUDIO_LEVEL_ADJUST] = "CMD_AUDIO_LEVEL_ADJUST",
|
[CMD_AUDIO_LEVEL_ADJUST] = "CMD_AUDIO_LEVEL_ADJUST",
|
||||||
|
[CMD_GET_TIME_CODE] = "CMD_GET_TIME_CODE",
|
||||||
|
[CMD_MANAGE_SIGNAL] = "CMD_MANAGE_SIGNAL",
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,8 @@ enum {
|
||||||
CMD_FORMAT_STREAM_IN, /* cmd_len >= 4 stat_len = 0 */
|
CMD_FORMAT_STREAM_IN, /* cmd_len >= 4 stat_len = 0 */
|
||||||
CMD_STREAM_SAMPLE_COUNT, /* cmd_len = 2 stat_len = (2 * nb_stream) */
|
CMD_STREAM_SAMPLE_COUNT, /* cmd_len = 2 stat_len = (2 * nb_stream) */
|
||||||
CMD_AUDIO_LEVEL_ADJUST, /* cmd_len = 3 stat_len = 0 */
|
CMD_AUDIO_LEVEL_ADJUST, /* cmd_len = 3 stat_len = 0 */
|
||||||
|
CMD_GET_TIME_CODE, /* cmd_len = 1 stat_len = 5 */
|
||||||
|
CMD_MANAGE_SIGNAL, /* cmd_len = 1 stat_len = 0 */
|
||||||
CMD_LAST_INDEX
|
CMD_LAST_INDEX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -116,7 +118,7 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh);
|
||||||
#define IO_NUM_REG_OUT_ANA_LEVEL 20
|
#define IO_NUM_REG_OUT_ANA_LEVEL 20
|
||||||
#define IO_NUM_REG_IN_ANA_LEVEL 21
|
#define IO_NUM_REG_IN_ANA_LEVEL 21
|
||||||
|
|
||||||
|
#define REG_CONT_VALSMPTE 0x000800
|
||||||
#define REG_CONT_UNMUTE_INPUTS 0x020000
|
#define REG_CONT_UNMUTE_INPUTS 0x020000
|
||||||
|
|
||||||
/* parameters used with register IO_NUM_REG_STATUS */
|
/* parameters used with register IO_NUM_REG_STATUS */
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#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_SMPTE 0x10
|
||||||
#define PCXHR_DSP_RESET_GPO_OFFSET 5
|
#define PCXHR_DSP_RESET_GPO_OFFSET 5
|
||||||
#define PCXHR_DSP_RESET_GPO_MASK 0x60
|
#define PCXHR_DSP_RESET_GPO_MASK 0x60
|
||||||
|
|
||||||
|
@ -527,6 +528,16 @@ int hr222_write_gpo(struct pcxhr_mgr *mgr, int value)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hr222_manage_timecode(struct pcxhr_mgr *mgr, int enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
mgr->dsp_reset |= PCXHR_DSP_RESET_SMPTE;
|
||||||
|
else
|
||||||
|
mgr->dsp_reset &= ~PCXHR_DSP_RESET_SMPTE;
|
||||||
|
|
||||||
|
PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset);
|
||||||
|
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)
|
||||||
|
|
|
@ -34,6 +34,7 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr,
|
||||||
|
|
||||||
int hr222_read_gpio(struct pcxhr_mgr *mgr, int is_gpi, int *value);
|
int hr222_read_gpio(struct pcxhr_mgr *mgr, int is_gpi, int *value);
|
||||||
int hr222_write_gpo(struct pcxhr_mgr *mgr, int value);
|
int hr222_write_gpo(struct pcxhr_mgr *mgr, int value);
|
||||||
|
int hr222_manage_timecode(struct pcxhr_mgr *mgr, int enable);
|
||||||
|
|
||||||
#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 */
|
||||||
|
|
Loading…
Reference in a new issue