Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: cs35l45: Analog PCM Volume and Amplifier Mode controls

Adds "Analog PCM Volume" control with supported values
0 = 10dB,1 = 13dB,2 = 16dB and 3 = 19dB.
The amplifier can operate either in Speaker Mode or Receiver Mode
as configured by the user. Speaker Mode has four gain options
to support maximum amplifier output amplitude for loud
speaker application. Receiver Mode has further optimized
noise performance while maintaining sufficient output to support
phone receiver application. While configured in Receiver Mode,
the analog PCM Volume control is disabled and
the analog gain is fixed to 1dB.

Signed-off-by: Vlad Karpovich <vkarpovi@opensource.cirrus.com>
Acked-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20230831162042.471801-2-vkarpovi@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Vlad Karpovich and committed by
Mark Brown
18050443 44f37b6c

+184 -2
+3
sound/soc/codecs/cs35l45-tables.c
··· 91 91 { CS35L45_DSP1RX7_INPUT, 0x0000003A }, 92 92 { CS35L45_DSP1RX8_INPUT, 0x00000028 }, 93 93 { CS35L45_AMP_PCM_CONTROL, 0x00100000 }, 94 + { CS35L45_AMP_GAIN, 0x00002300 }, 94 95 { CS35L45_IRQ1_CFG, 0x00000000 }, 95 96 { CS35L45_IRQ1_MASK_1, 0xBFEFFFBF }, 96 97 { CS35L45_IRQ1_MASK_2, 0xFFFFFFFF }, ··· 157 156 case CS35L45_DSP1RX6_INPUT: 158 157 case CS35L45_DSP1RX7_INPUT: 159 158 case CS35L45_DSP1RX8_INPUT: 159 + case CS35L45_HVLV_CONFIG: 160 160 case CS35L45_AMP_PCM_CONTROL: 161 + case CS35L45_AMP_GAIN: 161 162 case CS35L45_AMP_PCM_HPF_TST: 162 163 case CS35L45_IRQ1_CFG: 163 164 case CS35L45_IRQ1_STATUS:
+148
sound/soc/codecs/cs35l45.c
··· 169 169 return 0; 170 170 } 171 171 172 + static int cs35l45_activate_ctl(struct snd_soc_component *component, 173 + const char *ctl_name, bool active) 174 + { 175 + struct snd_card *card = component->card->snd_card; 176 + struct snd_kcontrol *kcontrol; 177 + struct snd_kcontrol_volatile *vd; 178 + unsigned int index_offset; 179 + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 180 + 181 + if (component->name_prefix) 182 + snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s", 183 + component->name_prefix, ctl_name); 184 + else 185 + snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s", ctl_name); 186 + 187 + kcontrol = snd_soc_card_get_kcontrol(component->card, name); 188 + if (!kcontrol) { 189 + dev_err(component->dev, "Can't find kcontrol %s\n", name); 190 + return -EINVAL; 191 + } 192 + 193 + index_offset = snd_ctl_get_ioff(kcontrol, &kcontrol->id); 194 + vd = &kcontrol->vd[index_offset]; 195 + if (active) 196 + vd->access |= SNDRV_CTL_ELEM_ACCESS_WRITE; 197 + else 198 + vd->access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE; 199 + 200 + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &kcontrol->id); 201 + 202 + return 0; 203 + } 204 + 205 + static int cs35l45_amplifier_mode_get(struct snd_kcontrol *kcontrol, 206 + struct snd_ctl_elem_value *ucontrol) 207 + { 208 + struct snd_soc_component *component = 209 + snd_soc_kcontrol_component(kcontrol); 210 + struct cs35l45_private *cs35l45 = 211 + snd_soc_component_get_drvdata(component); 212 + 213 + ucontrol->value.integer.value[0] = cs35l45->amplifier_mode; 214 + 215 + return 0; 216 + } 217 + 218 + static int cs35l45_amplifier_mode_put(struct snd_kcontrol *kcontrol, 219 + struct snd_ctl_elem_value *ucontrol) 220 + { 221 + struct snd_soc_component *component = 222 + snd_soc_kcontrol_component(kcontrol); 223 + struct cs35l45_private *cs35l45 = 224 + snd_soc_component_get_drvdata(component); 225 + struct snd_soc_dapm_context *dapm = 226 + snd_soc_component_get_dapm(component); 227 + unsigned int amp_state; 228 + int ret; 229 + 230 + if ((ucontrol->value.integer.value[0] == cs35l45->amplifier_mode) || 231 + (ucontrol->value.integer.value[0] > AMP_MODE_RCV)) 232 + return 0; 233 + 234 + snd_soc_dapm_mutex_lock(dapm); 235 + 236 + ret = regmap_read(cs35l45->regmap, CS35L45_BLOCK_ENABLES, &amp_state); 237 + if (ret < 0) { 238 + dev_err(cs35l45->dev, "Failed to read AMP state: %d\n", ret); 239 + snd_soc_dapm_mutex_unlock(dapm); 240 + return ret; 241 + } 242 + 243 + regmap_clear_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES, 244 + CS35L45_AMP_EN_MASK); 245 + snd_soc_component_disable_pin_unlocked(component, "SPK"); 246 + snd_soc_dapm_sync_unlocked(dapm); 247 + 248 + if (ucontrol->value.integer.value[0] == AMP_MODE_SPK) { 249 + regmap_clear_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES, 250 + CS35L45_RCV_EN_MASK); 251 + 252 + regmap_update_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES, 253 + CS35L45_BST_EN_MASK, 254 + CS35L45_BST_ENABLE << CS35L45_BST_EN_SHIFT); 255 + 256 + regmap_update_bits(cs35l45->regmap, CS35L45_HVLV_CONFIG, 257 + CS35L45_HVLV_MODE_MASK, 258 + CS35L45_HVLV_OPERATION << 259 + CS35L45_HVLV_MODE_SHIFT); 260 + 261 + ret = cs35l45_activate_ctl(component, "Analog PCM Volume", true); 262 + if (ret < 0) 263 + dev_err(cs35l45->dev, 264 + "Unable to deactivate ctl (%d)\n", ret); 265 + 266 + } else /* AMP_MODE_RCV */ { 267 + regmap_set_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES, 268 + CS35L45_RCV_EN_MASK); 269 + 270 + regmap_update_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES, 271 + CS35L45_BST_EN_MASK, 272 + CS35L45_BST_DISABLE_FET_OFF << 273 + CS35L45_BST_EN_SHIFT); 274 + 275 + regmap_update_bits(cs35l45->regmap, CS35L45_HVLV_CONFIG, 276 + CS35L45_HVLV_MODE_MASK, 277 + CS35L45_FORCE_LV_OPERATION << 278 + CS35L45_HVLV_MODE_SHIFT); 279 + 280 + regmap_clear_bits(cs35l45->regmap, 281 + CS35L45_BLOCK_ENABLES2, 282 + CS35L45_AMP_DRE_EN_MASK); 283 + 284 + regmap_update_bits(cs35l45->regmap, CS35L45_AMP_GAIN, 285 + CS35L45_AMP_GAIN_PCM_MASK, 286 + CS35L45_AMP_GAIN_PCM_13DBV << 287 + CS35L45_AMP_GAIN_PCM_SHIFT); 288 + 289 + ret = cs35l45_activate_ctl(component, "Analog PCM Volume", false); 290 + if (ret < 0) 291 + dev_err(cs35l45->dev, 292 + "Unable to deactivate ctl (%d)\n", ret); 293 + } 294 + 295 + if (amp_state & CS35L45_AMP_EN_MASK) 296 + regmap_set_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES, 297 + CS35L45_AMP_EN_MASK); 298 + 299 + snd_soc_component_enable_pin_unlocked(component, "SPK"); 300 + snd_soc_dapm_sync_unlocked(dapm); 301 + snd_soc_dapm_mutex_unlock(dapm); 302 + 303 + cs35l45->amplifier_mode = ucontrol->value.integer.value[0]; 304 + 305 + return 1; 306 + } 307 + 172 308 static const char * const cs35l45_asp_tx_txt[] = { 173 309 "Zero", "ASP_RX1", "ASP_RX2", 174 310 "VMON", "IMON", "ERR_VOL", ··· 568 432 { "SPK", NULL, "AMP"}, 569 433 }; 570 434 435 + static const char * const amplifier_mode_texts[] = {"SPK", "RCV"}; 436 + static SOC_ENUM_SINGLE_DECL(amplifier_mode_enum, SND_SOC_NOPM, 0, 437 + amplifier_mode_texts); 438 + static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 1000, 300, 0); 571 439 static const DECLARE_TLV_DB_SCALE(cs35l45_dig_pcm_vol_tlv, -10225, 25, true); 572 440 573 441 static const struct snd_kcontrol_new cs35l45_controls[] = { 442 + SOC_ENUM_EXT("Amplifier Mode", amplifier_mode_enum, 443 + cs35l45_amplifier_mode_get, cs35l45_amplifier_mode_put), 444 + SOC_SINGLE_TLV("Analog PCM Volume", CS35L45_AMP_GAIN, 445 + CS35L45_AMP_GAIN_PCM_SHIFT, 446 + CS35L45_AMP_GAIN_PCM_MASK >> CS35L45_AMP_GAIN_PCM_SHIFT, 447 + 0, amp_gain_tlv), 574 448 /* Ignore bit 0: it is beyond the resolution of TLV_DB_SCALE */ 575 449 SOC_SINGLE_S_TLV("Digital PCM Volume", 576 450 CS35L45_AMP_PCM_CONTROL, ··· 1249 1103 ret = cs35l45_apply_property_config(cs35l45); 1250 1104 if (ret < 0) 1251 1105 return ret; 1106 + 1107 + cs35l45->amplifier_mode = AMP_MODE_SPK; 1252 1108 1253 1109 return 0; 1254 1110 }
+33 -2
sound/soc/codecs/cs35l45.h
··· 61 61 #define CS35L45_DSP1RX6_INPUT 0x00004C54 62 62 #define CS35L45_DSP1RX7_INPUT 0x00004C58 63 63 #define CS35L45_DSP1RX8_INPUT 0x00004C5C 64 + #define CS35L45_HVLV_CONFIG 0x00006400 64 65 #define CS35L45_LDPM_CONFIG 0x00006404 65 66 #define CS35L45_AMP_PCM_CONTROL 0x00007000 66 67 #define CS35L45_AMP_PCM_HPF_TST 0x00007004 68 + #define CS35L45_AMP_GAIN 0x00007800 67 69 #define CS35L45_IRQ1_CFG 0x0000E000 68 70 #define CS35L45_IRQ1_STATUS 0x0000E004 69 71 #define CS35L45_IRQ1_EINT_1 0x0000E010 ··· 169 167 #define CS35L45_VDD_BATTMON_EN_SHIFT 8 170 168 #define CS35L45_BST_EN_SHIFT 4 171 169 #define CS35L45_BST_EN_MASK GENMASK(5, 4) 170 + #define CS35L45_RCV_EN_SHIFT 2 171 + #define CS35L45_RCV_EN_MASK BIT(2) 172 + #define CS35L45_AMP_EN_SHIFT 0 173 + #define CS35L45_AMP_EN_MASK BIT(0) 172 174 173 - #define CS35L45_BST_DISABLE_FET_ON 0x01 175 + #define CS35L45_BST_DISABLE_FET_OFF 0x00 176 + #define CS35L45_BST_DISABLE_FET_ON 0x01 177 + #define CS35L45_BST_ENABLE 0x02 174 178 175 179 /* BLOCK_ENABLES2 */ 176 180 #define CS35L45_ASP_EN_SHIFT 27 177 - 181 + #define CS35L45_AMP_DRE_EN_SHIFT 20 182 + #define CS35L45_AMP_DRE_EN_MASK BIT(20) 178 183 #define CS35L45_MEM_RDY_SHIFT 1 179 184 #define CS35L45_MEM_RDY_MASK BIT(1) 180 185 ··· 275 266 #define CS35L45_ASP_WL_SHIFT 0 276 267 #define CS35L45_ASP_WL_MASK GENMASK(5, 0) 277 268 269 + /* HVLV_CONFIG */ 270 + #define CS35L45_FORCE_LV_OPERATION 0x01 271 + #define CS35L45_FORCE_HV_OPERATION 0x02 272 + #define CS35L45_HVLV_OPERATION 0x03 273 + #define CS35L45_HVLV_MODE_SHIFT 0 274 + #define CS35L45_HVLV_MODE_MASK GENMASK(1, 0) 275 + 278 276 /* AMP_PCM_CONTROL */ 279 277 #define CS35L45_AMP_VOL_PCM_SHIFT 0 280 278 #define CS35L45_AMP_VOL_PCM_WIDTH 11 ··· 290 274 #define CS35l45_HPF_DEFAULT 0x00000000 291 275 #define CS35L45_HPF_44P1 0x000108BD 292 276 #define CS35L45_HPF_88P2 0x0001045F 277 + 278 + /* AMP_GAIN_PCM */ 279 + #define CS35L45_AMP_GAIN_PCM_10DBV 0x00 280 + #define CS35L45_AMP_GAIN_PCM_13DBV 0x01 281 + #define CS35L45_AMP_GAIN_PCM_16DBV 0x02 282 + #define CS35L45_AMP_GAIN_PCM_19DBV 0x03 283 + 284 + #define CS35L45_AMP_GAIN_PCM_SHIFT 8 285 + #define CS35L45_AMP_GAIN_PCM_MASK GENMASK(9, 8) 293 286 294 287 /* IRQ1_EINT_4 */ 295 288 #define CS35L45_OTP_BOOT_DONE_STS_MASK BIT(1) ··· 421 396 CONTROL_BUS_SPI = 1, 422 397 }; 423 398 399 + enum amp_mode { 400 + AMP_MODE_SPK = 0, 401 + AMP_MODE_RCV = 1, 402 + }; 403 + 424 404 #define CS35L45_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 425 405 SNDRV_PCM_FMTBIT_S24_3LE| \ 426 406 SNDRV_PCM_FMTBIT_S24_LE) ··· 494 464 bool sysclk_set; 495 465 u8 slot_width; 496 466 u8 slot_count; 467 + int amplifier_mode; 497 468 int irq_invert; 498 469 int irq; 499 470 unsigned int i2c_addr;