1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. 3 // Copyright (c) 2017-2018, Linaro Limited 4 5 #include <linux/slab.h> 6 #include <sound/soc.h> 7 #include <linux/kernel.h> 8 #include <linux/delay.h> 9 #include "wcd9335.h" 10 #include "wcd-clsh-v2.h" 11 12 struct wcd_clsh_ctrl { 13 int state; 14 int mode; 15 int flyback_users; 16 int buck_users; 17 int clsh_users; 18 int codec_version; 19 struct snd_soc_component *comp; 20 }; 21 22 /* Class-H registers for codecs from and above WCD9335 */ 23 #define WCD9XXX_A_CDC_RX0_RX_PATH_CFG0 WCD9335_REG(0xB, 0x42) 24 #define WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK BIT(6) 25 #define WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE BIT(6) 26 #define WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE 0 27 #define WCD9XXX_A_CDC_RX1_RX_PATH_CFG0 WCD9335_REG(0xB, 0x56) 28 #define WCD9XXX_A_CDC_RX2_RX_PATH_CFG0 WCD9335_REG(0xB, 0x6A) 29 #define WCD9XXX_A_CDC_CLSH_K1_MSB WCD9335_REG(0xC, 0x08) 30 #define WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK GENMASK(3, 0) 31 #define WCD9XXX_A_CDC_CLSH_K1_LSB WCD9335_REG(0xC, 0x09) 32 #define WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK GENMASK(7, 0) 33 #define WCD9XXX_A_ANA_RX_SUPPLIES WCD9335_REG(0x6, 0x08) 34 #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK BIT(1) 35 #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H 0 36 #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB BIT(1) 37 #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK BIT(2) 38 #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA BIT(2) 39 #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT 0 40 #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK BIT(3) 41 #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA BIT(3) 42 #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT 0 43 #define WCD9XXX_A_ANA_RX_VNEG_EN_MASK BIT(6) 44 #define WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT 6 45 #define WCD9XXX_A_ANA_RX_VNEG_ENABLE BIT(6) 46 #define WCD9XXX_A_ANA_RX_VNEG_DISABLE 0 47 #define WCD9XXX_A_ANA_RX_VPOS_EN_MASK BIT(7) 48 #define WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT 7 49 #define WCD9XXX_A_ANA_RX_VPOS_ENABLE BIT(7) 50 #define WCD9XXX_A_ANA_RX_VPOS_DISABLE 0 51 #define WCD9XXX_A_ANA_HPH WCD9335_REG(0x6, 0x09) 52 #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK GENMASK(3, 2) 53 #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA 0x08 54 #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP 0x04 55 #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL 0x0 56 #define WCD9XXX_A_CDC_CLSH_CRC WCD9335_REG(0xC, 0x01) 57 #define WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK BIT(0) 58 #define WCD9XXX_A_CDC_CLSH_CRC_CLK_ENABLE BIT(0) 59 #define WCD9XXX_A_CDC_CLSH_CRC_CLK_DISABLE 0 60 #define WCD9XXX_FLYBACK_EN WCD9335_REG(0x6, 0xA4) 61 #define WCD9XXX_FLYBACK_EN_DELAY_SEL_MASK GENMASK(6, 5) 62 #define WCD9XXX_FLYBACK_EN_DELAY_26P25_US 0x40 63 #define WCD9XXX_FLYBACK_EN_RESET_BY_EXT_MASK BIT(4) 64 #define WCD9XXX_FLYBACK_EN_PWDN_WITHOUT_DELAY BIT(4) 65 #define WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY 0 66 #define WCD9XXX_RX_BIAS_FLYB_BUFF WCD9335_REG(0x6, 0xC7) 67 #define WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4) 68 #define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(3, 0) 69 #define WCD9XXX_HPH_L_EN WCD9335_REG(0x6, 0xD3) 70 #define WCD9XXX_HPH_CONST_SEL_L_MASK GENMASK(7, 3) 71 #define WCD9XXX_HPH_CONST_SEL_BYPASS 0 72 #define WCD9XXX_HPH_CONST_SEL_LP_PATH 0x40 73 #define WCD9XXX_HPH_CONST_SEL_HQ_PATH 0x80 74 #define WCD9XXX_HPH_R_EN WCD9335_REG(0x6, 0xD6) 75 #define WCD9XXX_HPH_REFBUFF_UHQA_CTL WCD9335_REG(0x6, 0xDD) 76 #define WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK GENMASK(2, 0) 77 #define WCD9XXX_CLASSH_CTRL_VCL_2 WCD9335_REG(0x6, 0x9B) 78 #define WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK GENMASK(5, 4) 79 #define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM 0x20 80 #define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM 0x0 81 #define WCD9XXX_CDC_RX1_RX_PATH_CTL WCD9335_REG(0xB, 0x55) 82 #define WCD9XXX_CDC_RX2_RX_PATH_CTL WCD9335_REG(0xB, 0x69) 83 #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL WCD9335_REG(0xD, 0x41) 84 #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_EN_MASK BIT(0) 85 #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_11P3_EN_MASK BIT(1) 86 #define WCD9XXX_CLASSH_CTRL_CCL_1 WCD9335_REG(0x6, 0x9C) 87 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK GENMASK(7, 4) 88 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50 89 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30 90 91 #define WCD9XXX_BASE_ADDRESS 0x3000 92 #define WCD9XXX_ANA_RX_SUPPLIES (WCD9XXX_BASE_ADDRESS+0x008) 93 #define WCD9XXX_ANA_HPH (WCD9XXX_BASE_ADDRESS+0x009) 94 #define WCD9XXX_CLASSH_MODE_2 (WCD9XXX_BASE_ADDRESS+0x098) 95 #define WCD9XXX_CLASSH_MODE_3 (WCD9XXX_BASE_ADDRESS+0x099) 96 #define WCD9XXX_FLYBACK_VNEG_CTRL_1 (WCD9XXX_BASE_ADDRESS+0x0A5) 97 #define WCD9XXX_FLYBACK_VNEG_CTRL_4 (WCD9XXX_BASE_ADDRESS+0x0A8) 98 #define WCD9XXX_FLYBACK_VNEGDAC_CTRL_2 (WCD9XXX_BASE_ADDRESS+0x0AF) 99 #define WCD9XXX_RX_BIAS_HPH_LOWPOWER (WCD9XXX_BASE_ADDRESS+0x0BF) 100 #define WCD9XXX_V3_RX_BIAS_FLYB_BUFF (WCD9XXX_BASE_ADDRESS+0x0C7) 101 #define WCD9XXX_HPH_PA_CTL1 (WCD9XXX_BASE_ADDRESS+0x0D1) 102 #define WCD9XXX_HPH_NEW_INT_PA_MISC2 (WCD9XXX_BASE_ADDRESS+0x138) 103 104 #define CLSH_REQ_ENABLE true 105 #define CLSH_REQ_DISABLE false 106 #define WCD_USLEEP_RANGE 50 107 108 enum { 109 DAC_GAIN_0DB = 0, 110 DAC_GAIN_0P2DB, 111 DAC_GAIN_0P4DB, 112 DAC_GAIN_0P6DB, 113 DAC_GAIN_0P8DB, 114 DAC_GAIN_M0P2DB, 115 DAC_GAIN_M0P4DB, 116 DAC_GAIN_M0P6DB, 117 }; 118 119 static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl, 120 bool enable) 121 { 122 struct snd_soc_component *comp = ctrl->comp; 123 124 if ((enable && ++ctrl->clsh_users == 1) || 125 (!enable && --ctrl->clsh_users == 0)) 126 snd_soc_component_update_bits(comp, WCD9XXX_A_CDC_CLSH_CRC, 127 WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK, 128 enable); 129 if (ctrl->clsh_users < 0) 130 ctrl->clsh_users = 0; 131 } 132 133 static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp, 134 int mode) 135 { 136 /* set to HIFI */ 137 if (mode == CLS_H_HIFI) 138 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 139 WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, 140 WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA); 141 else 142 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 143 WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, 144 WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT); 145 } 146 147 static void wcd_clsh_v3_set_buck_mode(struct snd_soc_component *component, 148 int mode) 149 { 150 if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || 151 mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) 152 snd_soc_component_update_bits(component, 153 WCD9XXX_ANA_RX_SUPPLIES, 154 0x08, 0x08); /* set to HIFI */ 155 else 156 snd_soc_component_update_bits(component, 157 WCD9XXX_ANA_RX_SUPPLIES, 158 0x08, 0x00); /* set to default */ 159 } 160 161 static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp, 162 int mode) 163 { 164 /* set to HIFI */ 165 if (mode == CLS_H_HIFI) 166 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 167 WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, 168 WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA); 169 else 170 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 171 WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, 172 WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT); 173 } 174 175 static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl, 176 int mode, 177 bool enable) 178 { 179 struct snd_soc_component *comp = ctrl->comp; 180 181 /* enable/disable buck */ 182 if ((enable && (++ctrl->buck_users == 1)) || 183 (!enable && (--ctrl->buck_users == 0))) 184 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 185 WCD9XXX_A_ANA_RX_VPOS_EN_MASK, 186 enable << WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT); 187 /* 188 * 500us sleep is required after buck enable/disable 189 * as per HW requirement 190 */ 191 usleep_range(500, 500 + WCD_USLEEP_RANGE); 192 } 193 194 static void wcd_clsh_v3_buck_ctrl(struct snd_soc_component *component, 195 struct wcd_clsh_ctrl *ctrl, 196 int mode, 197 bool enable) 198 { 199 /* enable/disable buck */ 200 if ((enable && (++ctrl->buck_users == 1)) || 201 (!enable && (--ctrl->buck_users == 0))) { 202 snd_soc_component_update_bits(component, 203 WCD9XXX_ANA_RX_SUPPLIES, 204 (1 << 7), (enable << 7)); 205 /* 206 * 500us sleep is required after buck enable/disable 207 * as per HW requirement 208 */ 209 usleep_range(500, 510); 210 if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP || 211 mode == CLS_H_HIFI || mode == CLS_H_LP) 212 snd_soc_component_update_bits(component, 213 WCD9XXX_CLASSH_MODE_3, 214 0x02, 0x00); 215 216 snd_soc_component_update_bits(component, 217 WCD9XXX_CLASSH_MODE_2, 218 0xFF, 0x3A); 219 /* 500usec delay is needed as per HW requirement */ 220 usleep_range(500, 500 + WCD_USLEEP_RANGE); 221 } 222 } 223 224 static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl, 225 int mode, 226 bool enable) 227 { 228 struct snd_soc_component *comp = ctrl->comp; 229 230 /* enable/disable flyback */ 231 if ((enable && (++ctrl->flyback_users == 1)) || 232 (!enable && (--ctrl->flyback_users == 0))) { 233 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 234 WCD9XXX_A_ANA_RX_VNEG_EN_MASK, 235 enable << WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT); 236 /* 100usec delay is needed as per HW requirement */ 237 usleep_range(100, 110); 238 } 239 /* 240 * 500us sleep is required after flyback enable/disable 241 * as per HW requirement 242 */ 243 usleep_range(500, 500 + WCD_USLEEP_RANGE); 244 } 245 246 static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode) 247 { 248 struct snd_soc_component *comp = ctrl->comp; 249 int val = 0; 250 251 switch (mode) { 252 case CLS_H_NORMAL: 253 case CLS_AB: 254 val = WCD9XXX_HPH_CONST_SEL_BYPASS; 255 break; 256 case CLS_H_HIFI: 257 val = WCD9XXX_HPH_CONST_SEL_HQ_PATH; 258 break; 259 case CLS_H_LP: 260 val = WCD9XXX_HPH_CONST_SEL_LP_PATH; 261 break; 262 } 263 264 snd_soc_component_update_bits(comp, WCD9XXX_HPH_L_EN, 265 WCD9XXX_HPH_CONST_SEL_L_MASK, 266 val); 267 268 snd_soc_component_update_bits(comp, WCD9XXX_HPH_R_EN, 269 WCD9XXX_HPH_CONST_SEL_L_MASK, 270 val); 271 } 272 273 static void wcd_clsh_v2_set_hph_mode(struct snd_soc_component *comp, int mode) 274 { 275 int val = 0, gain = 0, res_val; 276 int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; 277 278 res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM; 279 switch (mode) { 280 case CLS_H_NORMAL: 281 res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM; 282 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; 283 gain = DAC_GAIN_0DB; 284 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; 285 break; 286 case CLS_AB: 287 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; 288 gain = DAC_GAIN_0DB; 289 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; 290 break; 291 case CLS_H_HIFI: 292 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA; 293 gain = DAC_GAIN_M0P2DB; 294 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; 295 break; 296 case CLS_H_LP: 297 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP; 298 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA; 299 break; 300 } 301 302 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_HPH, 303 WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val); 304 snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_VCL_2, 305 WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK, 306 res_val); 307 if (mode != CLS_H_LP) 308 snd_soc_component_update_bits(comp, 309 WCD9XXX_HPH_REFBUFF_UHQA_CTL, 310 WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK, 311 gain); 312 snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_CCL_1, 313 WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK, 314 ipeak); 315 } 316 317 static void wcd_clsh_v3_set_hph_mode(struct snd_soc_component *component, 318 int mode) 319 { 320 u8 val; 321 322 switch (mode) { 323 case CLS_H_NORMAL: 324 val = 0x00; 325 break; 326 case CLS_AB: 327 case CLS_H_ULP: 328 val = 0x0C; 329 break; 330 case CLS_AB_HIFI: 331 case CLS_H_HIFI: 332 val = 0x08; 333 break; 334 case CLS_H_LP: 335 case CLS_H_LOHIFI: 336 case CLS_AB_LP: 337 case CLS_AB_LOHIFI: 338 val = 0x04; 339 break; 340 default: 341 dev_err(component->dev, "%s:Invalid mode %d\n", __func__, mode); 342 return; 343 } 344 345 snd_soc_component_update_bits(component, WCD9XXX_ANA_HPH, 0x0C, val); 346 } 347 348 void wcd_clsh_set_hph_mode(struct wcd_clsh_ctrl *ctrl, int mode) 349 { 350 struct snd_soc_component *comp = ctrl->comp; 351 352 if (ctrl->codec_version >= WCD937X) 353 wcd_clsh_v3_set_hph_mode(comp, mode); 354 else 355 wcd_clsh_v2_set_hph_mode(comp, mode); 356 357 } 358 359 static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp, 360 int mode) 361 { 362 363 snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, 364 WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, 0x0A); 365 snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, 366 WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, 0x0A); 367 /* Sleep needed to avoid click and pop as per HW requirement */ 368 usleep_range(100, 110); 369 } 370 371 static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp, 372 int mode) 373 { 374 if (mode == CLS_AB) 375 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 376 WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, 377 WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB); 378 else 379 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 380 WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, 381 WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H); 382 } 383 384 static void wcd_clsh_v3_set_buck_regulator_mode(struct snd_soc_component *component, 385 int mode) 386 { 387 snd_soc_component_update_bits(component, WCD9XXX_ANA_RX_SUPPLIES, 388 0x02, 0x00); 389 } 390 391 static void wcd_clsh_v3_set_flyback_mode(struct snd_soc_component *component, 392 int mode) 393 { 394 if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || 395 mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) { 396 snd_soc_component_update_bits(component, 397 WCD9XXX_ANA_RX_SUPPLIES, 398 0x04, 0x04); 399 snd_soc_component_update_bits(component, 400 WCD9XXX_FLYBACK_VNEG_CTRL_4, 401 0xF0, 0x80); 402 } else { 403 snd_soc_component_update_bits(component, 404 WCD9XXX_ANA_RX_SUPPLIES, 405 0x04, 0x00); /* set to Default */ 406 snd_soc_component_update_bits(component, 407 WCD9XXX_FLYBACK_VNEG_CTRL_4, 408 0xF0, 0x70); 409 } 410 } 411 412 static void wcd_clsh_v3_force_iq_ctl(struct snd_soc_component *component, 413 int mode, bool enable) 414 { 415 if (enable) { 416 snd_soc_component_update_bits(component, 417 WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, 418 0xE0, 0xA0); 419 /* 100usec delay is needed as per HW requirement */ 420 usleep_range(100, 110); 421 snd_soc_component_update_bits(component, 422 WCD9XXX_CLASSH_MODE_3, 423 0x02, 0x02); 424 snd_soc_component_update_bits(component, 425 WCD9XXX_CLASSH_MODE_2, 426 0xFF, 0x1C); 427 if (mode == CLS_H_LOHIFI || mode == CLS_AB_LOHIFI) { 428 snd_soc_component_update_bits(component, 429 WCD9XXX_HPH_NEW_INT_PA_MISC2, 430 0x20, 0x20); 431 snd_soc_component_update_bits(component, 432 WCD9XXX_RX_BIAS_HPH_LOWPOWER, 433 0xF0, 0xC0); 434 snd_soc_component_update_bits(component, 435 WCD9XXX_HPH_PA_CTL1, 436 0x0E, 0x02); 437 } 438 } else { 439 snd_soc_component_update_bits(component, 440 WCD9XXX_HPH_NEW_INT_PA_MISC2, 441 0x20, 0x00); 442 snd_soc_component_update_bits(component, 443 WCD9XXX_RX_BIAS_HPH_LOWPOWER, 444 0xF0, 0x80); 445 snd_soc_component_update_bits(component, 446 WCD9XXX_HPH_PA_CTL1, 447 0x0E, 0x06); 448 } 449 } 450 451 static void wcd_clsh_v3_flyback_ctrl(struct snd_soc_component *component, 452 struct wcd_clsh_ctrl *ctrl, 453 int mode, 454 bool enable) 455 { 456 /* enable/disable flyback */ 457 if ((enable && (++ctrl->flyback_users == 1)) || 458 (!enable && (--ctrl->flyback_users == 0))) { 459 snd_soc_component_update_bits(component, 460 WCD9XXX_FLYBACK_VNEG_CTRL_1, 461 0xE0, 0xE0); 462 snd_soc_component_update_bits(component, 463 WCD9XXX_ANA_RX_SUPPLIES, 464 (1 << 6), (enable << 6)); 465 /* 466 * 100us sleep is required after flyback enable/disable 467 * as per HW requirement 468 */ 469 usleep_range(100, 110); 470 snd_soc_component_update_bits(component, 471 WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, 472 0xE0, 0xE0); 473 /* 500usec delay is needed as per HW requirement */ 474 usleep_range(500, 500 + WCD_USLEEP_RANGE); 475 } 476 } 477 478 static void wcd_clsh_v3_set_flyback_current(struct snd_soc_component *component, 479 int mode) 480 { 481 snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF, 482 0x0F, 0x0A); 483 snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF, 484 0xF0, 0xA0); 485 /* Sleep needed to avoid click and pop as per HW requirement */ 486 usleep_range(100, 110); 487 } 488 489 static void wcd_clsh_v3_state_aux(struct wcd_clsh_ctrl *ctrl, int req_state, 490 bool is_enable, int mode) 491 { 492 struct snd_soc_component *component = ctrl->comp; 493 494 if (is_enable) { 495 wcd_clsh_v3_set_buck_mode(component, mode); 496 wcd_clsh_v3_set_flyback_mode(component, mode); 497 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); 498 wcd_clsh_v3_set_flyback_current(component, mode); 499 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); 500 } else { 501 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, false); 502 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, false); 503 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); 504 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); 505 } 506 } 507 508 static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state, 509 bool is_enable, int mode) 510 { 511 struct snd_soc_component *comp = ctrl->comp; 512 513 if (mode != CLS_AB) { 514 dev_err(comp->dev, "%s: LO cannot be in this mode: %d\n", 515 __func__, mode); 516 return; 517 } 518 519 if (is_enable) { 520 wcd_clsh_set_buck_regulator_mode(comp, mode); 521 wcd_clsh_set_buck_mode(comp, mode); 522 wcd_clsh_set_flyback_mode(comp, mode); 523 wcd_clsh_flyback_ctrl(ctrl, mode, true); 524 wcd_clsh_set_flyback_current(comp, mode); 525 wcd_clsh_buck_ctrl(ctrl, mode, true); 526 } else { 527 wcd_clsh_buck_ctrl(ctrl, mode, false); 528 wcd_clsh_flyback_ctrl(ctrl, mode, false); 529 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 530 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 531 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); 532 } 533 } 534 535 static void wcd_clsh_v3_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, 536 bool is_enable, int mode) 537 { 538 struct snd_soc_component *component = ctrl->comp; 539 540 if (mode == CLS_H_NORMAL) { 541 dev_dbg(component->dev, "%s: Normal mode not applicable for hph_r\n", 542 __func__); 543 return; 544 } 545 546 if (is_enable) { 547 wcd_clsh_v3_set_buck_regulator_mode(component, mode); 548 wcd_clsh_v3_set_flyback_mode(component, mode); 549 wcd_clsh_v3_force_iq_ctl(component, mode, true); 550 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); 551 wcd_clsh_v3_set_flyback_current(component, mode); 552 wcd_clsh_v3_set_buck_mode(component, mode); 553 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); 554 wcd_clsh_v3_set_hph_mode(component, mode); 555 } else { 556 wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); 557 558 /* buck and flyback set to default mode and disable */ 559 wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); 560 wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); 561 wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); 562 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); 563 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); 564 } 565 } 566 567 static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, 568 bool is_enable, int mode) 569 { 570 struct snd_soc_component *comp = ctrl->comp; 571 572 if (mode == CLS_H_NORMAL) { 573 dev_err(comp->dev, "%s: Normal mode not applicable for hph_r\n", 574 __func__); 575 return; 576 } 577 578 if (is_enable) { 579 if (mode != CLS_AB) { 580 wcd_enable_clsh_block(ctrl, true); 581 /* 582 * These K1 values depend on the Headphone Impedance 583 * For now it is assumed to be 16 ohm 584 */ 585 snd_soc_component_update_bits(comp, 586 WCD9XXX_A_CDC_CLSH_K1_MSB, 587 WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, 588 0x00); 589 snd_soc_component_update_bits(comp, 590 WCD9XXX_A_CDC_CLSH_K1_LSB, 591 WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, 592 0xC0); 593 snd_soc_component_update_bits(comp, 594 WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, 595 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 596 WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); 597 } 598 wcd_clsh_set_buck_regulator_mode(comp, mode); 599 wcd_clsh_set_flyback_mode(comp, mode); 600 wcd_clsh_flyback_ctrl(ctrl, mode, true); 601 wcd_clsh_set_flyback_current(comp, mode); 602 wcd_clsh_set_buck_mode(comp, mode); 603 wcd_clsh_buck_ctrl(ctrl, mode, true); 604 wcd_clsh_v2_set_hph_mode(comp, mode); 605 wcd_clsh_set_gain_path(ctrl, mode); 606 } else { 607 wcd_clsh_v2_set_hph_mode(comp, CLS_H_NORMAL); 608 609 if (mode != CLS_AB) { 610 snd_soc_component_update_bits(comp, 611 WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, 612 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 613 WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); 614 wcd_enable_clsh_block(ctrl, false); 615 } 616 /* buck and flyback set to default mode and disable */ 617 wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); 618 wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); 619 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 620 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 621 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); 622 } 623 } 624 625 static void wcd_clsh_v3_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, 626 bool is_enable, int mode) 627 { 628 struct snd_soc_component *component = ctrl->comp; 629 630 if (mode == CLS_H_NORMAL) { 631 dev_dbg(component->dev, "%s: Normal mode not applicable for hph_l\n", 632 __func__); 633 return; 634 } 635 636 if (is_enable) { 637 wcd_clsh_v3_set_buck_regulator_mode(component, mode); 638 wcd_clsh_v3_set_flyback_mode(component, mode); 639 wcd_clsh_v3_force_iq_ctl(component, mode, true); 640 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); 641 wcd_clsh_v3_set_flyback_current(component, mode); 642 wcd_clsh_v3_set_buck_mode(component, mode); 643 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); 644 wcd_clsh_v3_set_hph_mode(component, mode); 645 } else { 646 wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); 647 648 /* set buck and flyback to Default Mode */ 649 wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); 650 wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); 651 wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); 652 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); 653 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); 654 } 655 } 656 657 static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, 658 bool is_enable, int mode) 659 { 660 struct snd_soc_component *comp = ctrl->comp; 661 662 if (mode == CLS_H_NORMAL) { 663 dev_err(comp->dev, "%s: Normal mode not applicable for hph_l\n", 664 __func__); 665 return; 666 } 667 668 if (is_enable) { 669 if (mode != CLS_AB) { 670 wcd_enable_clsh_block(ctrl, true); 671 /* 672 * These K1 values depend on the Headphone Impedance 673 * For now it is assumed to be 16 ohm 674 */ 675 snd_soc_component_update_bits(comp, 676 WCD9XXX_A_CDC_CLSH_K1_MSB, 677 WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, 678 0x00); 679 snd_soc_component_update_bits(comp, 680 WCD9XXX_A_CDC_CLSH_K1_LSB, 681 WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, 682 0xC0); 683 snd_soc_component_update_bits(comp, 684 WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, 685 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 686 WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); 687 } 688 wcd_clsh_set_buck_regulator_mode(comp, mode); 689 wcd_clsh_set_flyback_mode(comp, mode); 690 wcd_clsh_flyback_ctrl(ctrl, mode, true); 691 wcd_clsh_set_flyback_current(comp, mode); 692 wcd_clsh_set_buck_mode(comp, mode); 693 wcd_clsh_buck_ctrl(ctrl, mode, true); 694 wcd_clsh_v2_set_hph_mode(comp, mode); 695 wcd_clsh_set_gain_path(ctrl, mode); 696 } else { 697 wcd_clsh_v2_set_hph_mode(comp, CLS_H_NORMAL); 698 699 if (mode != CLS_AB) { 700 snd_soc_component_update_bits(comp, 701 WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, 702 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 703 WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); 704 wcd_enable_clsh_block(ctrl, false); 705 } 706 /* set buck and flyback to Default Mode */ 707 wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); 708 wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); 709 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 710 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 711 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); 712 } 713 } 714 715 static void wcd_clsh_v3_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, 716 bool is_enable, int mode) 717 { 718 struct snd_soc_component *component = ctrl->comp; 719 720 if (is_enable) { 721 wcd_clsh_v3_set_buck_regulator_mode(component, mode); 722 wcd_clsh_v3_set_flyback_mode(component, mode); 723 wcd_clsh_v3_force_iq_ctl(component, mode, true); 724 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); 725 wcd_clsh_v3_set_flyback_current(component, mode); 726 wcd_clsh_v3_set_buck_mode(component, mode); 727 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); 728 wcd_clsh_v3_set_hph_mode(component, mode); 729 } else { 730 wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); 731 732 /* set buck and flyback to Default Mode */ 733 wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); 734 wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); 735 wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); 736 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); 737 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); 738 } 739 } 740 741 static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, 742 bool is_enable, int mode) 743 { 744 struct snd_soc_component *comp = ctrl->comp; 745 746 if (mode != CLS_H_NORMAL) { 747 dev_err(comp->dev, "%s: mode: %d cannot be used for EAR\n", 748 __func__, mode); 749 return; 750 } 751 752 if (is_enable) { 753 wcd_enable_clsh_block(ctrl, true); 754 snd_soc_component_update_bits(comp, 755 WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, 756 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 757 WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); 758 wcd_clsh_set_buck_mode(comp, mode); 759 wcd_clsh_set_flyback_mode(comp, mode); 760 wcd_clsh_flyback_ctrl(ctrl, mode, true); 761 wcd_clsh_set_flyback_current(comp, mode); 762 wcd_clsh_buck_ctrl(ctrl, mode, true); 763 } else { 764 snd_soc_component_update_bits(comp, 765 WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, 766 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 767 WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); 768 wcd_enable_clsh_block(ctrl, false); 769 wcd_clsh_buck_ctrl(ctrl, mode, false); 770 wcd_clsh_flyback_ctrl(ctrl, mode, false); 771 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 772 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 773 } 774 } 775 776 static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state, 777 bool is_enable, int mode) 778 { 779 switch (req_state) { 780 case WCD_CLSH_STATE_EAR: 781 if (ctrl->codec_version >= WCD937X) 782 wcd_clsh_v3_state_ear(ctrl, req_state, is_enable, mode); 783 else 784 wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); 785 break; 786 case WCD_CLSH_STATE_HPHL: 787 if (ctrl->codec_version >= WCD937X) 788 wcd_clsh_v3_state_hph_l(ctrl, req_state, is_enable, mode); 789 else 790 wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode); 791 break; 792 case WCD_CLSH_STATE_HPHR: 793 if (ctrl->codec_version >= WCD937X) 794 wcd_clsh_v3_state_hph_r(ctrl, req_state, is_enable, mode); 795 else 796 wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); 797 break; 798 case WCD_CLSH_STATE_LO: 799 if (ctrl->codec_version < WCD937X) 800 wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); 801 break; 802 case WCD_CLSH_STATE_AUX: 803 if (ctrl->codec_version >= WCD937X) 804 wcd_clsh_v3_state_aux(ctrl, req_state, is_enable, mode); 805 break; 806 default: 807 break; 808 } 809 810 return 0; 811 } 812 813 /* 814 * Function: wcd_clsh_is_state_valid 815 * Params: state 816 * Description: 817 * Provides information on valid states of Class H configuration 818 */ 819 static bool wcd_clsh_is_state_valid(int state) 820 { 821 switch (state) { 822 case WCD_CLSH_STATE_IDLE: 823 case WCD_CLSH_STATE_EAR: 824 case WCD_CLSH_STATE_HPHL: 825 case WCD_CLSH_STATE_HPHR: 826 case WCD_CLSH_STATE_LO: 827 case WCD_CLSH_STATE_AUX: 828 return true; 829 default: 830 return false; 831 }; 832 } 833 834 /* 835 * Function: wcd_clsh_fsm 836 * Params: ctrl, req_state, req_type, clsh_event 837 * Description: 838 * This function handles PRE DAC and POST DAC conditions of different devices 839 * and updates class H configuration of different combination of devices 840 * based on validity of their states. ctrl will contain current 841 * class h state information 842 */ 843 int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, 844 enum wcd_clsh_event clsh_event, 845 int nstate, 846 enum wcd_clsh_mode mode) 847 { 848 struct snd_soc_component *comp = ctrl->comp; 849 850 if (nstate == ctrl->state) 851 return 0; 852 853 if (!wcd_clsh_is_state_valid(nstate)) { 854 dev_err(comp->dev, "Class-H not a valid new state:\n"); 855 return -EINVAL; 856 } 857 858 switch (clsh_event) { 859 case WCD_CLSH_EVENT_PRE_DAC: 860 _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_ENABLE, mode); 861 break; 862 case WCD_CLSH_EVENT_POST_PA: 863 _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode); 864 break; 865 } 866 867 ctrl->state = nstate; 868 ctrl->mode = mode; 869 870 return 0; 871 } 872 873 int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl) 874 { 875 return ctrl->state; 876 } 877 878 struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp, 879 int version) 880 { 881 struct wcd_clsh_ctrl *ctrl; 882 883 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); 884 if (!ctrl) 885 return ERR_PTR(-ENOMEM); 886 887 ctrl->state = WCD_CLSH_STATE_IDLE; 888 ctrl->comp = comp; 889 ctrl->codec_version = version; 890 891 return ctrl; 892 } 893 894 void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl) 895 { 896 kfree(ctrl); 897 } 898