This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TLV320AIC3110:限制最大音量级别

Guru**** 2382480 points
Other Parts Discussed in Thread: TLV320AIC3110
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/audio-group/audio/f/audio-forum/1248707/tlv320aic3110-limiting-the-maximum-volume-level

器件型号:TLV320AIC3110

您好!

我正在尝试限制 tlv320aic3110允许的最大音量。 在我们的初始测试中、当音量处于其最大默认音量时、它最终会损坏扬声器。 目前、我们正在使用 ALSA 控件降低默认音量、但我们希望有一个即使使用 ALSA 控件也无法超越的限值。 我的想法是使用从器件树中读取的一些值、这些值会写入相应的寄存器。

我已成功修改驱动程序以读取这些值并且正在写入一系列寄存器、但这似乎没有任何效果。 当我在我们的终端中加载操作系统并将音量级别修改为最大值时、我似乎在没有修改的情况下获得了相同的音量。

这些是我要写入的寄存器:

if (strncmp(name, "SP Analog Playback Volume", 25) == 0) {
	aic31xx->SP_Analog_Playback_Volume = 127 - limit;
}

if (strncmp(name, "SP Driver Playback Volume", 25) == 0) {
	aic31xx->SP_Driver_Playback_Volume = limit;
}

ret = snd_soc_component_write(component, AIC31XX_DACMIXERROUTE, 0x44);	/* Page 1 / Register 35 (0x23): DAC_L and DAC_R Output Mixer Routing */
ret = snd_soc_component_write(component, AIC31XX_LANALOGHPL, 0xC0);	/* Page 1 / Register 36 (0x24): Left Analog Volume to HPL */
ret = snd_soc_component_write(component, AIC31XX_RANALOGHPR, 0xC0);	/* Page 1 / Register 37 (0x25): Right Analog Volume to HPR */
ret = snd_soc_component_write(component, AIC31XX_LANALOGSPL, (aic31xx->SP_Analog_Playback_Volume & 0x7F) | 0x80);	/* Page 1 / Register 38 (0x26): Left Analog Volume to SPL */
ret = snd_soc_component_write(component, AIC31XX_RANALOGSPR, (aic31xx->SP_Analog_Playback_Volume & 0x7F) | 0x80);	/* Page 1 / Register 39 (0x27): Right Analog Volume to SPR */
ret = snd_soc_component_write(component, AIC31XX_HPDRIVER, 0xc4);	/* Page 1 / Register 31 (0x1F): Headphone Drivers */
ret = snd_soc_component_write(component, AIC31XX_HPLGAIN, 0x4d);	/* Page 1 / Register 40 (0x28): HPL Driver */
ret = snd_soc_component_write(component, AIC31XX_HPRGAIN, 0x4d);	/* Page 1 / Register 41 (0x29): HPR Driver */
ret = snd_soc_component_write(component, AIC31XX_SPLGAIN, ((aic31xx->SP_Driver_Playback_Volume & 0x03) << 3) | 0x5);	/* Page 1 / Register 42 (0x2A): SPL Driver */
ret = snd_soc_component_write(component, AIC31XX_SPRGAIN, ((aic31xx->SP_Driver_Playback_Volume & 0x03) << 3) | 0x5);	/* Page 1 / Register 43 (0x2B): SPR Driver */
ret = snd_soc_component_write(component, AIC31XX_SPKAMP, 0xc6);	/* Page 1 / Register 32 (0x20): Class-D Speaker Amplifier */
ret = snd_soc_component_write(component, AIC31XX_LANALOGSPL, 0x74);	/* Page 1 / Register 38 (0x26): Left Analog Volume to SPL */
ret = snd_soc_component_write(component, AIC31XX_RANALOGSPR, 0x74);	/* Page 1 / Register 39 (0x27): Right Analog Volume to SPR */

我将在探针函数中的最后、即在读取前面提到的器件树中的值之后立即写入它们。 根据写入函数返回的值、该操作成功、读取函数返回与我尝试写入的值相同的值。

我是应该在不同的地方写入这些寄存器还是以特定的频率(例如每分钟)写入这些寄存器? 这可能是完全不同的事情吗?

要修改音量一旦我的更改被安装,我要使用 alsamixer,我要使用 speaker-test 来产生声音。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好! Jesús

    我认为在对寄存器进行初始写入后、无需重新应用设置。  

    首先、您可以尝试通过将寄存器42和43位7-1设置为0b0000010、将驱动器增益设置为恒定的6dB 吗? 然后、我们可以尝试改变模拟输出控制、以查看是否存在差异。

    此外,是否有理由在上述代码第12/13行设置 Reg 38/39,并在第20/21行再次设置 Reg 38/39? 我认为像第20/21行一样将它们设置为0x74 会导致模拟音量控制静音、因为第7位将设置为0。 您可以尝试在此处将这些设置设置为 F4、以查看是否听到差异。 输出未使用当前代码静音这一事实确实会让我怀疑设置是否持续应用。

    请告诉我这是否有帮助!

    此致、
    卢卡斯

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    我已经尝试将42和43设置为0b0000010、然后将38和39设置为0xF4、但似乎没有任何变化。 当我使用 alsamixer 将其设置为最大值时,音量似乎相同。 我是否需要执行某些操作才能使更改生效?

    关于设置38和39、我真的没有注意到。 我写了第一行,当我看到它没有任何效果,在我的调查期间,我看到这两个寄存器,并在最后添加他们,我想我以前忘记了使用它们。

    谢谢你。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好  Jesús

    感谢您尝试这些建议。 我在您的代码中注意到您不是在写入页寄存器(0x00)。 如果你还没有在其他地方这么做、那么在进行其他写入之前、你可以尝试将0x01写入寄存器0x00以选择页1吗?

    此致、
    卢卡斯

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    我已经添加了该内容、它似乎没有正确设置为0x01。 我在所有写入的开头添加了这一点:

    ret = snd_soc_component_write(component, AIC31XX_PAGECTL, 0x01); /* Page Control Register */
    
    if (ret < 0) {
    	dev_info(aic31xx->dev, ~~~~~Error in write - %d\n", ret);
    }
    else {
    	dev_info(aic31xx->dev, "~~~~~Register value - "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(snd_soc_component_read(component, AIC31XX_PAGECTL)));
    	dev_info(aic31xx->dev, "~~~~~Wanted to write: "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(0x01));
    }
    

    这就是 dmesg 告诉我的:

    [    7.251271] tlv320aic31xx-codec 0-0018: ASoC: error at soc_component_read_no_lock on tlv320aic31xx-codec.0-0018: -16
    [    7.312438] tlv320aic31xx-codec 0-0018: ASoC: error at soc_component_read_no_lock on tlv320aic31xx-codec.0-0018: -16
    [    7.405444] tlv320aic31xx-codec 0-0018: ASoC: error at soc_component_read_no_lock on tlv320aic31xx-codec.0-0018: -16
    [    7.449900] tlv320aic31xx-codec 0-0018: ASoC: error at soc_component_read_no_lock on tlv320aic31xx-codec.0-0018: -16
    [    7.485123] tlv320aic31xx-codec 0-0018: ASoC: error at soc_component_read_no_lock on tlv320aic31xx-codec.0-0018: -16
    [    7.522520] tlv320aic31xx-codec 0-0018: ASoC: error at soc_component_read_no_lock on tlv320aic31xx-codec.0-0018: -16
    [    7.554308] tlv320aic31xx-codec 0-0018: ASoC: error at soc_component_read_no_lock on tlv320aic31xx-codec.0-0018: -16
    [    7.586582] tlv320aic31xx-codec 0-0018: ASoC: error at soc_component_read_no_lock on tlv320aic31xx-codec.0-0018: -16
    [    7.619376] tlv320aic31xx-codec 0-0018: ~~~~~Register value - 11110000
    [    7.619415] tlv320aic31xx-codec 0-0018: ~~~~~Wanted to write: 00000001

    我也尝试过写入"页0/寄存器1 (0x01):软件复位"、但我有相同的问题。 它在对其进行"写入"之后几次读取失败、然后显示错误的值、即二进制的-16。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好! Jesús

    如果您想限制 最大音量,并通过 alsamixer 调节音量。 您不需要重写寄存器、因为每次您调整 kcontrol 时、都会进行修改。 我的建议是重写 kcontrol 的最大值。

    请参阅以下几行代码。

    static const struct snd_kcontrol_new common31xx_snd_controls[] = {
    	SOC_DOUBLE_R_S_TLV("DAC Playback Volume", AIC31XX_LDACVOL,
    			   AIC31XX_RDACVOL, 0, -127, 48, 7, 0, dac_vol_tlv),
    
    	SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN,
    		     AIC31XX_HPRGAIN, 2, 1, 0),
    	SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN,
    			 AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv),
    
    	SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
    			 AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
    
    	/* HP de-pop control: apply power not immediately but via ramp
    	 * function with these psarameters. Note that power up sequence
    	 * has to wait for this to complete; this is implemented by
    	 * polling HP driver status in aic31xx_dapm_power_event()
    	 */
    	SOC_ENUM("HP Output Driver Power-On time", hp_poweron_time_enum),
    	SOC_ENUM("HP Output Driver Ramp-up step", hp_rampup_step_enum),
    
    	SOC_ENUM("Volume Soft Stepping", vol_soft_step_mode_enum),
    };
    
    static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
    	SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1,
    		       adc_fgain_tlv),
    
    	SOC_SINGLE("ADC Capture Switch", AIC31XX_ADCFGA, 7, 1, 1),
    	SOC_DOUBLE_R_S_TLV("ADC Capture Volume", AIC31XX_ADCVOL, AIC31XX_ADCVOL,
    			   0, -24, 40, 6, 0, adc_cgain_tlv),
    
    	SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0,
    		       119, 0, mic_pga_tlv),
    };
    
    static const struct snd_kcontrol_new aic311x_snd_controls[] = {
    	SOC_DOUBLE_R("Speaker Driver Playback Switch", AIC31XX_SPLGAIN,
    		     AIC31XX_SPRGAIN, 2, 1, 0),
    	SOC_DOUBLE_R_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN,
    			 AIC31XX_SPRGAIN, 3, 3, 0, class_D_drv_tlv),
    
    	SOC_DOUBLE_R_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL,
    			 AIC31XX_RANALOGSPR, 0, 0x7F, 1, sp_vol_tlv),
    };

     snd_kcontrol_new 的结构 将创建您在 alsamixer 中使用的 kcontrol,请参见每个宏的定义。 例如、检查 SOC_DOUBLE_R_TLV 和  SOC_DOUBLE_R_S_TLV 的定义、 Xmax 对应于寄存器设置的最大值、因此对 Xmax 进行限制、您应该限制最大音量。 为了控制扬声器的输出、您应该 修改 "Speaker Driver Playback Volume (扬声器驱动程序 播放音量)"和"DAC Playback Volume (DAC 播放音量)"。

    #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
    {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
    	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
    		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
    	.tlv.p = (tlv_array), \
    	.info = snd_soc_info_volsw, \
    	.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
    	.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
    					    xmax, xinvert) }
    
    #define SOC_DOUBLE_R_S_TLV(xname, reg_left, reg_right, xshift, xmin, xmax, xsign_bit, xinvert, tlv_array) \
    {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
    	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
    		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
    	.tlv.p = (tlv_array), \
    	.info = snd_soc_info_volsw, \
    	.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
    	.private_value = SOC_DOUBLE_R_S_VALUE(reg_left, reg_right, xshift, \
    					    xmin, xmax, xsign_bit, xinvert) }

    我希望这些信息能有所帮助、请告诉我这是否可行。

    谢谢

    凯文·卢

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    我修改了该结构中的值、现在已成功更改最大卷。 非常感谢。

    现在我必须根据器件树中的值修改它、但这是另一个问题。

    非常感谢您的帮助。