/* * Default values for the effect slider controls, they are in order of their * effect NID's. Surround, Crystalizer, Dialog Plus, Smart Volume, and then * X-bass.
*/ staticconstunsignedint effect_slider_defaults[] = {67, 65, 50, 74, 50}; /* Amount of effect level sliders for ca0132_alt controls. */ #define EFFECT_LEVEL_SLIDERS 5
/* * DSP reqs for handling full-range speakers/bass redirection. If a speaker is * set as not being full range, and bass redirection is enabled, all * frequencies below the crossover frequency are redirected to the LFE * channel. If the surround configuration has no LFE channel, this can't be * enabled. X-Bass must be disabled when using these.
*/ enum speaker_range_reqs {
SPEAKER_BASS_REDIRECT = 0x15,
SPEAKER_BASS_REDIRECT_XOVER_FREQ = 0x16, /* Between 0x16-0x1a are the X-Bass reqs. */
SPEAKER_FULL_RANGE_FRONT_L_R = 0x1a,
SPEAKER_FULL_RANGE_CENTER_LFE = 0x1b,
SPEAKER_FULL_RANGE_REAR_L_R = 0x1c,
SPEAKER_FULL_RANGE_SURROUND_L_R = 0x1d,
SPEAKER_BASS_REDIRECT_SUB_GAIN = 0x1e,
};
/* * Definitions for the DSP req's to handle speaker tuning. These all belong to * module ID 0x96, the output effects module.
*/ enum speaker_tuning_reqs { /* * Currently, this value is always set to 0.0f. However, on Windows, * when selecting certain headphone profiles on the new Sound Blaster * connect software, the QUERY_SPEAKER_EQ_ADDRESS req on mid 0x80 is * sent. This gets the speaker EQ address area, which is then used to * send over (presumably) an equalizer profile for the specific * headphone setup. It is sent using the same method the DSP * firmware is uploaded with, which I believe is why the 'ctspeq.bin' * file exists in linux firmware tree but goes unused. It would also * explain why the QUERY_SPEAKER_EQ_ADDRESS req is defined but unused. * Once this profile is sent over, SPEAKER_TUNING_USE_SPEAKER_EQ is * set to 1.0f.
*/
SPEAKER_TUNING_USE_SPEAKER_EQ = 0x1f,
SPEAKER_TUNING_ENABLE_CENTER_EQ = 0x20,
SPEAKER_TUNING_FRONT_LEFT_VOL_LEVEL = 0x21,
SPEAKER_TUNING_FRONT_RIGHT_VOL_LEVEL = 0x22,
SPEAKER_TUNING_CENTER_VOL_LEVEL = 0x23,
SPEAKER_TUNING_LFE_VOL_LEVEL = 0x24,
SPEAKER_TUNING_REAR_LEFT_VOL_LEVEL = 0x25,
SPEAKER_TUNING_REAR_RIGHT_VOL_LEVEL = 0x26,
SPEAKER_TUNING_SURROUND_LEFT_VOL_LEVEL = 0x27,
SPEAKER_TUNING_SURROUND_RIGHT_VOL_LEVEL = 0x28, /* * Inversion is used when setting headphone virtualization to line * out. Not sure why this is, but it's the only place it's ever used.
*/
SPEAKER_TUNING_FRONT_LEFT_INVERT = 0x29,
SPEAKER_TUNING_FRONT_RIGHT_INVERT = 0x2a,
SPEAKER_TUNING_CENTER_INVERT = 0x2b,
SPEAKER_TUNING_LFE_INVERT = 0x2c,
SPEAKER_TUNING_REAR_LEFT_INVERT = 0x2d,
SPEAKER_TUNING_REAR_RIGHT_INVERT = 0x2e,
SPEAKER_TUNING_SURROUND_LEFT_INVERT = 0x2f,
SPEAKER_TUNING_SURROUND_RIGHT_INVERT = 0x30, /* Delay is used when setting surround speaker distance in Windows. */
SPEAKER_TUNING_FRONT_LEFT_DELAY = 0x31,
SPEAKER_TUNING_FRONT_RIGHT_DELAY = 0x32,
SPEAKER_TUNING_CENTER_DELAY = 0x33,
SPEAKER_TUNING_LFE_DELAY = 0x34,
SPEAKER_TUNING_REAR_LEFT_DELAY = 0x35,
SPEAKER_TUNING_REAR_RIGHT_DELAY = 0x36,
SPEAKER_TUNING_SURROUND_LEFT_DELAY = 0x37,
SPEAKER_TUNING_SURROUND_RIGHT_DELAY = 0x38, /* Of these two, only mute seems to ever be used. */
SPEAKER_TUNING_MAIN_VOLUME = 0x39,
SPEAKER_TUNING_MUTE = 0x3a,
};
/* * DSP volume setting structs. Req 1 is left volume, req 2 is right volume, * and I don't know what the third req is, but it's always zero. I assume it's * some sort of update or set command to tell the DSP there's new volume info.
*/ #define DSP_VOL_OUT 0 #define DSP_VOL_IN 1
struct ct_dsp_volume_ctl {
hda_nid_t vnid; int mid; /* module ID*/ unsignedint reqs[3]; /* scp req ID */
};
/* * Data structures for storing audio router remapping data. These are used to * remap a currently active streams ports.
*/ struct chipio_stream_remap_data { unsignedint stream_id; unsignedint count;
/* * Control flag IDs
*/ enum control_flag_id { /* Connection manager stream setup is bypassed/enabled */
CONTROL_FLAG_C_MGR = 0, /* DSP DMA is bypassed/enabled */
CONTROL_FLAG_DMA = 1, /* 8051 'idle' mode is disabled/enabled */
CONTROL_FLAG_IDLE_ENABLE = 2, /* Tracker for the SPDIF-in path is bypassed/enabled */
CONTROL_FLAG_TRACKER = 3, /* DigitalOut to Spdif2Out connection is disabled/enabled */
CONTROL_FLAG_SPDIF2OUT = 4, /* Digital Microphone is disabled/enabled */
CONTROL_FLAG_DMIC = 5, /* ADC_B rate is 48 kHz/96 kHz */
CONTROL_FLAG_ADC_B_96KHZ = 6, /* ADC_C rate is 48 kHz/96 kHz */
CONTROL_FLAG_ADC_C_96KHZ = 7, /* DAC rate is 48 kHz/96 kHz (affects all DACs) */
CONTROL_FLAG_DAC_96KHZ = 8, /* DSP rate is 48 kHz/96 kHz */
CONTROL_FLAG_DSP_96KHZ = 9, /* SRC clock is 98 MHz/196 MHz (196 MHz forces rate to 96 KHz) */
CONTROL_FLAG_SRC_CLOCK_196MHZ = 10, /* SRC rate is 48 kHz/96 kHz (48 kHz disabled when clock is 196 MHz) */
CONTROL_FLAG_SRC_RATE_96KHZ = 11, /* Decode Loop (DSP->SRC->DSP) is disabled/enabled */
CONTROL_FLAG_DECODE_LOOP = 12, /* De-emphasis filter on DAC-1 disabled/enabled */
CONTROL_FLAG_DAC1_DEEMPHASIS = 13, /* De-emphasis filter on DAC-2 disabled/enabled */
CONTROL_FLAG_DAC2_DEEMPHASIS = 14, /* De-emphasis filter on DAC-3 disabled/enabled */
CONTROL_FLAG_DAC3_DEEMPHASIS = 15, /* High-pass filter on ADC_B disabled/enabled */
CONTROL_FLAG_ADC_B_HIGH_PASS = 16, /* High-pass filter on ADC_C disabled/enabled */
CONTROL_FLAG_ADC_C_HIGH_PASS = 17, /* Common mode on Port_A disabled/enabled */
CONTROL_FLAG_PORT_A_COMMON_MODE = 18, /* Common mode on Port_D disabled/enabled */
CONTROL_FLAG_PORT_D_COMMON_MODE = 19, /* Impedance for ramp generator on Port_A 16 Ohm/10K Ohm */
CONTROL_FLAG_PORT_A_10KOHM_LOAD = 20, /* Impedance for ramp generator on Port_D, 16 Ohm/10K Ohm */
CONTROL_FLAG_PORT_D_10KOHM_LOAD = 21, /* ASI rate is 48kHz/96kHz */
CONTROL_FLAG_ASI_96KHZ = 22, /* DAC power settings able to control attached ports no/yes */
CONTROL_FLAG_DACS_CONTROL_PORTS = 23, /* Clock Stop OK reporting is disabled/enabled */
CONTROL_FLAG_CONTROL_STOP_OK_ENABLE = 24, /* Number of control flags */
CONTROL_FLAGS_MAX = (CONTROL_FLAG_CONTROL_STOP_OK_ENABLE+1)
};
/* * Control parameter IDs
*/ enum control_param_id { /* 0: None, 1: Mic1In*/
CONTROL_PARAM_VIP_SOURCE = 1, /* 0: force HDA, 1: allow DSP if HDA Spdif1Out stream is idle */
CONTROL_PARAM_SPDIF1_SOURCE = 2, /* Port A output stage gain setting to use when 16 Ohm output
* impedance is selected*/
CONTROL_PARAM_PORTA_160OHM_GAIN = 8, /* Port D output stage gain setting to use when 16 Ohm output
* impedance is selected*/
CONTROL_PARAM_PORTD_160OHM_GAIN = 10,
/* * This control param name was found in the 8051 memory, and makes * sense given the fact the AE-5 uses it and has the ASI flag set.
*/
CONTROL_PARAM_ASI = 23,
/* Stream Control */
/* Select stream with the given ID */
CONTROL_PARAM_STREAM_ID = 24, /* Source connection point for the selected stream */
CONTROL_PARAM_STREAM_SOURCE_CONN_POINT = 25, /* Destination connection point for the selected stream */
CONTROL_PARAM_STREAM_DEST_CONN_POINT = 26, /* Number of audio channels in the selected stream */
CONTROL_PARAM_STREAMS_CHANNELS = 27, /*Enable control for the selected stream */
CONTROL_PARAM_STREAM_CONTROL = 28,
/* Connection Point Control */
/* Select connection point with the given ID */
CONTROL_PARAM_CONN_POINT_ID = 29, /* Connection point sample rate */
CONTROL_PARAM_CONN_POINT_SAMPLE_RATE = 30,
/* Node Control */
/* Select HDA node with the given ID */
CONTROL_PARAM_NODE_ID = 31
};
/* * Dsp Io Status codes
*/ enum hda_vendor_status_dspio { /* Success */
VENDOR_STATUS_DSPIO_OK = 0x00, /* Busy, unable to accept new command, the host must retry */
VENDOR_STATUS_DSPIO_BUSY = 0x01, /* SCP command queue is full */
VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL = 0x02, /* SCP response queue is empty */
VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY = 0x03
};
/* * Chip Io Status codes
*/ enum hda_vendor_status_chipio { /* Success */
VENDOR_STATUS_CHIPIO_OK = 0x00, /* Busy, unable to accept new command, the host must retry */
VENDOR_STATUS_CHIPIO_BUSY = 0x01
};
/* mixer and effects related */ unsignedchar dmic_ctl; int cur_out_type; int cur_mic_type; long vnode_lvol[VNODES_COUNT]; long vnode_rvol[VNODES_COUNT]; long vnode_lswitch[VNODES_COUNT]; long vnode_rswitch[VNODES_COUNT]; long effects_switch[EFFECTS_COUNT]; long voicefx_val; long cur_mic_boost; /* ca0132_alt control related values */ unsignedchar in_enum_val; unsignedchar out_enum_val; unsignedchar channel_cfg_val; unsignedchar speaker_range_val[2]; unsignedchar mic_boost_enum_val; unsignedchar smart_volume_setting; unsignedchar bass_redirection_val; long bass_redirect_xover_freq; long fx_ctl_val[EFFECT_LEVEL_SLIDERS]; long xbass_xover_freq; long eq_preset_val; unsignedint tlv[4]; struct hda_vmaster_mute_hook vmaster_mute; /* AE-5 Control values */ unsignedchar ae5_headphone_gain_val; unsignedchar ae5_filter_val; /* ZxR Control Values */ unsignedchar zxr_gain_set;
#ifdef ENABLE_TUNING_CONTROLS long cur_ctl_vals[TUNING_CTLS_COUNT]; #endif /* * The Recon3D, Sound Blaster Z, Sound Blaster ZxR, and Sound Blaster * AE-5 all use PCI region 2 to toggle GPIO and other currently unknown * things.
*/ bool use_pci_mmio; void __iomem *mem_base;
/* * Whether or not to use the alt functions like alt_select_out, * alt_select_in, etc. Only used on desktop codecs for now, because of * surround sound support.
*/ bool use_alt_functions;
/* * Whether or not to use alt controls: volume effect sliders, EQ * presets, smart volume presets, and new control names with FX prefix. * Renames PlayEnhancement and CrystalVoice too.
*/ bool use_alt_controls;
};
/* Sound Blaster Z pin configs taken from Windows Driver */ staticconststruct hda_pintbl sbz_pincfgs[] = {
{ 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */
{ 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
{ 0x0d, 0x014510f0 }, /* Digital Out */
{ 0x0e, 0x01c510f0 }, /* SPDIF In */
{ 0x0f, 0x0221701f }, /* Port A -- BackPanel HP */
{ 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */
{ 0x11, 0x01017014 }, /* Port B -- LineMicIn2 / Rear L/R */
{ 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */
{ 0x13, 0x908700f0 }, /* What U Hear In*/
{ 0x18, 0x50d000f0 }, /* N/A */
{}
};
/* Sound Blaster ZxR pin configs taken from Windows Driver */ staticconststruct hda_pintbl zxr_pincfgs[] = {
{ 0x0b, 0x01047110 }, /* Port G -- Lineout FRONT L/R */
{ 0x0c, 0x414510f0 }, /* SPDIF Out 1 - Disabled*/
{ 0x0d, 0x014510f0 }, /* Digital Out */
{ 0x0e, 0x41c520f0 }, /* SPDIF In - Disabled*/
{ 0x0f, 0x0122711f }, /* Port A -- BackPanel HP */
{ 0x10, 0x01017111 }, /* Port D -- Center/LFE */
{ 0x11, 0x01017114 }, /* Port B -- LineMicIn2 / Rear L/R */
{ 0x12, 0x01a271f0 }, /* Port C -- LineIn1 */
{ 0x13, 0x908700f0 }, /* What U Hear In*/
{ 0x18, 0x50d000f0 }, /* N/A */
{}
};
/* Recon3D pin configs taken from Windows Driver */ staticconststruct hda_pintbl r3d_pincfgs[] = {
{ 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
{ 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
{ 0x0d, 0x014510f0 }, /* Digital Out */
{ 0x0e, 0x01c520f0 }, /* SPDIF In */
{ 0x0f, 0x0221401f }, /* Port A -- BackPanel HP */
{ 0x10, 0x01016011 }, /* Port D -- Center/LFE or FP Hp */
{ 0x11, 0x01011014 }, /* Port B -- LineMicIn2 / Rear L/R */
{ 0x12, 0x02a090f0 }, /* Port C -- LineIn1 */
{ 0x13, 0x908700f0 }, /* What U Hear In*/
{ 0x18, 0x50d000f0 }, /* N/A */
{}
};
/* Sound Blaster AE-5 pin configs taken from Windows Driver */ staticconststruct hda_pintbl ae5_pincfgs[] = {
{ 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */
{ 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
{ 0x0d, 0x014510f0 }, /* Digital Out */
{ 0x0e, 0x01c510f0 }, /* SPDIF In */
{ 0x0f, 0x01017114 }, /* Port A -- Rear L/R. */
{ 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */
{ 0x11, 0x012170ff }, /* Port B -- LineMicIn2 / Rear Headphone */
{ 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */
{ 0x13, 0x908700f0 }, /* What U Hear In*/
{ 0x18, 0x50d000f0 }, /* N/A */
{}
};
/* Recon3D integrated pin configs taken from Windows Driver */ staticconststruct hda_pintbl r3di_pincfgs[] = {
{ 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
{ 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
{ 0x0d, 0x014510f0 }, /* Digital Out */
{ 0x0e, 0x41c520f0 }, /* SPDIF In */
{ 0x0f, 0x0221401f }, /* Port A -- BackPanel HP */
{ 0x10, 0x01016011 }, /* Port D -- Center/LFE or FP Hp */
{ 0x11, 0x01011014 }, /* Port B -- LineMicIn2 / Rear L/R */
{ 0x12, 0x02a090f0 }, /* Port C -- LineIn1 */
{ 0x13, 0x908700f0 }, /* What U Hear In*/
{ 0x18, 0x500000f0 }, /* N/A */
{}
};
/* send bits of data specified by reg */ do {
res = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
reg, data); if (res == VENDOR_STATUS_CHIPIO_OK) return 0;
msleep(20);
} while (time_before(jiffies, timeout));
return -EIO;
}
/* * Write chip address through the vendor widget -- NOT protected by the Mutex!
*/ staticint chipio_write_address(struct hda_codec *codec, unsignedint chip_addx)
{ struct ca0132_spec *spec = codec->spec; int res;
if (spec->curr_chip_addx == chip_addx) return 0;
/* send low 16 bits of the address */
res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_LOW,
chip_addx & 0xffff);
if (res != -EIO) { /* send high 16 bits of the address */
res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_HIGH,
chip_addx >> 16);
}
/* * Write data through the vendor widget -- NOT protected by the Mutex!
*/ staticint chipio_write_data(struct hda_codec *codec, unsignedint data)
{ struct ca0132_spec *spec = codec->spec; int res;
/* send low 16 bits of the data */
res = chipio_send(codec, VENDOR_CHIPIO_DATA_LOW, data & 0xffff);
if (res != -EIO) { /* send high 16 bits of the data */
res = chipio_send(codec, VENDOR_CHIPIO_DATA_HIGH,
data >> 16);
}
/*If no error encountered, automatically increment the address
as per chip behaviour*/
spec->curr_chip_addx = (res != -EIO) ?
(spec->curr_chip_addx + 4) : ~0U; return res;
}
/* * Write multiple data through the vendor widget -- NOT protected by the Mutex!
*/ staticint chipio_write_data_multiple(struct hda_codec *codec, const u32 *data, unsignedint count)
{ int status = 0;
while ((count-- != 0) && (status == 0))
status = chipio_write_data(codec, *data++);
return status;
}
/* * Read data through the vendor widget -- NOT protected by the Mutex!
*/ staticint chipio_read_data(struct hda_codec *codec, unsignedint *data)
{ struct ca0132_spec *spec = codec->spec; int res;
/* post read */
res = chipio_send(codec, VENDOR_CHIPIO_HIC_POST_READ, 0);
if (res != -EIO) { /* read status */
res = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
}
if (res != -EIO) { /* read data */
*data = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_HIC_READ_DATA,
0);
}
/*If no error encountered, automatically increment the address
as per chip behaviour*/
spec->curr_chip_addx = (res != -EIO) ?
(spec->curr_chip_addx + 4) : ~0U; return res;
}
/* * Write given value to the given address through the chip I/O widget. * protected by the Mutex
*/ staticint chipio_write(struct hda_codec *codec, unsignedint chip_addx, constunsignedint data)
{ struct ca0132_spec *spec = codec->spec; int err;
mutex_lock(&spec->chipio_mutex);
/* write the address, and if successful proceed to write data */
err = chipio_write_address(codec, chip_addx); if (err < 0) gotoexit;
err = chipio_write_data(codec, data); if (err < 0) gotoexit;
/* * Write given value to the given address through the chip I/O widget. * not protected by the Mutex
*/ staticint chipio_write_no_mutex(struct hda_codec *codec, unsignedint chip_addx, constunsignedint data)
{ int err;
/* write the address, and if successful proceed to write data */
err = chipio_write_address(codec, chip_addx); if (err < 0) gotoexit;
err = chipio_write_data(codec, data); if (err < 0) gotoexit;
exit: return err;
}
/* * Write multiple values to the given address through the chip I/O widget. * protected by the Mutex
*/ staticint chipio_write_multiple(struct hda_codec *codec,
u32 chip_addx, const u32 *data, unsignedint count)
{ struct ca0132_spec *spec = codec->spec; int status;
mutex_lock(&spec->chipio_mutex);
status = chipio_write_address(codec, chip_addx); if (status < 0) goto error;
status = chipio_write_data_multiple(codec, data, count);
error:
mutex_unlock(&spec->chipio_mutex);
return status;
}
/* * Read the given address through the chip I/O widget * protected by the Mutex
*/ staticint chipio_read(struct hda_codec *codec, unsignedint chip_addx, unsignedint *data)
{ struct ca0132_spec *spec = codec->spec; int err;
mutex_lock(&spec->chipio_mutex);
/* write the address, and if successful proceed to write data */
err = chipio_write_address(codec, chip_addx); if (err < 0) gotoexit;
err = chipio_read_data(codec, data); if (err < 0) gotoexit;
/* * Set chip parameters through the chip I/O widget. NO MUTEX.
*/ staticvoid chipio_set_control_param_no_mutex(struct hda_codec *codec, enum control_param_id param_id, int param_val)
{ int val;
if ((param_id < 32) && (param_val < 8)) {
val = (param_val << 5) | (param_id);
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_SET, val);
} else { if (chipio_send(codec, VENDOR_CHIPIO_STATUS, 0) == 0) {
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_EX_ID_SET,
param_id);
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_EX_VALUE_SET,
param_val);
}
}
} /* * Connect stream to a source point, and then connect * that source point to a destination point.
*/ staticvoid chipio_set_stream_source_dest(struct hda_codec *codec, int streamid, int source_point, int dest_point)
{
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_STREAM_ID, streamid);
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_STREAM_SOURCE_CONN_POINT, source_point);
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_STREAM_DEST_CONN_POINT, dest_point);
}
/* * Set number of channels in the selected stream.
*/ staticvoid chipio_set_stream_channels(struct hda_codec *codec, int streamid, unsignedint channels)
{
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_STREAM_ID, streamid);
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_STREAMS_CHANNELS, channels);
}
/* * Set sampling rate of the connection point. NO MUTEX.
*/ staticvoid chipio_set_conn_rate_no_mutex(struct hda_codec *codec, int connid, enum ca0132_sample_rate rate)
{
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_CONN_POINT_ID, connid);
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_CONN_POINT_SAMPLE_RATE, rate);
}
/* * Set sampling rate of the connection point.
*/ staticvoid chipio_set_conn_rate(struct hda_codec *codec, int connid, enum ca0132_sample_rate rate)
{
chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_ID, connid);
chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_SAMPLE_RATE,
rate);
}
/* * Writes to the 8051's internal address space directly instead of indirectly, * giving access to the special function registers located at addresses * 0x80-0xFF.
*/ staticvoid chipio_8051_write_direct(struct hda_codec *codec, unsignedint addr, unsignedint data)
{ unsignedint verb;
/* * Writes to the 8051's exram, which has 16-bits of address space. * Data at addresses 0x2000-0x7fff is mirrored to 0x8000-0xdfff. * Data at 0x8000-0xdfff can also be used as program memory for the 8051 by * setting the pmem bank selection SFR. * 0xe000-0xffff is always mapped as program memory, with only 0xf000-0xffff * being writable.
*/ staticvoid chipio_8051_set_address(struct hda_codec *codec, unsignedint addr)
{ unsignedint tmp;
/* send bits of data specified by reg to dsp */ do {
res = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0, reg, data); if ((res >= 0) && (res != VENDOR_STATUS_DSPIO_BUSY)) return res;
msleep(20);
} while (time_before(jiffies, timeout));
return -EIO;
}
/* * Wait for DSP to be ready for commands
*/ staticvoid dspio_write_wait(struct hda_codec *codec)
{ int status; unsignedlong timeout = jiffies + msecs_to_jiffies(1000);
do {
status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
VENDOR_DSPIO_STATUS, 0); if ((status == VENDOR_STATUS_DSPIO_OK) ||
(status == VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY)) break;
msleep(1);
} while (time_before(jiffies, timeout));
}
/* * Write SCP data to DSP
*/ staticint dspio_write(struct hda_codec *codec, unsignedint scp_data)
{ struct ca0132_spec *spec = codec->spec; int status;
dspio_write_wait(codec);
mutex_lock(&spec->chipio_mutex);
status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_LOW,
scp_data & 0xffff); if (status < 0) goto error;
status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_HIGH,
scp_data >> 16); if (status < 0) goto error;
/* OK, now check if the write itself has executed*/
status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
VENDOR_DSPIO_STATUS, 0);
error:
mutex_unlock(&spec->chipio_mutex);
status = dspio_write_multiple(codec, (unsignedint *)send_buf,
scp_send_size); if (status < 0) {
spec->wait_scp = 0; return status;
}
if (waiting_for_resp) { unsignedlong timeout = jiffies + msecs_to_jiffies(1000);
memset(return_buf, 0, return_buf_size); do {
msleep(20);
} while (spec->wait_scp && time_before(jiffies, timeout));
waiting_for_resp = false; if (!spec->wait_scp) {
ret_msg = (struct scp_msg *)return_buf;
memcpy(&ret_msg->hdr, &spec->scp_resp_header, 4);
memcpy(&ret_msg->data, spec->scp_resp_data,
spec->wait_num_data);
*bytes_returned = (spec->scp_resp_count + 1) * 4;
status = 0;
} else {
status = -EIO;
}
spec->wait_scp = 0;
}
return status;
}
/** * dspio_scp - Prepare and send the SCP message to DSP * @codec: the HDA codec * @mod_id: ID of the DSP module to send the command * @src_id: ID of the source * @req: ID of request to send to the DSP module * @dir: SET or GET * @data: pointer to the data to send with the request, request specific * @len: length of the data, in bytes * @reply: point to the buffer to hold data returned for a reply * @reply_len: length of the reply buffer returned from GET * * Returns zero or a negative error code.
*/ staticint dspio_scp(struct hda_codec *codec, int mod_id, int src_id, int req, int dir, constvoid *data, unsignedint len, void *reply, unsignedint *reply_len)
{ int status = 0; struct scp_msg scp_send, scp_reply; unsignedint ret_bytes, send_size, ret_size; unsignedint send_get_flag, reply_resp_flag, reply_error_flag; unsignedint reply_data_size;
/** * dsp_allocate_router_ports - Allocate router ports * * @codec: the HDA codec * @num_chans: number of channels in the stream * @ports_per_channel: number of ports per channel * @start_device: start device * @port_map: pointer to the port list to hold the allocated ports * * Returns zero or a negative error code.
*/ staticint dsp_allocate_router_ports(struct hda_codec *codec, unsignedint num_chans, unsignedint ports_per_channel, unsignedint start_device, unsignedint *port_map)
{ int status = 0; int res;
u8 val;
status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0); if (status < 0) return status;
val = start_device << 6;
val |= (ports_per_channel - 1) << 4;
val |= num_chans - 1;
/* * CA0132 chip DSP transfer stuffs. For DSP download.
*/ #define INVALID_DMA_CHANNEL (~0U)
/* * Program a list of address/data pairs via the ChipIO widget. * The segment data is in the format of successive pairs of words. * These are repeated as indicated by the segment's count field.
*/ staticint dspxfr_hci_write(struct hda_codec *codec, conststruct dsp_image_seg *fls)
{ int status; const u32 *data; unsignedint count;
count = fls->count;
data = (u32 *)(fls->data); while (count >= 2) {
status = chipio_write(codec, data[0], data[1]); if (status < 0) {
codec_dbg(codec, "hci_write chipio failed\n"); return status;
}
count -= 2;
data += 2;
} return 0;
}
/** * dspxfr_one_seg - Write a block of data into DSP code or data RAM using pre-allocated DMA engine. * * @codec: the HDA codec * @fls: pointer to a fast load image * @reloc: Relocation address for loading single-segment overlays, or 0 for * no relocation * @dma_engine: pointer to DMA engine to be used for DSP download * @dma_chan: The number of DMA channels used for DSP download * @port_map_mask: port mapping * @ovly: TRUE if overlay format is required * * Returns zero or a negative error code.
*/ staticint dspxfr_one_seg(struct hda_codec *codec, conststruct dsp_image_seg *fls, unsignedint reloc, struct dma_engine *dma_engine, unsignedint dma_chan, unsignedint port_map_mask, bool ovly)
{ int status = 0; bool comm_dma_setup_done = false; constunsignedint *data; unsignedint chip_addx; unsignedint words_to_write; unsignedint buffer_size_words; unsignedchar *buffer_addx; unsignedshort hda_format; unsignedint sample_rate_div; unsignedint sample_rate_mul; unsignedint num_chans; unsignedint hda_frame_size_words; unsignedint remainder_words; const u32 *data_remainder;
u32 chip_addx_remainder; unsignedint run_size_words; conststruct dsp_image_seg *hci_write = NULL; unsignedlong timeout; bool dma_active;
if (fls == NULL) return -EINVAL; if (is_hci_prog_list_seg(fls)) {
hci_write = fls;
fls = get_next_seg_ptr(fls);
}
data += remainder_words;
chip_addx += remainder_words*sizeof(u32);
words_to_write -= remainder_words;
while (words_to_write != 0) {
run_size_words = min(buffer_size_words, words_to_write);
codec_dbg(codec, "dspxfr (seg loop)cnt=%u rs=%u remainder=%u\n",
words_to_write, run_size_words, remainder_words);
dma_xfer(dma_engine, data, run_size_words*sizeof(u32)); if (!comm_dma_setup_done) {
status = dsp_dma_stop(codec, dma_chan, ovly); if (status < 0) return status;
status = dsp_dma_setup_common(codec, chip_addx,
dma_chan, port_map_mask, ovly); if (status < 0) return status;
comm_dma_setup_done = true;
}
status = dsp_dma_setup(codec, chip_addx,
run_size_words, dma_chan); if (status < 0) return status;
status = dsp_dma_start(codec, dma_chan, ovly); if (status < 0) return status; if (!dsp_is_dma_active(codec, dma_chan)) {
codec_dbg(codec, "dspxfr:DMA did not start\n"); return -EIO;
}
status = dma_set_state(dma_engine, DMA_STATE_RUN); if (status < 0) return status; if (remainder_words != 0) {
status = chipio_write_multiple(codec,
chip_addx_remainder,
data_remainder,
remainder_words); if (status < 0) return status;
remainder_words = 0;
} if (hci_write) {
status = dspxfr_hci_write(codec, hci_write); if (status < 0) return status;
hci_write = NULL;
}
timeout = jiffies + msecs_to_jiffies(2000); do {
dma_active = dsp_is_dma_active(codec, dma_chan); if (!dma_active) break;
msleep(20);
} while (time_before(jiffies, timeout)); if (dma_active) break;
codec_dbg(codec, "+++++ DMA complete\n");
dma_set_state(dma_engine, DMA_STATE_STOP);
status = dma_reset(dma_engine);
if (status < 0) return status;
data += run_size_words;
chip_addx += run_size_words*sizeof(u32);
words_to_write -= run_size_words;
}
if (remainder_words != 0) {
status = chipio_write_multiple(codec, chip_addx_remainder,
data_remainder, remainder_words);
}
return status;
}
/** * dspxfr_image - Write the entire DSP image of a DSP code/data overlay to DSP memories * * @codec: the HDA codec * @fls_data: pointer to a fast load image * @reloc: Relocation address for loading single-segment overlays, or 0 for * no relocation * @sample_rate: sampling rate of the stream used for DSP download * @channels: channels of the stream used for DSP download * @ovly: TRUE if overlay format is required * * Returns zero or a negative error code.
*/ staticint dspxfr_image(struct hda_codec *codec, conststruct dsp_image_seg *fls_data, unsignedint reloc, unsignedint sample_rate, unsignedshort channels, bool ovly)
{ struct ca0132_spec *spec = codec->spec; int status; unsignedshort hda_format = 0; unsignedint response; unsignedchar stream_id = 0; struct dma_engine *dma_engine; unsignedint dma_chan; unsignedint port_map_mask;
if (fls_data == NULL) return -EINVAL;
dma_engine = kzalloc(sizeof(*dma_engine), GFP_KERNEL); if (!dma_engine) return -ENOMEM;
/** * dspload_image - Download DSP from a DSP Image Fast Load structure. * * @codec: the HDA codec * @fls: pointer to a fast load image * @ovly: TRUE if overlay format is required * @reloc: Relocation address for loading single-segment overlays, or 0 for * no relocation * @autostart: TRUE if DSP starts after loading; ignored if ovly is TRUE * @router_chans: number of audio router channels to be allocated (0 means use * internal defaults; max is 32) * * Download DSP from a DSP Image Fast Load structure. This structure is a * linear, non-constant sized element array of structures, each of which * contain the count of the data to be loaded, the data itself, and the * corresponding starting chip address of the starting data location. * Returns zero or a negative error code.
*/ staticint dspload_image(struct hda_codec *codec, conststruct dsp_image_seg *fls, bool ovly, unsignedint reloc, bool autostart, int router_chans)
{ int status = 0; unsignedint sample_rate; unsignedshort channels;
codec_dbg(codec, "---- dspload_image begin ------\n"); if (router_chans == 0) { if (!ovly)
router_chans = DMA_TRANSFER_FRAME_SIZE_NWORDS; else
router_chans = DMA_OVERLAY_FRAME_SIZE_NWORDS;
}
do { if (dspload_is_loaded(codec)) {
codec_info(codec, "ca0132 DSP downloaded and running\n"); returntrue;
}
msleep(20);
} while (time_before(jiffies, timeout));
codec_err(codec, "ca0132 failed to download DSP\n"); returnfalse;
}
/* * ca0113 related functions. The ca0113 acts as the HDA bus for the pci-e * based cards, and has a second mmio region, region2, that's used for special * commands.
*/
/* * For cards with PCI-E region2 (Sound Blaster Z/ZxR, Recon3D, and AE-5) * the mmio address 0x320 is used to set GPIO pins. The format for the data * The first eight bits are just the number of the pin. So far, I've only seen * this number go to 7. * AE-5 note: The AE-5 seems to use pins 2 and 3 to somehow set the color value * of the on-card LED. It seems to use pin 2 for data, then toggles 3 to on and * then off to send that bit.
*/ staticvoid ca0113_mmio_gpio_set(struct hda_codec *codec, unsignedint gpio_pin, bool enable)
{ struct ca0132_spec *spec = codec->spec; unsignedshort gpio_data;
/* * Special pci region2 commands that are only used by the AE-5. They follow * a set format, and require reads at certain points to seemingly 'clear' * the response data. My first tests didn't do these reads, and would cause * the card to get locked up until the memory was read. These commands * seem to work with three distinct values that I've taken to calling group, * target-id, and value.
*/ staticvoid ca0113_mmio_command_set(struct hda_codec *codec, unsignedint group, unsignedint target, unsignedint value)
{ struct ca0132_spec *spec = codec->spec; unsignedint write_val;
/* * This second type of command is used for setting the sound filter type.
*/ staticvoid ca0113_mmio_command_set_type2(struct hda_codec *codec, unsignedint group, unsignedint target, unsignedint value)
{ struct ca0132_spec *spec = codec->spec; unsignedint write_val;
/* * Setup GPIO for the other variants of Core3D.
*/
/* * Sets up the GPIO pins so that they are discoverable. If this isn't done, * the card shows as having no GPIO pins.
*/ staticvoid ca0132_gpio_init(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec;
/* * GPIO control functions for the Recon3D integrated.
*/
enum r3di_gpio_bit { /* Bit 1 - Switch between front/rear mic. 0 = rear, 1 = front */
R3DI_MIC_SELECT_BIT = 1, /* Bit 2 - Switch between headphone/line out. 0 = Headphone, 1 = Line */
R3DI_OUT_SELECT_BIT = 2, /* * I dunno what this actually does, but it stays on until the dsp * is downloaded.
*/
R3DI_GPIO_DSP_DOWNLOADING = 3, /* * Same as above, no clue what it does, but it comes on after the dsp * is downloaded.
*/
R3DI_GPIO_DSP_DOWNLOADED = 4
};
enum r3di_mic_select { /* Set GPIO bit 1 to 0 for rear mic */
R3DI_REAR_MIC = 0, /* Set GPIO bit 1 to 1 for front microphone*/
R3DI_FRONT_MIC = 1
};
enum r3di_out_select { /* Set GPIO bit 2 to 0 for headphone */
R3DI_HEADPHONE_OUT = 0, /* Set GPIO bit 2 to 1 for speaker */
R3DI_LINE_OUT = 1
}; enum r3di_dsp_status { /* Set GPIO bit 3 to 1 until DSP is downloaded */
R3DI_DSP_DOWNLOADING = 0, /* Set GPIO bit 4 to 1 once DSP is downloaded */
R3DI_DSP_DOWNLOADED = 1
};
/*If Playback effects are on, allow stream some time to flush
*effects tail*/ if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
msleep(50);
/* Add latency if playback enhancement and either effect is enabled. */ if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) { if ((spec->effects_switch[SURROUND - EFFECT_START_NID]) ||
(spec->effects_switch[DIALOG_PLUS - EFFECT_START_NID]))
latency += DSP_PLAY_ENHANCEMENT_LATENCY;
}
/* Applying Speaker EQ adds latency as well. */ if (spec->cur_out_type == SPEAKER_OUT)
latency += DSP_SPEAKER_OUT_LATENCY;
/* * Creates a mixer control that uses defaults of HDA_CODEC_VOL except for the * volume put, which is used for setting the DSP volume. This was done because * the ca0132 functions were taking too much time and causing lag.
*/ #define CA0132_ALT_CODEC_VOL_MONO(xname, nid, channel, dir) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.subdevice = HDA_SUBDEV_AMP_FLAG, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
.info = snd_hda_mixer_amp_volume_info, \
.get = snd_hda_mixer_amp_volume_get, \
.put = ca0132_alt_volume_put, \
.tlv = { .c = snd_hda_mixer_amp_tlv }, \
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) }
/* lookup tables */ /* * Lookup table with decibel values for the DSP. When volume is changed in * Windows, the DSP is also sent the dB value in floating point. In Windows, * these values have decimal points, probably because the Windows driver * actually uses floating point. We can't here, so I made a lookup table of * values -90 to 9. -90 is the lowest decibel value for both the ADC's and the * DAC's, and 9 is the maximum.
*/ staticconstunsignedint float_vol_db_lookup[] = {
0xC2B40000, 0xC2B20000, 0xC2B00000, 0xC2AE0000, 0xC2AC0000, 0xC2AA0000,
0xC2A80000, 0xC2A60000, 0xC2A40000, 0xC2A20000, 0xC2A00000, 0xC29E0000,
0xC29C0000, 0xC29A0000, 0xC2980000, 0xC2960000, 0xC2940000, 0xC2920000,
0xC2900000, 0xC28E0000, 0xC28C0000, 0xC28A0000, 0xC2880000, 0xC2860000,
0xC2840000, 0xC2820000, 0xC2800000, 0xC27C0000, 0xC2780000, 0xC2740000,
0xC2700000, 0xC26C0000, 0xC2680000, 0xC2640000, 0xC2600000, 0xC25C0000,
0xC2580000, 0xC2540000, 0xC2500000, 0xC24C0000, 0xC2480000, 0xC2440000,
0xC2400000, 0xC23C0000, 0xC2380000, 0xC2340000, 0xC2300000, 0xC22C0000,
0xC2280000, 0xC2240000, 0xC2200000, 0xC21C0000, 0xC2180000, 0xC2140000,
0xC2100000, 0xC20C0000, 0xC2080000, 0xC2040000, 0xC2000000, 0xC1F80000,
0xC1F00000, 0xC1E80000, 0xC1E00000, 0xC1D80000, 0xC1D00000, 0xC1C80000,
0xC1C00000, 0xC1B80000, 0xC1B00000, 0xC1A80000, 0xC1A00000, 0xC1980000,
0xC1900000, 0xC1880000, 0xC1800000, 0xC1700000, 0xC1600000, 0xC1500000,
0xC1400000, 0xC1300000, 0xC1200000, 0xC1100000, 0xC1000000, 0xC0E00000,
0xC0C00000, 0xC0A00000, 0xC0800000, 0xC0400000, 0xC0000000, 0xBF800000,
0x00000000, 0x3F800000, 0x40000000, 0x40400000, 0x40800000, 0x40A00000,
0x40C00000, 0x40E00000, 0x41000000, 0x41100000
};
/* Wedge Angle defaults to 30. 10 below is 30 - 20. 20 is min. */
spec->cur_ctl_vals[WEDGE_ANGLE - TUNING_CTL_START_NID] = 10; /* SVM level defaults to 0.74. */
spec->cur_ctl_vals[SVM_LEVEL - TUNING_CTL_START_NID] = 74;
/* EQ defaults to 0dB. */ for (i = 2; i < TUNING_CTLS_COUNT; i++)
spec->cur_ctl_vals[i] = 24;
} #endif/*ENABLE_TUNING_CONTROLS*/
/* * Select the active output. * If autodetect is enabled, output will be selected based on jack detection. * If jack inserted, headphone will be selected, else built-in speakers * If autodetect is disabled, output will be selected based on selection.
*/ staticint ca0132_select_out(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; unsignedint pin_ctl; int jack_present; int auto_jack; unsignedint tmp; int err;
for (i = 0; i < AE_CA0113_OUT_SET_COMMANDS; i++)
ca0113_mmio_command_set(codec, out_cmds->group[i],
out_cmds->target[i],
out_cmds->vals[spec->cur_out_type][i]);
}
staticint ca0132_alt_set_full_range_speaker(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; int quirk = ca0132_quirk(spec); unsignedint tmp; int err;
/* 2.0/4.0 setup has no LFE channel, so setting full-range does nothing. */ if (spec->channel_cfg_val == SPEAKER_CHANNELS_4_0
|| spec->channel_cfg_val == SPEAKER_CHANNELS_2_0) return 0;
/* Set front L/R full range. Zero for full-range, one for redirection. */
tmp = spec->speaker_range_val[0] ? FLOAT_ZERO : FLOAT_ONE;
err = dspio_set_uint_param(codec, 0x96,
SPEAKER_FULL_RANGE_FRONT_L_R, tmp); if (err < 0) return err;
/* When setting full-range rear, both rear and center/lfe are set. */
tmp = spec->speaker_range_val[1] ? FLOAT_ZERO : FLOAT_ONE;
err = dspio_set_uint_param(codec, 0x96,
SPEAKER_FULL_RANGE_CENTER_LFE, tmp); if (err < 0) return err;
/* * Only the AE series cards set this value when setting full-range, * and it's always 1.0f.
*/ if (quirk == QUIRK_AE5 || quirk == QUIRK_AE7) {
err = dspio_set_uint_param(codec, 0x96,
SPEAKER_FULL_RANGE_SURROUND_L_R, FLOAT_ONE); if (err < 0) return err;
}
/* If it is enabled, make sure to set the crossover frequency. */ if (tmp) {
tmp = float_xbass_xover_lookup[spec->xbass_xover_freq];
err = dspio_set_uint_param(codec, 0x96,
SPEAKER_BASS_REDIRECT_XOVER_FREQ, tmp); if (err < 0) return err;
}
return 0;
}
/* * These are the commands needed to setup output on each of the different card * types.
*/ staticvoid ca0132_alt_select_out_get_quirk_data(struct hda_codec *codec, conststruct ca0132_alt_out_set_quirk_data **quirk_data)
{ struct ca0132_spec *spec = codec->spec; int quirk = ca0132_quirk(spec); unsignedint i;
*quirk_data = NULL; for (i = 0; i < ARRAY_SIZE(quirk_out_set_data); i++) { if (quirk_out_set_data[i].quirk_id == quirk) {
*quirk_data = &quirk_out_set_data[i]; return;
}
}
}
if (out_info->mmio_gpio_count) { for (i = 0; i < out_info->mmio_gpio_count; i++) {
ca0113_mmio_gpio_set(codec, out_info->mmio_gpio_pin[i],
out_info->mmio_gpio_set[i]);
}
}
if (out_info->scp_cmds_count) { for (i = 0; i < out_info->scp_cmds_count; i++) {
err = dspio_set_uint_param(codec,
out_info->scp_cmd_mid[i],
out_info->scp_cmd_req[i],
out_info->scp_cmd_val[i]); if (err < 0) return err;
}
}
/* * This function behaves similarly to the ca0132_select_out funciton above, * except with a few differences. It adds the ability to select the current * output with an enumerated control "output source" if the auto detect * mute switch is set to off. If the auto detect mute switch is enabled, it * will detect either headphone or lineout(SPEAKER_OUT) from jack detection. * It also adds the ability to auto-detect the front headphone port.
*/ staticint ca0132_alt_select_out(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; unsignedint tmp, outfx_set; int jack_present; int auto_jack; int err; /* Default Headphone is rear headphone */
hda_nid_t headphone_nid = spec->out_pins[1];
/* * If headphone rear or front is plugged in, set to headphone. * If neither is plugged in, set to rear line out. Only if * hp/speaker auto detect is enabled.
*/ if (auto_jack) {
jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_hp) ||
snd_hda_jack_detect(codec, spec->unsol_tag_front_hp);
/* Disable headphone node. */
ca0132_set_out_node_pincfg(codec, spec->out_pins[1], 0, 0); /* Set front L-R to output. */
ca0132_set_out_node_pincfg(codec, spec->out_pins[0], 1, 0); /* Set Center/LFE to output. */
ca0132_set_out_node_pincfg(codec, spec->out_pins[2], 1, 0); /* Set rear surround to output. */
ca0132_set_out_node_pincfg(codec, spec->out_pins[3], 1, 0);
/* * Without PlayEnhancement being enabled, if we've got a 2.0 * setup, set it to floating point eight to disable any DSP * processing effects.
*/ if (!outfx_set && spec->channel_cfg_val == SPEAKER_CHANNELS_2_0)
tmp = FLOAT_EIGHT; else
tmp = speaker_channel_cfgs[spec->channel_cfg_val].val;
/* enable headphone, either front or rear */ if (snd_hda_jack_detect(codec, spec->unsol_tag_front_hp))
headphone_nid = spec->out_pins[2]; elseif (snd_hda_jack_detect(codec, spec->unsol_tag_hp))
headphone_nid = spec->out_pins[1];
if (err < 0) gotoexit; break;
} /* * If output effects are enabled, set the X-Bass effect value again to * make sure that it's properly enabled/disabled for speaker * configurations with an LFE channel.
*/ if (outfx_set)
ca0132_effects_set(codec, X_BASS,
spec->effects_switch[X_BASS - EFFECT_START_NID]);
/* Set speaker EQ bypass attenuation to 0. */
err = dspio_set_uint_param(codec, 0x8f, 0x01, FLOAT_ZERO); if (err < 0) gotoexit;
/* * Although unused on all cards but the AE series, this is always set * to zero when setting the output.
*/
err = dspio_set_uint_param(codec, 0x96,
SPEAKER_TUNING_USE_SPEAKER_EQ, FLOAT_ZERO); if (err < 0) gotoexit;
if (spec->cur_out_type == SPEAKER_OUT)
err = ca0132_alt_surround_set_bass_redirection(codec,
spec->bass_redirection_val); else
err = ca0132_alt_surround_set_bass_redirection(codec, 0); if (err < 0) gotoexit;
/* Unmute DSP now that we're done with output selection. */
err = dspio_set_uint_param(codec, 0x96,
SPEAKER_TUNING_MUTE, FLOAT_ZERO); if (err < 0) gotoexit;
if (spec->cur_out_type == SPEAKER_OUT) {
err = ca0132_alt_set_full_range_speaker(codec); if (err < 0) gotoexit;
}
/* * Select the active microphone. * If autodetect is enabled, mic will be selected based on jack detection. * If jack inserted, ext.mic will be selected, else built-in mic * If autodetect is disabled, mic will be selected based on selection.
*/ staticint ca0132_select_mic(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; int jack_present; int auto_jack;
if (jack_present)
spec->cur_mic_type = LINE_MIC_IN; else
spec->cur_mic_type = DIGITAL_MIC;
if (spec->cur_mic_type == DIGITAL_MIC) { /* enable digital Mic */
chipio_set_conn_rate(codec, MEM_CONNID_DMIC, SR_32_000);
ca0132_set_dmic(codec, 1);
ca0132_mic_boost_set(codec, 0); /* set voice focus */
ca0132_effects_set(codec, VOICE_FOCUS,
spec->effects_switch
[VOICE_FOCUS - EFFECT_START_NID]);
} else { /* disable digital Mic */
chipio_set_conn_rate(codec, MEM_CONNID_DMIC, SR_96_000);
ca0132_set_dmic(codec, 0);
ca0132_mic_boost_set(codec, spec->cur_mic_boost); /* disable voice focus */
ca0132_effects_set(codec, VOICE_FOCUS, 0);
}
snd_hda_power_down_pm(codec);
return 0;
}
/* * Select the active input. * Mic detection isn't used, because it's kind of pointless on the SBZ. * The front mic has no jack-detection, so the only way to switch to it * is to do it manually in alsamixer.
*/ staticint ca0132_alt_select_in(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; unsignedint tmp;
switch (vnid) { case VNID_SPK:
nid = spec->shared_out_nid; break; case VNID_MIC:
nid = spec->shared_mic_nid; break; default: returnfalse;
}
if (shared_nid)
*shared_nid = nid;
returntrue;
}
/* * The following functions are control change helpers. * They return 0 if no changed. Return 1 if changed.
*/ staticint ca0132_voicefx_set(struct hda_codec *codec, int enable)
{ struct ca0132_spec *spec = codec->spec; unsignedint tmp;
/* based on CrystalVoice state to enable VoiceFX. */ if (enable) {
tmp = spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] ?
FLOAT_ONE : FLOAT_ZERO;
} else {
tmp = FLOAT_ZERO;
}
/* * Set the effects parameters
*/ staticint ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
{ struct ca0132_spec *spec = codec->spec; unsignedint on, tmp, channel_cfg; int num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; int err = 0; int idx = nid - EFFECT_START_NID;
if ((idx < 0) || (idx >= num_fx)) return 0; /* no changed */
/* for out effect, qualify with PE */ if ((nid >= OUT_EFFECT_START_NID) && (nid < OUT_EFFECT_END_NID)) { /* if PE if off, turn off out effects. */ if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
val = 0; if (spec->cur_out_type == SPEAKER_OUT && nid == X_BASS) {
channel_cfg = spec->channel_cfg_val; if (channel_cfg != SPEAKER_CHANNELS_2_0 &&
channel_cfg != SPEAKER_CHANNELS_4_0)
val = 0;
}
}
/* for in effect, qualify with CrystalVoice */ if ((nid >= IN_EFFECT_START_NID) && (nid < IN_EFFECT_END_NID)) { /* if CrystalVoice if off, turn off in effects. */ if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID])
val = 0;
/* Voice Focus applies to 2-ch Mic, Digital Mic */ if ((nid == VOICE_FOCUS) && (spec->cur_mic_type != DIGITAL_MIC))
val = 0;
/* If Voice Focus on SBZ, set to two channel. */ if ((nid == VOICE_FOCUS) && ca0132_use_pci_mmio(spec)
&& (spec->cur_mic_type != REAR_LINE_IN)) { if (spec->effects_switch[CRYSTAL_VOICE -
EFFECT_START_NID]) {
if (spec->effects_switch[VOICE_FOCUS -
EFFECT_START_NID]) {
tmp = FLOAT_TWO;
val = 1;
} else
tmp = FLOAT_ONE;
dspio_set_uint_param(codec, 0x80, 0x00, tmp);
}
} /* * For SBZ noise reduction, there's an extra command * to module ID 0x47. No clue why.
*/ if ((nid == NOISE_REDUCTION) && ca0132_use_pci_mmio(spec)
&& (spec->cur_mic_type != REAR_LINE_IN)) { if (spec->effects_switch[CRYSTAL_VOICE -
EFFECT_START_NID]) { if (spec->effects_switch[NOISE_REDUCTION -
EFFECT_START_NID])
tmp = FLOAT_ONE; else
tmp = FLOAT_ZERO;
} else
tmp = FLOAT_ZERO;
dspio_set_uint_param(codec, 0x47, 0x00, tmp);
}
/* If rear line in disable effects. */ if (ca0132_use_alt_functions(spec) &&
spec->in_enum_val == REAR_LINE_IN)
val = 0;
}
if (ca0132_use_alt_functions(spec))
ca0132_alt_select_out(codec);
i = OUT_EFFECT_START_NID - EFFECT_START_NID;
nid = OUT_EFFECT_START_NID; /* PE affects all out effects */ for (; nid < OUT_EFFECT_END_NID; nid++, i++)
ret |= ca0132_effects_set(codec, nid, spec->effects_switch[i]);
return ret;
}
/* Check if Mic1 is streaming, if so, stop streaming */ staticint stop_mic1(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; unsignedint oldval = snd_hda_codec_read(codec, spec->adcs[0], 0,
AC_VERB_GET_CONV, 0); if (oldval != 0)
snd_hda_codec_write(codec, spec->adcs[0], 0,
AC_VERB_SET_CHANNEL_STREAMID,
0); return oldval;
}
/* Resume Mic1 streaming if it was stopped. */ staticvoid resume_mic1(struct hda_codec *codec, unsignedint oldval)
{ struct ca0132_spec *spec = codec->spec; /* Restore the previous stream and channel */ if (oldval != 0)
snd_hda_codec_write(codec, spec->adcs[0], 0,
AC_VERB_SET_CHANNEL_STREAMID,
oldval);
}
/* * Turn on/off CrystalVoice
*/ staticint ca0132_cvoice_switch_set(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec;
hda_nid_t nid; int i, ret = 0; unsignedint oldval;
i = IN_EFFECT_START_NID - EFFECT_START_NID;
nid = IN_EFFECT_START_NID; /* CrystalVoice affects all in effects */ for (; nid < IN_EFFECT_END_NID; nid++, i++)
ret |= ca0132_effects_set(codec, nid, spec->effects_switch[i]);
/* including VoiceFX */
ret |= ca0132_voicefx_set(codec, (spec->voicefx_val ? 1 : 0));
/* set correct vipsource */
oldval = stop_mic1(codec); if (ca0132_use_alt_functions(spec))
ret |= ca0132_alt_set_vipsource(codec, 1); else
ret |= ca0132_set_vipsource(codec, 1);
resume_mic1(codec, oldval); return ret;
}
staticint ca0132_mic_boost_set(struct hda_codec *codec, long val)
{ struct ca0132_spec *spec = codec->spec; int ret = 0;
if (val) /* on */
ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0,
HDA_INPUT, 0, HDA_AMP_VOLMASK, 3); else/* off */
ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0,
HDA_INPUT, 0, HDA_AMP_VOLMASK, 0);
return ret;
}
staticint ca0132_alt_mic_boost_set(struct hda_codec *codec, long val)
{ struct ca0132_spec *spec = codec->spec; int ret = 0;
staticint ae5_headphone_gain_set(struct hda_codec *codec, long val)
{ unsignedint i;
for (i = 0; i < 4; i++)
ca0113_mmio_command_set(codec, 0x48, 0x11 + i,
ae5_headphone_gain_presets[val].vals[i]); return 0;
}
/* * gpio pin 1 is a relay that switches on/off, apparently setting the headphone * amplifier to handle a 600 ohm load.
*/ staticint zxr_headphone_gain_set(struct hda_codec *codec, long val)
{
ca0113_mmio_gpio_set(codec, 1, val);
return 0;
}
staticint ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
hda_nid_t nid = get_amp_nid(kcontrol);
hda_nid_t shared_nid = 0; bool effective; int ret = 0; struct ca0132_spec *spec = codec->spec; int auto_jack;
if (nid == VNID_HP_SEL) {
auto_jack =
spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; if (!auto_jack) { if (ca0132_use_alt_functions(spec))
ca0132_alt_select_out(codec); else
ca0132_select_out(codec);
} return 1;
}
if (nid == VNID_AMIC1_SEL) {
auto_jack =
spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID]; if (!auto_jack)
ca0132_select_mic(codec); return 1;
}
if (nid == VNID_HP_ASEL) { if (ca0132_use_alt_functions(spec))
ca0132_alt_select_out(codec); else
ca0132_select_out(codec); return 1;
}
if (nid == VNID_AMIC1_ASEL) {
ca0132_select_mic(codec); return 1;
}
/* if effective conditions, then update hw immediately. */
effective = ca0132_is_vnode_effective(codec, nid, &shared_nid); if (effective) { int dir = get_amp_direction(kcontrol); int ch = get_amp_channels(kcontrol); unsignedlong pval;
/* * Below I've added controls to mess with the effect levels, I've only enabled * them on the Sound Blaster Z, but they would probably also work on the * Chromebook. I figured they were probably tuned specifically for it, and left * out for a reason.
*/
/* Sets DSP effect level from the sliders above the controls */
staticint ca0132_alt_slider_ctl_set(struct hda_codec *codec, hda_nid_t nid, constunsignedint *lookup, int idx)
{ int i = 0; unsignedint y; /* * For X_BASS, req 2 is actually crossover freq instead of * effect level
*/ if (nid == X_BASS)
y = 2; else
y = 1;
snd_hda_power_up(codec); if (nid == XBASS_XOVER) { for (i = 0; i < OUT_EFFECTS_COUNT; i++) if (ca0132_effects[i].nid == X_BASS) break;
dspio_set_param(codec, ca0132_effects[i].mid, 0x20,
ca0132_effects[i].reqs[1],
&(lookup[idx - 1]), sizeof(unsignedint));
} else { /* Find the actual effect structure */ for (i = 0; i < OUT_EFFECTS_COUNT; i++) if (nid == ca0132_effects[i].nid) break;
staticint ca0132_alt_slider_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ca0132_spec *spec = codec->spec;
hda_nid_t nid = get_amp_nid(kcontrol); long *valp = ucontrol->value.integer.value; int idx = nid - OUT_EFFECT_START_NID;
*valp = spec->fx_ctl_val[idx]; return 0;
}
/* * The X-bass crossover starts at 10hz, so the min is 1. The * frequency is set in multiples of 10.
*/ staticint ca0132_alt_xbass_xover_slider_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 1;
uinfo->value.integer.max = 100;
uinfo->value.integer.step = 1;
/* * Mic Boost Enum for alternative ca0132 codecs. I didn't like that the original * only has off or full 30 dB, and didn't like making a volume slider that has * traditional 0-100 in alsamixer that goes in big steps. I like enum better.
*/ #define MIC_BOOST_NUM_OF_STEPS 4 #define MIC_BOOST_ENUM_MAX_STRLEN 10
/* * Input Select Control for alternative ca0132 codecs. This exists because * front microphone has no auto-detect, and we need a way to set the rear * as line-in
*/ staticint ca0132_alt_input_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = IN_SRC_NUM_OF_INPUTS; if (uinfo->value.enumerated.item >= IN_SRC_NUM_OF_INPUTS)
uinfo->value.enumerated.item = IN_SRC_NUM_OF_INPUTS - 1;
strscpy(uinfo->value.enumerated.name,
in_src_str[uinfo->value.enumerated.item]); return 0;
}
if (spec->out_enum_val == SPEAKER_OUT)
ca0132_alt_select_out(codec);
return 1;
}
/* * Smart Volume output setting control. Three different settings, Normal, * which takes the value from the smart volume slider. The two others, loud * and night, disregard the slider value and have uneditable values.
*/ #define NUM_OF_SVM_SETTINGS 3 staticconstchar *const out_svm_set_enum_str[3] = {"Normal", "Loud", "Night" };
/* out and in effects */ if (((nid >= OUT_EFFECT_START_NID) && (nid < OUT_EFFECT_END_NID)) ||
((nid >= IN_EFFECT_START_NID) && (nid < IN_EFFECT_END_NID))) {
spec->effects_switch[nid - EFFECT_START_NID] = *valp;
changed = ca0132_effects_set(codec, nid, *valp); gotoexit;
}
/* mic boost */ if (nid == spec->input_pins[0]) {
spec->cur_mic_boost = *valp; if (ca0132_use_alt_functions(spec)) { if (spec->in_enum_val != REAR_LINE_IN)
changed = ca0132_mic_boost_set(codec, *valp);
} else { /* Mic boost does not apply to Digital Mic */ if (spec->cur_mic_type != DIGITAL_MIC)
changed = ca0132_mic_boost_set(codec, *valp);
}
gotoexit;
}
if (nid == ZXR_HEADPHONE_GAIN) {
spec->zxr_gain_set = *valp; if (spec->cur_out_type == HEADPHONE_OUT)
changed = zxr_headphone_gain_set(codec, *valp); else
changed = 0;
gotoexit;
}
if (nid == SPEAKER_FULL_RANGE_FRONT || nid == SPEAKER_FULL_RANGE_REAR) {
spec->speaker_range_val[nid - SPEAKER_FULL_RANGE_FRONT] = *valp; if (spec->cur_out_type == SPEAKER_OUT)
ca0132_alt_set_full_range_speaker(codec);
changed = 0;
}
if (nid == BASS_REDIRECTION) {
spec->bass_redirection_val = *valp; if (spec->cur_out_type == SPEAKER_OUT)
ca0132_alt_surround_set_bass_redirection(codec, *valp);
/* * Volume related
*/ /* * Sets the internal DSP decibel level to match the DAC for output, and the * ADC for input. Currently only the SBZ sets dsp capture volume level, and * all alternative codecs set DSP playback volume.
*/ staticvoid ca0132_alt_dsp_volume_put(struct hda_codec *codec, hda_nid_t nid)
{ struct ca0132_spec *spec = codec->spec; unsignedint dsp_dir; unsignedint lookup_val;
staticint ca0132_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ca0132_spec *spec = codec->spec;
hda_nid_t nid = get_amp_nid(kcontrol); int ch = get_amp_channels(kcontrol); long *valp = ucontrol->value.integer.value;
/* store the left and right volume */ if (ch & 1) {
*valp = spec->vnode_lvol[nid - VNODE_START_NID];
valp++;
} if (ch & 2) {
*valp = spec->vnode_rvol[nid - VNODE_START_NID];
valp++;
} return 0;
}
staticint ca0132_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ca0132_spec *spec = codec->spec;
hda_nid_t nid = get_amp_nid(kcontrol); int ch = get_amp_channels(kcontrol); long *valp = ucontrol->value.integer.value;
hda_nid_t shared_nid = 0; bool effective; int changed = 1;
/* store the left and right volume */ if (ch & 1) {
spec->vnode_lvol[nid - VNODE_START_NID] = *valp;
valp++;
} if (ch & 2) {
spec->vnode_rvol[nid - VNODE_START_NID] = *valp;
valp++;
}
/* if effective conditions, then update hw immediately. */
effective = ca0132_is_vnode_effective(codec, nid, &shared_nid); if (effective) { int dir = get_amp_direction(kcontrol); unsignedlong pval;
/* * This function is the same as the one above, because using an if statement * inside of the above volume control for the DSP volume would cause too much * lag. This is a lot more smooth.
*/ staticint ca0132_alt_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ca0132_spec *spec = codec->spec;
hda_nid_t nid = get_amp_nid(kcontrol); int ch = get_amp_channels(kcontrol); long *valp = ucontrol->value.integer.value;
hda_nid_t vnid = 0; int changed;
switch (nid) { case 0x02:
vnid = VNID_SPK; break; case 0x07:
vnid = VNID_MIC; break;
}
/* store the left and right volume */ if (ch & 1) {
spec->vnode_lvol[vnid - VNODE_START_NID] = *valp;
valp++;
} if (ch & 2) {
spec->vnode_rvol[vnid - VNODE_START_NID] = *valp;
valp++;
}
/* * Added FX: prefix for the alternative codecs, because otherwise the surround * effect would conflict with the Surround sound volume control. Also seems more * clear as to what the switches do. Left alone for others.
*/ staticint add_fx_switch(struct hda_codec *codec, hda_nid_t nid, constchar *pfx, int dir)
{ struct ca0132_spec *spec = codec->spec; char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int type = dir ? HDA_INPUT : HDA_OUTPUT; struct snd_kcontrol_new knew =
CA0132_CODEC_MUTE_MONO(namestr, nid, 1, type); /* If using alt_controls, add FX: prefix. But, don't add FX: * prefix to OutFX or InFX enable controls.
*/ if (ca0132_use_alt_controls(spec) && (nid <= IN_EFFECT_END_NID))
sprintf(namestr, "FX: %s %s Switch", pfx, dirstr[dir]); else
sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
/* * Add enumerated control for the three different settings of the smart volume * output effect. Normal just uses the slider value, and loud and night are * their own things that ignore that value.
*/ staticint ca0132_alt_add_svm_enum(struct hda_codec *codec)
{ struct snd_kcontrol_new knew =
HDA_CODEC_MUTE_MONO("FX: Smart Volume Setting",
SMART_VOLUME_ENUM, 1, 0, HDA_OUTPUT);
knew.info = ca0132_alt_svm_setting_info;
knew.get = ca0132_alt_svm_setting_get;
knew.put = ca0132_alt_svm_setting_put; return snd_hda_ctl_add(codec, SMART_VOLUME_ENUM,
snd_ctl_new1(&knew, codec));
}
/* * Create an Output Select enumerated control for codecs with surround * out capabilities.
*/ staticint ca0132_alt_add_output_enum(struct hda_codec *codec)
{ struct snd_kcontrol_new knew =
HDA_CODEC_MUTE_MONO("Output Select",
OUTPUT_SOURCE_ENUM, 1, 0, HDA_OUTPUT);
knew.info = ca0132_alt_output_select_get_info;
knew.get = ca0132_alt_output_select_get;
knew.put = ca0132_alt_output_select_put; return snd_hda_ctl_add(codec, OUTPUT_SOURCE_ENUM,
snd_ctl_new1(&knew, codec));
}
/* * Add a control for selecting channel count on speaker output. Setting this * allows the DSP to do bass redirection and channel upmixing on surround * configurations.
*/ staticint ca0132_alt_add_speaker_channel_cfg_enum(struct hda_codec *codec)
{ struct snd_kcontrol_new knew =
HDA_CODEC_MUTE_MONO("Surround Channel Config",
SPEAKER_CHANNEL_CFG_ENUM, 1, 0, HDA_OUTPUT);
knew.info = ca0132_alt_speaker_channel_cfg_get_info;
knew.get = ca0132_alt_speaker_channel_cfg_get;
knew.put = ca0132_alt_speaker_channel_cfg_put; return snd_hda_ctl_add(codec, SPEAKER_CHANNEL_CFG_ENUM,
snd_ctl_new1(&knew, codec));
}
/* * Full range front stereo and rear surround switches. When these are set to * full range, the lower frequencies from these channels are no longer * redirected to the LFE channel.
*/ staticint ca0132_alt_add_front_full_range_switch(struct hda_codec *codec)
{ struct snd_kcontrol_new knew =
CA0132_CODEC_MUTE_MONO("Full-Range Front Speakers",
SPEAKER_FULL_RANGE_FRONT, 1, HDA_OUTPUT);
/* * Bass redirection redirects audio below the crossover frequency to the LFE * channel on speakers that are set as not being full-range. On configurations * without an LFE channel, it does nothing. Bass redirection seems to be the * replacement for X-Bass on configurations with an LFE channel.
*/ staticint ca0132_alt_add_bass_redirection_crossover(struct hda_codec *codec)
{ constchar *namestr = "Bass Redirection Crossover"; struct snd_kcontrol_new knew =
HDA_CODEC_VOLUME_MONO(namestr, BASS_REDIRECTION_XOVER, 1, 0,
HDA_OUTPUT);
/* * Create an Input Source enumerated control for the alternate ca0132 codecs * because the front microphone has no auto-detect, and Line-in has to be set * somehow.
*/ staticint ca0132_alt_add_input_enum(struct hda_codec *codec)
{ struct snd_kcontrol_new knew =
HDA_CODEC_MUTE_MONO("Input Source",
INPUT_SOURCE_ENUM, 1, 0, HDA_INPUT);
knew.info = ca0132_alt_input_source_info;
knew.get = ca0132_alt_input_source_get;
knew.put = ca0132_alt_input_source_put; return snd_hda_ctl_add(codec, INPUT_SOURCE_ENUM,
snd_ctl_new1(&knew, codec));
}
/* * Add mic boost enumerated control. Switches through 0dB to 30dB. This adds * more control than the original mic boost, which is either full 30dB or off.
*/ staticint ca0132_alt_add_mic_boost_enum(struct hda_codec *codec)
{ struct snd_kcontrol_new knew =
HDA_CODEC_MUTE_MONO("Mic Boost Capture Switch",
MIC_BOOST_ENUM, 1, 0, HDA_INPUT);
knew.info = ca0132_alt_mic_boost_info;
knew.get = ca0132_alt_mic_boost_get;
knew.put = ca0132_alt_mic_boost_put; return snd_hda_ctl_add(codec, MIC_BOOST_ENUM,
snd_ctl_new1(&knew, codec));
}
/* * Add headphone gain enumerated control for the AE-5. This switches between * three modes, low, medium, and high. When non-headphone outputs are selected, * it is automatically set to high. This is the same behavior as Windows.
*/ staticint ae5_add_headphone_gain_enum(struct hda_codec *codec)
{ struct snd_kcontrol_new knew =
HDA_CODEC_MUTE_MONO("AE-5: Headphone Gain",
AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_OUTPUT);
knew.info = ae5_headphone_gain_info;
knew.get = ae5_headphone_gain_get;
knew.put = ae5_headphone_gain_put; return snd_hda_ctl_add(codec, AE5_HEADPHONE_GAIN_ENUM,
snd_ctl_new1(&knew, codec));
}
/* * Add sound filter enumerated control for the AE-5. This adds three different * settings: Slow Roll Off, Minimum Phase, and Fast Roll Off. From what I've * read into it, it changes the DAC's interpolation filter.
*/ staticint ae5_add_sound_filter_enum(struct hda_codec *codec)
{ struct snd_kcontrol_new knew =
HDA_CODEC_MUTE_MONO("AE-5: Sound Filter",
AE5_SOUND_FILTER_ENUM, 1, 0, HDA_OUTPUT);
knew.info = ae5_sound_filter_info;
knew.get = ae5_sound_filter_get;
knew.put = ae5_sound_filter_put; return snd_hda_ctl_add(codec, AE5_SOUND_FILTER_ENUM,
snd_ctl_new1(&knew, codec));
}
/* * Need to create follower controls for the alternate codecs that have surround * capabilities.
*/ staticconstchar * const ca0132_alt_follower_pfxs[] = { "Front", "Surround", "Center", "LFE", NULL,
};
/* * Also need special channel map, because the default one is incorrect. * I think this has to do with the pin for rear surround being 0x11, * and the center/lfe being 0x10. Usually the pin order is the opposite.
*/ staticconststruct snd_pcm_chmap_elem ca0132_alt_chmaps[] = {
{ .channels = 2,
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
{ .channels = 4,
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
{ .channels = 6,
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
{ }
};
/* Add the correct chmap for streams with 6 channels. */ staticvoid ca0132_alt_add_chmap_ctls(struct hda_codec *codec)
{ int err = 0; struct hda_pcm *pcm;
/* * Desktop specific control mixer. Removes auto-detect for mic, and adds * surround controls. Also sets both the Front Playback and Capture Volume * controls to alt so they set the DSP's decibel level.
*/ staticconststruct snd_kcontrol_new desktop_mixer[] = {
CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT),
CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x04, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x03, 1, 0, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x03, 1, 0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x03, 2, 0, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x03, 2, 0, HDA_OUTPUT),
CA0132_ALT_CODEC_VOL("Capture Volume", 0x07, HDA_INPUT),
CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT),
HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT),
HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT),
CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch",
VNID_HP_ASEL, 1, HDA_OUTPUT),
{ } /* end */
};
/* * Same as the Sound Blaster Z, except doesn't use the alt volume for capture * because it doesn't set decibel levels for the DSP for capture.
*/ staticconststruct snd_kcontrol_new r3di_mixer[] = {
CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT),
CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x04, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x03, 1, 0, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x03, 1, 0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x03, 2, 0, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x03, 2, 0, HDA_OUTPUT),
CA0132_CODEC_VOL("Capture Volume", VNID_MIC, HDA_INPUT),
CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT),
HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT),
HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT),
CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch",
VNID_HP_ASEL, 1, HDA_OUTPUT),
{ } /* end */
};
staticint ca0132_build_controls(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; int i, num_fx, num_sliders; int err = 0;
/* Add Mixer controls */ for (i = 0; i < spec->num_mixers; i++) {
err = snd_hda_add_new_ctls(codec, spec->mixers[i]); if (err < 0) return err;
} /* Setup vmaster with surround followers for desktop ca0132 devices */ if (ca0132_use_alt_functions(spec)) {
snd_hda_set_vmaster_tlv(codec, spec->dacs[0], HDA_OUTPUT,
spec->tlv);
snd_hda_add_vmaster(codec, "Master Playback Volume",
spec->tlv, ca0132_alt_follower_pfxs, "Playback Volume", 0);
err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
NULL, ca0132_alt_follower_pfxs, "Playback Switch", true, 0, &spec->vmaster_mute.sw_kctl); if (err < 0) return err;
}
/* Add in and out effects controls. * VoiceFX, PE and CrystalVoice are added separately.
*/
num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; for (i = 0; i < num_fx; i++) { /* Desktop cards break if Echo Cancellation is used. */ if (ca0132_use_pci_mmio(spec)) { if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
OUT_EFFECTS_COUNT)) continue;
}
err = add_fx_switch(codec, ca0132_effects[i].nid,
ca0132_effects[i].name,
ca0132_effects[i].direct); if (err < 0) return err;
} /* * If codec has use_alt_controls set to true, add effect level sliders, * EQ presets, and Smart Volume presets. Also, change names to add FX * prefix, and change PlayEnhancement and CrystalVoice to match.
*/ if (ca0132_use_alt_controls(spec)) {
err = ca0132_alt_add_svm_enum(codec); if (err < 0) return err;
err = add_ca0132_alt_eq_presets(codec); if (err < 0) return err;
/* * If the codec uses alt_functions, you need the enumerated controls * to select the new outputs and inputs, plus add the new mic boost * setting control.
*/ if (ca0132_use_alt_functions(spec)) {
err = ca0132_alt_add_output_enum(codec); if (err < 0) return err;
err = ca0132_alt_add_speaker_channel_cfg_enum(codec); if (err < 0) return err;
err = ca0132_alt_add_front_full_range_switch(codec); if (err < 0) return err;
err = ca0132_alt_add_rear_full_range_switch(codec); if (err < 0) return err;
err = ca0132_alt_add_bass_redirection_crossover(codec); if (err < 0) return err;
err = ca0132_alt_add_bass_redirection_switch(codec); if (err < 0) return err;
err = ca0132_alt_add_mic_boost_enum(codec); if (err < 0) return err; /* * ZxR only has microphone input, there is no front panel * header on the card, and aux-in is handled by the DBPro board.
*/ if (ca0132_quirk(spec) != QUIRK_ZXR) {
err = ca0132_alt_add_input_enum(codec); if (err < 0) return err;
}
}
switch (ca0132_quirk(spec)) { case QUIRK_AE5: case QUIRK_AE7:
err = ae5_add_headphone_gain_enum(codec); if (err < 0) return err;
err = ae5_add_sound_filter_enum(codec); if (err < 0) return err; break; case QUIRK_ZXR:
err = zxr_add_headphone_gain_switch(codec); if (err < 0) return err; break; default: break;
}
/* With the DSP enabled, desktops don't use this ADC. */ if (!ca0132_use_alt_functions(spec)) {
info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2"); if (!info) return -ENOMEM;
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
ca0132_pcm_analog_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1];
}
info = snd_hda_codec_pcm_new(codec, "CA0132 What U Hear"); if (!info) return -ENOMEM;
info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[2];
if (!spec->dig_out && !spec->dig_in) return 0;
info = snd_hda_codec_pcm_new(codec, "CA0132 Digital"); if (!info) return -ENOMEM;
info->pcm_type = HDA_PCM_TYPE_SPDIF; if (spec->dig_out) {
info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
ca0132_pcm_digital_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
} if (spec->dig_in) {
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
ca0132_pcm_digital_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
}
/* * Switch between Digital built-in mic and analog mic.
*/ staticvoid ca0132_set_dmic(struct hda_codec *codec, int enable)
{ struct ca0132_spec *spec = codec->spec; unsignedint tmp;
u8 val; unsignedint oldval;
oldval = stop_mic1(codec);
ca0132_set_vipsource(codec, 0); if (enable) { /* set DMic input as 2-ch */
tmp = FLOAT_TWO;
dspio_set_uint_param(codec, 0x80, 0x00, tmp);
val = spec->dmic_ctl;
val |= 0x80;
snd_hda_codec_write(codec, spec->input_pins[0], 0,
VENDOR_CHIPIO_DMIC_CTL_SET, val);
if (!(spec->dmic_ctl & 0x20))
chipio_set_control_flag(codec, CONTROL_FLAG_DMIC, 1);
} else { /* set AMic input as mono */
tmp = FLOAT_ONE;
dspio_set_uint_param(codec, 0x80, 0x00, tmp);
val = spec->dmic_ctl; /* clear bit7 and bit5 to disable dmic */
val &= 0x5f;
snd_hda_codec_write(codec, spec->input_pins[0], 0,
VENDOR_CHIPIO_DMIC_CTL_SET, val);
/* * Initialization for Digital Mic.
*/ staticvoid ca0132_init_dmic(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec;
u8 val;
/* Setup Digital Mic here, but don't enable. * Enable based on jack detect.
*/
/* MCLK uses MPIO1, set to enable. * Bit 2-0: MPIO select * Bit 3: set to disable * Bit 7-4: reserved
*/
val = 0x01;
snd_hda_codec_write(codec, spec->input_pins[0], 0,
VENDOR_CHIPIO_DMIC_MCLK_SET, val);
/* Data1 uses MPIO3. Data2 not use * Bit 2-0: Data1 MPIO select * Bit 3: set disable Data1 * Bit 6-4: Data2 MPIO select * Bit 7: set disable Data2
*/
val = 0x83;
snd_hda_codec_write(codec, spec->input_pins[0], 0,
VENDOR_CHIPIO_DMIC_PIN_SET, val);
/* Use Ch-0 and Ch-1. Rate is 48K, mode 1. Disable DMic first. * Bit 3-0: Channel mask * Bit 4: set for 48KHz, clear for 32KHz * Bit 5: mode * Bit 6: set to select Data2, clear for Data1 * Bit 7: set to enable DMic, clear for AMic
*/ if (ca0132_quirk(spec) == QUIRK_ALIENWARE_M17XR4)
val = 0x33; else
val = 0x23; /* keep a copy of dmic ctl val for enable/disable dmic purpuse */
spec->dmic_ctl = val;
snd_hda_codec_write(codec, spec->input_pins[0], 0,
VENDOR_CHIPIO_DMIC_CTL_SET, val);
}
/* * Initialization for Analog Mic 2
*/ staticvoid ca0132_init_analog_mic2(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec;
for (i = 0; i < spec->multiout.num_dacs; i++)
refresh_amp_caps(codec, spec->dacs[i], HDA_OUTPUT);
for (i = 0; i < spec->num_outputs; i++)
refresh_amp_caps(codec, spec->out_pins[i], HDA_OUTPUT);
for (i = 0; i < spec->num_inputs; i++) {
refresh_amp_caps(codec, spec->adcs[i], HDA_INPUT);
refresh_amp_caps(codec, spec->input_pins[i], HDA_INPUT);
}
}
/* If there is an active channel for some reason, find it and free it. */ staticvoid ca0132_alt_free_active_dma_channels(struct hda_codec *codec)
{ unsignedint i, tmp; int status;
/* Read active DSPDMAC channel register. */
status = chipio_read(codec, DSPDMAC_CHNLSTART_MODULE_OFFSET, &tmp); if (status >= 0) { /* AND against 0xfff to get the active channel bits. */
tmp = tmp & 0xfff;
/* If there are no active channels, nothing to free. */ if (!tmp) return;
} else {
codec_dbg(codec, "%s: Failed to read active DSP DMA channel register.\n",
__func__); return;
}
/* * Check each DSP DMA channel for activity, and if the channel is * active, free it.
*/ for (i = 0; i < DSPDMAC_DMA_CFG_CHANNEL_COUNT; i++) { if (dsp_is_dma_active(codec, i)) {
status = dspio_free_dma_chan(codec, i); if (status < 0)
codec_dbg(codec, "%s: Failed to free active DSP DMA channel %d.\n",
__func__, i);
}
}
}
/* * In the case of CT_EXTENSIONS_ENABLE being set to 1, and the DSP being in * use, audio is no longer routed directly to the DAC/ADC from the HDA stream. * Instead, audio is now routed through the DSP's DMA controllers, which * the DSP is tasked with setting up itself. Through debugging, it seems the * cause of most of the no-audio on startup issues were due to improperly * configured DSP DMA channels. * * Normally, the DSP configures these the first time an HDA audio stream is * started post DSP firmware download. That is why creating a 'dummy' stream * worked in fixing the audio in some cases. This works most of the time, but * sometimes if a stream is started/stopped before the DSP can setup the DMA * configuration registers, it ends up in a broken state. Issues can also * arise if streams are started in an unusual order, i.e the audio output dma * channel being sandwiched between the mic1 and mic2 dma channels. * * The solution to this is to make sure that the DSP has no DMA channels * in use post DSP firmware download, and then to manually start each default * DSP stream that uses the DMA channels. These are 0x0c, the audio output * stream, 0x03, analog mic 1, and 0x04, analog mic 2.
*/ staticvoid ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec)
{ staticconstunsignedint dsp_dma_stream_ids[] = { 0x0c, 0x03, 0x04 }; struct ca0132_spec *spec = codec->spec; unsignedint i, tmp;
/* * Check if any of the default streams are active, and if they are, * stop them.
*/
mutex_lock(&spec->chipio_mutex);
for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) {
chipio_get_stream_control(codec, dsp_dma_stream_ids[i], &tmp);
if (tmp) {
chipio_set_stream_control(codec,
dsp_dma_stream_ids[i], 0);
}
}
mutex_unlock(&spec->chipio_mutex);
/* * If all DSP streams are inactive, there should be no active DSP DMA * channels. Check and make sure this is the case, and if it isn't, * free any active channels.
*/
ca0132_alt_free_active_dma_channels(codec);
mutex_lock(&spec->chipio_mutex);
/* Make sure stream 0x0c is six channels. */
chipio_set_stream_channels(codec, 0x0c, 6);
for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) {
chipio_set_stream_control(codec,
dsp_dma_stream_ids[i], 1);
/* Give the DSP some time to setup the DMA channel. */
msleep(75);
}
mutex_unlock(&spec->chipio_mutex);
}
/* * The region of ChipIO memory from 0x190000-0x1903fc is a sort of 'audio * router', where each entry represents a 48khz audio channel, with a format * of an 8-bit destination, an 8-bit source, and an unknown 2-bit number * value. The 2-bit number value is seemingly 0 if inactive, 1 if active, * and 3 if it's using Sample Rate Converter ports. * An example is: * 0x0001f8c0 * In this case, f8 is the destination, and c0 is the source. The number value * is 1. * This region of memory is normally managed internally by the 8051, where * the region of exram memory from 0x1477-0x1575 has each byte represent an * entry within the 0x190000 range, and when a range of entries is in use, the * ending value is overwritten with 0xff. * 0x1578 in exram is a table of 0x25 entries, corresponding to the ChipIO * streamID's, where each entry is a starting 0x190000 port offset. * 0x159d in exram is the same as 0x1578, except it contains the ending port * offset for the corresponding streamID. * * On certain cards, such as the SBZ/ZxR/AE7, these are originally setup by * the 8051, then manually overwritten to remap the ports to work with the * new DACs. * * Currently known portID's: * 0x00-0x1f: HDA audio stream input/output ports. * 0x80-0xbf: Sample rate converter input/outputs. Only valid ports seem to * have the lower-nibble set to 0x1, 0x2, and 0x9. * 0xc0-0xdf: DSP DMA input/output ports. Dynamically assigned. * 0xe0-0xff: DAC/ADC audio input/output ports. * * Currently known streamID's: * 0x03: Mic1 ADC to DSP. * 0x04: Mic2 ADC to DSP. * 0x05: HDA node 0x02 audio stream to DSP. * 0x0f: DSP Mic exit to HDA node 0x07. * 0x0c: DSP processed audio to DACs. * 0x14: DAC0, front L/R. * * It is possible to route the HDA audio streams directly to the DAC and * bypass the DSP entirely, with the only downside being that since the DSP * does volume control, the only volume control you'll get is through PCM on * the PC side, in the same way volume is handled for optical out. This may be * useful for debugging.
*/ staticvoid chipio_remap_stream(struct hda_codec *codec, conststruct chipio_stream_remap_data *remap_data)
{ unsignedint i, stream_offset;
/* Get the starting port for the stream to be remapped. */
chipio_8051_read_exram(codec, 0x1578 + remap_data->stream_id,
&stream_offset);
/* * Check if the stream's port value is 0xff, because the 8051 may not * have gotten around to setting up the stream yet. Wait until it's * setup to remap it's ports.
*/ if (stream_offset == 0xff) { for (i = 0; i < 5; i++) {
msleep(25);
/* * Default speaker tuning values setup for alternative codecs.
*/ staticconstunsignedint sbz_default_delay_values[] = { /* Non-zero values are floating point 0.000198. */
0x394f9e38, 0x394f9e38, 0x00000000, 0x00000000, 0x00000000, 0x00000000
};
staticconstunsignedint zxr_default_delay_values[] = { /* Non-zero values are floating point 0.000220. */
0x00000000, 0x00000000, 0x3966afcd, 0x3966afcd, 0x3966afcd, 0x3966afcd
};
staticconstunsignedint ae5_default_delay_values[] = { /* Non-zero values are floating point 0.000100. */
0x00000000, 0x00000000, 0x38d1b717, 0x38d1b717, 0x38d1b717, 0x38d1b717
};
/* * If we never change these, probably only need them on initialization.
*/ staticvoid ca0132_alt_init_speaker_tuning(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; unsignedint i, tmp, start_req, end_req; constunsignedint *values;
switch (ca0132_quirk(spec)) { case QUIRK_SBZ:
values = sbz_default_delay_values; break; case QUIRK_ZXR:
values = zxr_default_delay_values; break; case QUIRK_AE5: case QUIRK_AE7:
values = ae5_default_delay_values; break; default:
values = sbz_default_delay_values; break;
}
start_req = SPEAKER_TUNING_FRONT_LEFT_VOL_LEVEL;
end_req = SPEAKER_TUNING_REAR_RIGHT_VOL_LEVEL; for (i = start_req; i < end_req + 1; i++)
dspio_set_uint_param(codec, 0x96, i, tmp);
start_req = SPEAKER_TUNING_FRONT_LEFT_INVERT;
end_req = SPEAKER_TUNING_REAR_RIGHT_INVERT; for (i = start_req; i < end_req + 1; i++)
dspio_set_uint_param(codec, 0x96, i, tmp);
for (i = 0; i < 6; i++)
dspio_set_uint_param(codec, 0x96,
SPEAKER_TUNING_FRONT_LEFT_DELAY + i, values[i]);
}
/* * Sets the source of stream 0x14 to connpointID 0x48, and the destination * connpointID to 0x91. If this isn't done, the destination is 0x71, and * you get no sound. I'm guessing this has to do with the Sound Blaster Z * having an updated DAC, which changes the destination to that DAC.
*/ staticvoid sbz_connect_streams(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec;
mutex_lock(&spec->chipio_mutex);
codec_dbg(codec, "Connect Streams entered, mutex locked and loaded.\n");
/* This value is 0x43 for 96khz, and 0x83 for 192khz. */
chipio_write_no_mutex(codec, 0x18a020, 0x00000043);
/* * Write data through ChipIO to setup proper stream destinations. * Not sure how it exactly works, but it seems to direct data * to different destinations. Example is f8 to c0, e0 to c0. * All I know is, if you don't set these, you get no sound.
*/ staticvoid sbz_chipio_startup_data(struct hda_codec *codec)
{ conststruct chipio_stream_remap_data *dsp_out_remap_data; struct ca0132_spec *spec = codec->spec;
mutex_lock(&spec->chipio_mutex);
codec_dbg(codec, "Startup Data entered, mutex locked and loaded.\n");
staticvoid ae5_post_dsp_param_setup(struct hda_codec *codec)
{ /* * Param3 in the 8051's memory is represented by the ascii string 'mch' * which seems to be 'multichannel'. This is also mentioned in the * AE-5's registry values in Windows.
*/
chipio_set_control_param(codec, 3, 0); /* * I believe ASI is 'audio serial interface' and that it's used to * change colors on the external LED strip connected to the AE-5.
*/
chipio_set_control_flag(codec, CONTROL_FLAG_ASI_96KHZ, 1);
chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_NODE_ID, 0x09); /* * In the 8051's memory, this param is referred to as 'n2sid', which I * believe is 'node to streamID'. It seems to be a way to assign a * stream to a given HDA node.
*/
chipio_set_control_param_no_mutex(codec, 0x20, 0x21);
/* * Now, at this point on Windows, an actual stream is setup and * seemingly sends data to the HDA node 0x09, which is the digital * audio input node. This is left out here, because obviously I don't * know what data is being sent. Interestingly, the AE-5 seems to go * through the motions of getting here and never actually takes this * step, but the AE-7 does.
*/
/* * Runs again, this has been repeated a few times, but I'm just * following what the Windows driver does.
*/
ae7_post_dsp_pll_setup(codec);
chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7);
mutex_unlock(&spec->chipio_mutex);
}
/* * The Windows driver has commands that seem to setup ASI, which I believe to * be some sort of audio serial interface. My current speculation is that it's * related to communicating with the new DAC.
*/ staticvoid ae7_post_dsp_asi_setup(struct hda_codec *codec)
{
chipio_8051_write_direct(codec, 0x93, 0x10);
/* Set speaker source? */
dspio_set_uint_param(codec, 0x32, 0x00, tmp);
if (ca0132_quirk(spec) == QUIRK_R3DI)
r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADED);
/* Disable mute on Center/LFE. */ if (ca0132_quirk(spec) == QUIRK_R3D) {
ca0113_mmio_gpio_set(codec, 2, false);
ca0113_mmio_gpio_set(codec, 4, true);
}
/* Setup effect defaults */
num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1; for (idx = 0; idx < num_fx; idx++) { for (i = 0; i <= ca0132_effects[idx].params; i++) {
dspio_set_uint_param(codec,
ca0132_effects[idx].mid,
ca0132_effects[idx].reqs[i],
ca0132_effects[idx].def_vals[i]);
}
}
}
/* * Setup default parameters for the Sound Blaster Z DSP. A lot more going on * than the Chromebook setup.
*/ staticvoid sbz_setup_defaults(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; unsignedint tmp; int num_fx; int idx, i;
/* * Sets internal input loopback to off, used to have a switch to * enable input loopback, but turned out to be way too buggy.
*/
tmp = FLOAT_ONE;
dspio_set_uint_param(codec, 0x37, 0x08, tmp);
dspio_set_uint_param(codec, 0x37, 0x10, tmp);
/* * This is the second time we've called this, but this is seemingly * what Windows does.
*/
ca0132_alt_init_analog_mics(codec);
ae7_post_dsp_asi_setup(codec);
/* * Not sure why, but these are both set to 1. They're only set to 0 * upon shutdown.
*/
ca0113_mmio_gpio_set(codec, 0, true);
ca0113_mmio_gpio_set(codec, 1, true);
staticbool ca0132_download_dsp_images(struct hda_codec *codec)
{ bool dsp_loaded = false; struct ca0132_spec *spec = codec->spec; conststruct dsp_image_seg *dsp_os_image; conststruct firmware *fw_entry = NULL; /* * Alternate firmwares for different variants. The Recon3Di apparently * can use the default firmware, but I'll leave the option in case * it needs it again.
*/ switch (ca0132_quirk(spec)) { case QUIRK_SBZ: case QUIRK_R3D: case QUIRK_AE5: if (request_firmware(&fw_entry, DESKTOP_EFX_FILE,
codec->card->dev) != 0)
codec_dbg(codec, "Desktop firmware not found."); else
codec_dbg(codec, "Desktop firmware selected."); break; case QUIRK_R3DI: if (request_firmware(&fw_entry, R3DI_EFX_FILE,
codec->card->dev) != 0)
codec_dbg(codec, "Recon3Di alt firmware not detected."); else
codec_dbg(codec, "Recon3Di firmware selected."); break; default: break;
} /* * Use default ctefx.bin if no alt firmware is detected, or if none * exists for your particular codec.
*/ if (!fw_entry) {
codec_dbg(codec, "Default firmware selected."); if (request_firmware(&fw_entry, EFX_FILE,
codec->card->dev) != 0) returnfalse;
}
if (spec->dsp_state == DSP_DOWNLOAD_FAILED) return; /* don't retry failures */
chipio_enable_clocks(codec); if (spec->dsp_state != DSP_DOWNLOADED) {
spec->dsp_state = DSP_DOWNLOADING;
if (!ca0132_download_dsp_images(codec))
spec->dsp_state = DSP_DOWNLOAD_FAILED; else
spec->dsp_state = DSP_DOWNLOADED;
}
/* For codecs using alt functions, this is already done earlier */ if (spec->dsp_state == DSP_DOWNLOADED && !ca0132_use_alt_functions(spec))
ca0132_set_dsp_msr(codec, true);
}
/* Delay enabling the HP amp, to let the mic-detection * state machine run.
*/
tbl = snd_hda_jack_tbl_get(codec, cb->nid); if (tbl)
tbl->block_report = 1;
schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500));
}
staticvoid ca0132_init_chip(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; int num_fx; int i; unsignedint on;
mutex_init(&spec->chipio_mutex);
/* * The Windows driver always does this upon startup, which seems to * clear out any previous configuration. This should help issues where * a boot into Windows prior to a boot into Linux breaks things. Also, * Windows always sends the reset twice.
*/ if (ca0132_use_alt_functions(spec)) {
chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0);
chipio_write_no_mutex(codec, 0x18b0a4, 0x000000c2);
for (i = 0; i < VNODES_COUNT; i++) {
spec->vnode_lvol[i] = 0x5a;
spec->vnode_rvol[i] = 0x5a;
spec->vnode_lswitch[i] = 0;
spec->vnode_rswitch[i] = 0;
}
/* * Default states for effects are in ca0132_effects[].
*/
num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; for (i = 0; i < num_fx; i++) {
on = (unsignedint)ca0132_effects[i].reqs[0];
spec->effects_switch[i] = on ? 1 : 0;
} /* * Sets defaults for the effect slider controls, only for alternative * ca0132 codecs. Also sets x-bass crossover frequency to 80hz.
*/ if (ca0132_use_alt_controls(spec)) { /* Set speakers to default to full range. */
spec->speaker_range_val[0] = 1;
spec->speaker_range_val[1] = 1;
spec->xbass_xover_freq = 8; for (i = 0; i < EFFECT_LEVEL_SLIDERS; i++)
spec->fx_ctl_val[i] = effect_slider_defaults[i];
/* * The ZxR doesn't have a front panel header, and it's line-in is on * the daughter board. So, there is no input enum control, and we need * to make sure that spec->in_enum_val is set properly.
*/ if (ca0132_quirk(spec) == QUIRK_ZXR)
spec->in_enum_val = REAR_MIC;
for (i = 0; i < ARRAY_SIZE(pins); i++) {
snd_hda_codec_write(codec, pins[i], 0,
AC_VERB_SET_UNSOLICITED_ENABLE, 0x00);
}
}
/* On shutdown, sends commands in sets of three */ staticvoid sbz_gpio_shutdown_commands(struct hda_codec *codec, int dir, int mask, int data)
{ if (dir >= 0)
snd_hda_codec_write(codec, 0x01, 0,
AC_VERB_SET_GPIO_DIRECTION, dir); if (mask >= 0)
snd_hda_codec_write(codec, 0x01, 0,
AC_VERB_SET_GPIO_MASK, mask);
if (data >= 0)
snd_hda_codec_write(codec, 0x01, 0,
AC_VERB_SET_GPIO_DATA, data);
}
staticvoid ca0132_exit_chip(struct hda_codec *codec)
{ /* put any chip cleanup stuffs here. */
if (dspload_is_loaded(codec))
dsp_reset(codec);
}
/* * This fixes a problem that was hard to reproduce. Very rarely, I would * boot up, and there would be no sound, but the DSP indicated it had loaded * properly. I did a few memory dumps to see if anything was different, and * there were a few areas of memory uninitialized with a1a2a3a4. This function * checks if those areas are uninitialized, and if they are, it'll attempt to * reload the card 3 times. Usually it fixes by the second.
*/ staticvoid sbz_dsp_startup_check(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; unsignedint dsp_data_check[4]; unsignedint cur_address = 0x390; unsignedint i; unsignedint failure = 0; unsignedint reload = 3;
if (spec->startup_check_entered) return;
spec->startup_check_entered = true;
for (i = 0; i < 4; i++) {
chipio_read(codec, cur_address, &dsp_data_check[i]);
cur_address += 0x4;
} for (i = 0; i < 4; i++) { if (dsp_data_check[i] == 0xa1a2a3a4)
failure = 1;
}
codec_dbg(codec, "Startup Check: %d ", failure); if (failure)
codec_info(codec, "DSP not initialized properly. Attempting to fix."); /* * While the failure condition is true, and we haven't reached our * three reload limit, continue trying to reload the driver and * fix the issue.
*/ while (failure && (reload != 0)) {
codec_info(codec, "Reloading... Tries left: %d", reload);
sbz_exit_chip(codec);
spec->dsp_state = DSP_DOWNLOAD_INIT;
snd_hda_codec_init(codec);
failure = 0; for (i = 0; i < 4; i++) {
chipio_read(codec, cur_address, &dsp_data_check[i]);
cur_address += 0x4;
} for (i = 0; i < 4; i++) { if (dsp_data_check[i] == 0xa1a2a3a4)
failure = 1;
}
reload--;
}
if (!failure && reload < 3)
codec_info(codec, "DSP fixed.");
if (!failure) return;
codec_info(codec, "DSP failed to initialize properly. Either try a full shutdown or a suspend to clear the internal memory.");
}
/* * This is for the extra volume verbs 0x797 (left) and 0x798 (right). These add * extra precision for decibel values. If you had the dB value in floating point * you would take the value after the decimal point, multiply by 64, and divide * by 2. So for 8.59, it's (59 * 64) / 100. Useful if someone wanted to * implement fixed point or floating point dB volumes. For now, I'll set them * to 0 just incase a value has lingered from a boot into Windows.
*/ staticvoid ca0132_alt_vol_setup(struct hda_codec *codec)
{
snd_hda_codec_write(codec, 0x02, 0, 0x797, 0x00);
snd_hda_codec_write(codec, 0x02, 0, 0x798, 0x00);
snd_hda_codec_write(codec, 0x03, 0, 0x797, 0x00);
snd_hda_codec_write(codec, 0x03, 0, 0x798, 0x00);
snd_hda_codec_write(codec, 0x04, 0, 0x797, 0x00);
snd_hda_codec_write(codec, 0x04, 0, 0x798, 0x00);
snd_hda_codec_write(codec, 0x07, 0, 0x797, 0x00);
snd_hda_codec_write(codec, 0x07, 0, 0x798, 0x00);
}
/* * Extra commands that don't really fit anywhere else.
*/ staticvoid sbz_pre_dsp_setup(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec;
/* * The ZxR seems to use alternative DAC's for the surround channels, which * require PLL PMU setup for the clock rate, I'm guessing. Without setting * this up, we get no audio out of the surround jacks.
*/ staticvoid zxr_pre_dsp_setup(struct hda_codec *codec)
{ staticconstunsignedint addr[] = { 0x43, 0x40, 0x41, 0x42, 0x45 }; staticconstunsignedint data[] = { 0x08, 0x0c, 0x0b, 0x07, 0x0d }; unsignedint i;
/* * This writes a RET instruction at the entry point of the function at * 0xfa92 in exram. This function seems to have something to do with * ASI. Might be some way to prevent the card from reconfiguring the * ASI stuff itself.
*/
chipio_8051_write_exram(codec, 0xfa92, 0x22);
for (i = 0; i < ARRAY_SIZE(addr); i++)
chipio_8051_write_pll_pmu(codec, addr[i], data[i]);
}
/* * These are sent before the DSP is downloaded. Not sure * what they do, or if they're necessary. Could possibly * be removed. Figure they're better to leave in.
*/ staticconstunsignedint ca0113_mmio_init_address_sbz[] = {
0x400, 0x408, 0x40c, 0x01c, 0xc0c, 0xc00, 0xc04, 0xc0c, 0xc0c, 0xc0c,
0xc0c, 0xc08, 0xc08, 0xc08, 0xc08, 0xc08, 0xc04
};
for (i = 0; i < count; i++) { /* * AE-7 shares all writes with the AE-5, except that it writes * a different value to 0x20c.
*/ if (i == 21 && ca0132_quirk(spec) == QUIRK_AE7) {
writel(0x00800001, spec->mem_base + addr[i]); continue;
}
writel(data[i], spec->mem_base + addr[i]);
}
if (ca0132_quirk(spec) == QUIRK_AE5)
writel(0x00880680, spec->mem_base + 0x1c);
}
switch (ca0132_quirk(spec)) { case QUIRK_R3D: case QUIRK_SBZ: case QUIRK_ZXR:
ca0132_mmio_init_sbz(codec); break; case QUIRK_AE5:
ca0132_mmio_init_ae5(codec); break; default: break;
}
}
/* * This function writes to some SFR's, does some region2 writes, and then * eventually resets the codec with the 0x7ff verb. Not quite sure why it does * what it does.
*/ staticvoid ae5_register_set(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec; unsignedint count = ARRAY_SIZE(ca0132_ae5_register_set_addresses); constunsignedint *addr = ca0132_ae5_register_set_addresses; constunsignedchar *data = ca0132_ae5_register_set_data; unsignedint i, cur_addr; unsignedchar tmp[3];
if (ca0132_quirk(spec) == QUIRK_AE7)
chipio_8051_write_pll_pmu(codec, 0x41, 0xc8);
for (i = cur_addr = 0; i < 3; i++, cur_addr++)
writeb(tmp[i], spec->mem_base + addr[cur_addr]);
/* * First writes are in single bytes, final are in 4 bytes. So, we use * writeb, then writel.
*/ for (i = 0; cur_addr < 12; i++, cur_addr++)
writeb(data[i], spec->mem_base + addr[cur_addr]);
if (ca0132_quirk(spec) == QUIRK_AE5)
ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
}
/* * Extra init functions for alternative ca0132 codecs. Done * here so they don't clutter up the main ca0132_init function * anymore than they have to.
*/ staticvoid ca0132_alt_init(struct hda_codec *codec)
{ struct ca0132_spec *spec = codec->spec;
/* * If the DSP is already downloaded, and init has been entered again, * there's only two reasons for it. One, the codec has awaken from a * suspended state, and in that case dspload_is_loaded will return * false, and the init will be ran again. The other reason it gets * re entered is on startup for some reason it triggers a suspend and * resume state. In this case, it will check if the DSP is downloaded, * and not run the init function again. For codecs using alt_functions, * it will check if the DSP is loaded properly.
*/ if (spec->dsp_state == DSP_DOWNLOADED) {
dsp_loaded = dspload_is_loaded(codec); if (!dsp_loaded) {
spec->dsp_reload = true;
spec->dsp_state = DSP_DOWNLOAD_INIT;
} else { if (ca0132_quirk(spec) == QUIRK_SBZ)
sbz_dsp_startup_check(codec); return 0;
}
}
if (spec->dsp_state != DSP_DOWNLOAD_FAILED)
spec->dsp_state = DSP_DOWNLOAD_INIT;
spec->curr_chip_addx = INVALID_CHIP_ADDRESS;
if (ca0132_use_pci_mmio(spec))
ca0132_mmio_init(codec);
snd_hda_power_up_pm(codec);
if (ca0132_quirk(spec) == QUIRK_AE5 || ca0132_quirk(spec) == QUIRK_AE7)
ae5_register_set(codec);
if (ca0132_use_alt_functions(spec))
ca0132_alt_init(codec);
ca0132_download_dsp(codec);
ca0132_refresh_widget_caps(codec);
switch (ca0132_quirk(spec)) { case QUIRK_R3DI: case QUIRK_R3D:
r3d_setup_defaults(codec); break; case QUIRK_SBZ: case QUIRK_ZXR:
sbz_setup_defaults(codec); break; case QUIRK_AE5:
ae5_setup_defaults(codec); break; case QUIRK_AE7:
ae7_setup_defaults(codec); break; default:
ca0132_setup_defaults(codec);
ca0132_init_analog_mic2(codec);
ca0132_init_dmic(codec); break;
}
for (i = 0; i < spec->num_outputs; i++)
init_output(codec, spec->out_pins[i], spec->dacs[0]);
/* * Re set the PlayEnhancement switch on a resume event, because the * controls will not be reloaded.
*/ if (spec->dsp_reload) {
spec->dsp_reload = false;
ca0132_pe_switch_set(codec);
}
spec->chip_init_verbs = ca0132_init_verbs0; /* * Since desktop cards use pci_mmio, this can be used to determine * whether or not to use these verbs instead of a separate bool.
*/ if (ca0132_use_pci_mmio(spec))
spec->desktop_init_verbs = ca0132_init_verbs1;
spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS, sizeof(struct hda_verb),
GFP_KERNEL); if (!spec->spec_init_verbs) return -ENOMEM;
/* * The Sound Blaster ZxR shares the same PCI subsystem ID as some regular * Sound Blaster Z cards. However, they have different HDA codec subsystem * ID's. So, we check for the ZxR's subsystem ID, as well as the DBPro * daughter boards ID.
*/ staticvoid sbz_detect_quirk(struct hda_codec *codec)
{ switch (codec->core.subsystem_id) { case 0x11020033:
codec->fixup_id = QUIRK_ZXR; break; case 0x1102003f:
codec->fixup_id = QUIRK_ZXR_DBPRO; break; default:
codec->fixup_id = QUIRK_SBZ; break;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.