Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fdfbaf69 authored by Markus Bollinger's avatar Markus Bollinger Committed by Takashi Iwai
Browse files

ALSA: pcxhr: Add LTC support



add LTC (linear timecode) read function via proc interface to the pcxhr driver

Signed-off-by: default avatarMarkus Bollinger <bollinger@digigram.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent d7dc9e32
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
@@ -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)
{
	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->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 */

+1 −0
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ struct pcxhr_mgr {
	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 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;

+4 −0
Original line number Diff line number Diff line
@@ -504,6 +504,8 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = {
[CMD_FORMAT_STREAM_IN] =		{ 0x870000, 0, RMH_SSIZE_FIXED },
[CMD_STREAM_SAMPLE_COUNT] =		{ 0x902000, 2, 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
@@ -533,6 +535,8 @@ static char* cmd_names[] = {
[CMD_FORMAT_STREAM_IN] =		"CMD_FORMAT_STREAM_IN",
[CMD_STREAM_SAMPLE_COUNT] =		"CMD_STREAM_SAMPLE_COUNT",
[CMD_AUDIO_LEVEL_ADJUST] =		"CMD_AUDIO_LEVEL_ADJUST",
[CMD_GET_TIME_CODE] =			"CMD_GET_TIME_CODE",
[CMD_MANAGE_SIGNAL] =			"CMD_MANAGE_SIGNAL",
};
#endif

+3 −1
Original line number Diff line number Diff line
@@ -79,6 +79,8 @@ enum {
	CMD_FORMAT_STREAM_IN,		/* cmd_len >= 4	stat_len = 0 */
	CMD_STREAM_SAMPLE_COUNT,	/* cmd_len = 2	stat_len = (2 * nb_stream) */
	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
};

@@ -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_IN_ANA_LEVEL		21


#define REG_CONT_VALSMPTE		0x000800
#define REG_CONT_UNMUTE_INPUTS		0x020000

/* parameters used with register IO_NUM_REG_STATUS */
+11 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@
#define PCXHR_DSP_RESET_DSP	0x01
#define PCXHR_DSP_RESET_MUTE	0x02
#define PCXHR_DSP_RESET_CODEC	0x08
#define PCXHR_DSP_RESET_SMPTE	0x10
#define PCXHR_DSP_RESET_GPO_OFFSET	5
#define PCXHR_DSP_RESET_GPO_MASK	0x60

@@ -527,6 +528,16 @@ int hr222_write_gpo(struct pcxhr_mgr *mgr, int value)
	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 is_capture, int channel)
Loading