static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char aes_bits) { int i, err, cmd; unsigned char new_bits = aes_bits; unsigned char old_bits = chip->aes_bits[aes_idx]; struct pcxhr_rmh rmh; for (i = 0; i < 8; i++) { if ((old_bits & 0x01) != (new_bits & 0x01)) { cmd = chip->chip_idx & 0x03; if (chip->chip_idx > 3) cmd |= 1 << 22; cmd |= ((aes_idx << 3) + i) << 2; cmd |= (new_bits & 0x01) << 23; pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); rmh.cmd[0] |= IO_NUM_REG_CUER; rmh.cmd[1] = cmd; rmh.cmd_len = 2; snd_printdd("write iec958 AES %d byte %d bit %d (cmd %x)\n", chip->chip_idx, aes_idx, i, cmd); err = pcxhr_send_msg(chip->mgr, &rmh); if (err) return err; } old_bits >>= 1; new_bits >>= 1; } chip->aes_bits[aes_idx] = aes_bits; return 0; }
static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe) { struct pcxhr_rmh rmh; int capture_mask = 0; int playback_mask = 0; int err = 0; if (pipe->is_capture) capture_mask = (1 << pipe->first_audio); else playback_mask = (1 << pipe->first_audio); /* stop one pipe */ err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0); if (err < 0) snd_printk(KERN_ERR "error stopping pipe!\n"); /* release the pipe */ pcxhr_init_rmh(&rmh, CMD_FREE_PIPE); pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, 0, 0); err = pcxhr_send_msg(mgr, &rmh); if (err < 0) snd_printk(KERN_ERR "error pipe release (CMD_FREE_PIPE) err(%x)\n", err); pipe->status = PCXHR_PIPE_UNDEFINED; return err; }
static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) { int err, vol; struct pcxhr_rmh rmh; pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); if (is_capture) { rmh.cmd[0] |= IO_NUM_REG_IN_ANA_LEVEL; rmh.cmd[2] = chip->analog_capture_volume[channel]; } else { rmh.cmd[0] |= IO_NUM_REG_OUT_ANA_LEVEL; if (chip->analog_playback_active[channel]) vol = chip->analog_playback_volume[channel]; else vol = PCXHR_LINE_PLAYBACK_LEVEL_MIN; rmh.cmd[2] = PCXHR_LINE_PLAYBACK_LEVEL_MAX - vol; } rmh.cmd[1] = 1 << ((2 * chip->chip_idx) + channel); rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err < 0) { snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)" " is_capture(%d) err(%x)\n", chip->chip_idx, is_capture, err); return -EINVAL; } return 0; }
static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx) { int err; struct pcxhr_rmh rmh; struct pcxhr_pipe *pipe = &chip->playback_pipe; int left, right; if (chip->digital_playback_active[idx][0]) left = chip->digital_playback_volume[idx][0]; else left = PCXHR_DIGITAL_LEVEL_MIN; if (chip->digital_playback_active[idx][1]) right = chip->digital_playback_volume[idx][1]; else right = PCXHR_DIGITAL_LEVEL_MIN; pcxhr_init_rmh(&rmh, CMD_STREAM_OUT_LEVEL_ADJUST); pcxhr_set_pipe_cmd_params(&rmh, 0, pipe->first_audio, 0, 1<<idx); rmh.cmd[0] |= MORE_THAN_ONE_STREAM_LEVEL; rmh.cmd[2] = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_1_MASK; rmh.cmd[2] |= (left << 10); rmh.cmd[3] = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_2_MASK; rmh.cmd[3] |= right; rmh.cmd_len = 4; err = pcxhr_send_msg(chip->mgr, &rmh); if (err < 0) { snd_printk(KERN_DEBUG "error update_playback_stream_level " "card(%d) err(%x)\n", chip->chip_idx, err); return -EINVAL; } return 0; }
/* * allocate a playback/capture pipe (pcmp0/pcmc0) */ static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe, int is_capture, int pin) { int stream_count, audio_count; int err; struct pcxhr_rmh rmh; if (is_capture) { stream_count = 1; if (mgr->mono_capture) audio_count = 1; else audio_count = 2; } else { stream_count = PCXHR_PLAYBACK_STREAMS; audio_count = 2; /* always stereo */ } snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", pin, is_capture ? 'c' : 'p'); pipe->is_capture = is_capture; pipe->first_audio = pin; /* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */ pcxhr_init_rmh(&rmh, CMD_RES_PIPE); pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, audio_count, stream_count); err = pcxhr_send_msg(mgr, &rmh); if (err < 0) { snd_printk(KERN_ERR "error pipe allocation (CMD_RES_PIPE) err=%x!\n", err ); return err; } pipe->status = PCXHR_PIPE_DEFINED; return 0; }
static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char aes_bits) { int i, err, cmd; unsigned char new_bits = aes_bits; unsigned char old_bits = chip->aes_bits[aes_idx]; struct pcxhr_rmh rmh; for (i = 0; i < 8; i++) { if ((old_bits & 0x01) != (new_bits & 0x01)) { cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ if (chip->chip_idx > 3) /* new bit used if chip_idx>3 (PCX1222HR) */ cmd |= 1 << 22; cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ cmd |= (new_bits & 0x01) << 23; /* add bit value */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); rmh.cmd[0] |= IO_NUM_REG_CUER; rmh.cmd[1] = cmd; rmh.cmd_len = 2; dev_dbg(chip->card->dev, "write iec958 AES %d byte %d bit %d (cmd %x)\n", chip->chip_idx, aes_idx, i, cmd); err = pcxhr_send_msg(chip->mgr, &rmh); if (err) return err; } old_bits >>= 1; new_bits >>= 1; } chip->aes_bits[aes_idx] = aes_bits; return 0; }
static int pcxhr_set_audio_source(struct snd_pcxhr* chip) { struct pcxhr_rmh rmh; unsigned int mask, reg; unsigned int codec; int err, use_src, changed; switch (chip->chip_idx) { case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break; case 1 : mask = PCXHR_SOURCE_AUDIO23_UER; codec = CS8420_23_CS; break; case 2 : mask = PCXHR_SOURCE_AUDIO45_UER; codec = CS8420_45_CS; break; case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break; default: return -EINVAL; } reg = 0; /* audio source from analog plug */ use_src = 0; /* do not activate codec SRC */ if (chip->audio_capture_source != 0) { reg = mask; /* audio source from digital plug */ if (chip->audio_capture_source == 2) use_src = 1; } /* set the input source */ pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed); /* resync them (otherwise channel inversion possible) */ if (changed) { pcxhr_init_rmh(&rmh, CMD_RESYNC_AUDIO_INPUTS); rmh.cmd[0] |= (1 << chip->chip_idx); err = pcxhr_send_msg(chip->mgr, &rmh); if (err) return err; } pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set codec SRC on off */ rmh.cmd_len = 3; rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; rmh.cmd[1] = codec; rmh.cmd[2] = (CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x54); err = pcxhr_send_msg(chip->mgr, &rmh); if(err) return err; rmh.cmd[2] = (CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x49); err = pcxhr_send_msg(chip->mgr, &rmh); return err; }
static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, int capture, int channel) { int err; struct pcxhr_rmh rmh; struct pcxhr_pipe *pipe; if (capture) pipe = &chip->capture_pipe[0]; else pipe = &chip->playback_pipe; pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); /* add channel mask */ pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, 1 << (channel + pipe->first_audio)); /* TODO : if mask (3 << pipe->first_audio) is used, left and right * channel will be programmed to the same params */ if (capture) { rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled * (capture pipe level) */ rmh.cmd[2] = chip->digital_capture_volume[channel]; } else { rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | VALID_AUDIO_IO_MUTE_MONITOR_1; /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL * not yet handled (playback pipe level) */ rmh.cmd[2] = chip->monitoring_volume[channel] << 10; if (chip->monitoring_active[channel] == 0) rmh.cmd[2] |= AUDIO_IO_HAS_MUTE_MONITOR_1; } rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err < 0) { dev_dbg(chip->card->dev, "error update_audio_level(%d) err=%x\n", chip->chip_idx, err); return -EINVAL; } return 0; }
void pcxhr_reset_board(struct pcxhr_mgr *mgr) { struct pcxhr_rmh rmh; if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) { /* mute outputs */ /* a read to IO_NUM_REG_MUTE_OUT register unmutes! */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; pcxhr_send_msg(mgr, &rmh); /* mute inputs */ pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, 0, NULL); } /* reset pcxhr dsp */ if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX)) pcxhr_reset_dsp(mgr); /* reset second xilinx */ if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) pcxhr_reset_xilinx_com(mgr); return; }
static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char* aes_bits) { int i, err; unsigned char temp; struct pcxhr_rmh rmh; pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; switch (chip->chip_idx) { case 0: rmh.cmd[1] = CS8420_01_CS; break; /* use CS8416_01_CS for AES SYNC plug */ case 1: rmh.cmd[1] = CS8420_23_CS; break; case 2: rmh.cmd[1] = CS8420_45_CS; break; case 3: rmh.cmd[1] = CS8420_67_CS; break; default: return -EINVAL; } switch (aes_idx) { case 0: rmh.cmd[2] = CS8420_CSB0; break; /* use CS8416_CSBx for AES SYNC plug */ case 1: rmh.cmd[2] = CS8420_CSB1; break; case 2: rmh.cmd[2] = CS8420_CSB2; break; case 3: rmh.cmd[2] = CS8420_CSB3; break; case 4: rmh.cmd[2] = CS8420_CSB4; break; default: return -EINVAL; } rmh.cmd[1] &= 0x0fffff; /* size and code the chip id for the fpga */ rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; /* chip signature + map for spi read */ rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) return err; temp = 0; for (i = 0; i < 8; i++) { /* attention : reversed bit order (not with CS8416_01_CS) */ temp <<= 1; if (rmh.stat[1] & (1 << i)) temp |= 1; } snd_printdd("read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp); *aes_bits = temp; return 0; }
static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, int capture, int channel) { int err; struct pcxhr_rmh rmh; struct pcxhr_pipe *pipe; if (capture) pipe = &chip->capture_pipe[0]; else pipe = &chip->playback_pipe; pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, 1 << (channel + pipe->first_audio)); if (capture) { rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; rmh.cmd[2] = chip->digital_capture_volume[channel]; } else { rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | VALID_AUDIO_IO_MUTE_MONITOR_1; rmh.cmd[2] = chip->monitoring_volume[channel] << 10; if (chip->monitoring_active[channel] == 0) rmh.cmd[2] |= AUDIO_IO_HAS_MUTE_MONITOR_1; } rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err < 0) { snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n", chip->chip_idx, err); return -EINVAL; } return 0; }
static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char *aes_bits) { int i, err; unsigned char temp; struct pcxhr_rmh rmh; pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; switch (chip->chip_idx) { case 0: rmh.cmd[1] = CS8420_01_CS; break; case 1: rmh.cmd[1] = CS8420_23_CS; break; case 2: rmh.cmd[1] = CS8420_45_CS; break; case 3: rmh.cmd[1] = CS8420_67_CS; break; default: return -EINVAL; } if (chip->mgr->board_aes_in_192k) { switch (aes_idx) { case 0: rmh.cmd[2] = CS8416_CSB0; break; case 1: rmh.cmd[2] = CS8416_CSB1; break; case 2: rmh.cmd[2] = CS8416_CSB2; break; case 3: rmh.cmd[2] = CS8416_CSB3; break; case 4: rmh.cmd[2] = CS8416_CSB4; break; default: return -EINVAL; } } else { switch (aes_idx) { case 0: rmh.cmd[2] = CS8420_CSB0; break; case 1: rmh.cmd[2] = CS8420_CSB1; break; case 2: rmh.cmd[2] = CS8420_CSB2; break; case 3: rmh.cmd[2] = CS8420_CSB3; break; case 4: rmh.cmd[2] = CS8420_CSB4; break; default: return -EINVAL; } } rmh.cmd[1] &= 0x0fffff; rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) return err; if (chip->mgr->board_aes_in_192k) { temp = (unsigned char)rmh.stat[1]; } else { temp = 0; for (i = 0; i < 8; i++) { temp <<= 1; if (rmh.stat[1] & (1 << i)) temp |= 1; } } snd_printdd("read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp); *aes_bits = temp; return 0; }
static int pcxhr_set_audio_source(struct snd_pcxhr* chip) { struct pcxhr_rmh rmh; unsigned int mask, reg; unsigned int codec; int err, changed; switch (chip->chip_idx) { case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break; case 1 : mask = PCXHR_SOURCE_AUDIO23_UER; codec = CS8420_23_CS; break; case 2 : mask = PCXHR_SOURCE_AUDIO45_UER; codec = CS8420_45_CS; break; case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break; default: return -EINVAL; } if (chip->audio_capture_source != 0) { reg = mask; } else { reg = 0; } pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed); if (changed) { pcxhr_init_rmh(&rmh, CMD_RESYNC_AUDIO_INPUTS); rmh.cmd[0] |= (1 << chip->chip_idx); err = pcxhr_send_msg(chip->mgr, &rmh); if (err) return err; } if (chip->mgr->board_aes_in_192k) { int i; unsigned int src_config = 0xC0; for (i = 0; (i < 4) && (i < chip->mgr->capture_chips); i++) { if (chip->mgr->chip[i]->audio_capture_source == 2) src_config |= (1 << (3 - i)); } pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); rmh.cmd_len = 2; rmh.cmd[0] |= IO_NUM_REG_CONFIG_SRC; rmh.cmd[1] = src_config; err = pcxhr_send_msg(chip->mgr, &rmh); } else { int use_src = 0; if (chip->audio_capture_source == 2) use_src = 1; pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); rmh.cmd_len = 3; rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; rmh.cmd[1] = codec; rmh.cmd[2] = ((CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x54)); err = pcxhr_send_msg(chip->mgr, &rmh); if (err) return err; rmh.cmd[2] = ((CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x49)); err = pcxhr_send_msg(chip->mgr, &rmh); } return err; }
static int pcxhr_init_board(struct pcxhr_mgr *mgr) { int err; struct pcxhr_rmh rmh; int card_streams; /* calc the number of all streams used */ if (mgr->mono_capture) card_streams = mgr->capture_chips * 2; else card_streams = mgr->capture_chips; card_streams += mgr->playback_chips * PCXHR_PLAYBACK_STREAMS; /* enable interrupts */ pcxhr_enable_dsp(mgr); pcxhr_init_rmh(&rmh, CMD_SUPPORTED); err = pcxhr_send_msg(mgr, &rmh); if (err) return err; /* test 8 or 12 phys out */ snd_assert((rmh.stat[0] & MASK_FIRST_FIELD) == mgr->playback_chips*2, return -EINVAL); /* test 8 or 2 phys in */ snd_assert(((rmh.stat[0] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD) == mgr->capture_chips * 2, return -EINVAL); /* test max nb substream per board */ snd_assert((rmh.stat[1] & 0x5F) >= card_streams, return -EINVAL); /* test max nb substream per pipe */ snd_assert(((rmh.stat[1]>>7)&0x5F) >= PCXHR_PLAYBACK_STREAMS, return -EINVAL); pcxhr_init_rmh(&rmh, CMD_VERSION); /* firmware num for DSP */ rmh.cmd[0] |= mgr->firmware_num; /* transfer granularity in samples (should be multiple of 48) */ rmh.cmd[1] = (1<<23) + PCXHR_GRANULARITY; rmh.cmd_len = 2; err = pcxhr_send_msg(mgr, &rmh); if (err) return err; snd_printdd("PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff, (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff); mgr->dsp_version = rmh.stat[0]; /* get options */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd[0] |= IO_NUM_REG_STATUS; rmh.cmd[1] = REG_STATUS_OPTIONS; rmh.cmd_len = 2; err = pcxhr_send_msg(mgr, &rmh); if (err) return err; if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == REG_STATUS_OPT_ANALOG_BOARD) mgr->board_has_analog = 1; /* analog addon board available */ else /* analog addon board not available -> no support for instance */ return -EINVAL; /* unmute inputs */ err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, REG_CONT_UNMUTE_INPUTS, NULL); if (err) return err; /* unmute outputs */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* a write to IO_NUM_REG_MUTE_OUT mutes! */ rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; err = pcxhr_send_msg(mgr, &rmh); return err; }