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 EXPORT_SYMBOL_GPL(wcd_clsh_set_hph_mode); 359 360 static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp, 361 int mode) 362 { 363 364 snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, 365 WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, 0x0A); 366 snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, 367 WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, 0x0A); 368 /* Sleep needed to avoid click and pop as per HW requirement */ 369 usleep_range(100, 110); 370 } 371 372 static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp, 373 int mode) 374 { 375 if (mode == CLS_AB) 376 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 377 WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, 378 WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB); 379 else 380 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 381 WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, 382 WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H); 383 } 384 385 static void wcd_clsh_v3_set_buck_regulator_mode(struct snd_soc_component *component, 386 int mode) 387 { 388 snd_soc_component_update_bits(component, WCD9XXX_ANA_RX_SUPPLIES, 389 0x02, 0x00); 390 } 391 392 static void wcd_clsh_v3_set_flyback_mode(struct snd_soc_component *component, 393 int mode) 394 { 395 if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || 396 mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) { 397 snd_soc_component_update_bits(component, 398 WCD9XXX_ANA_RX_SUPPLIES, 399 0x04, 0x04); 400 snd_soc_component_update_bits(component, 401 WCD9XXX_FLYBACK_VNEG_CTRL_4, 402 0xF0, 0x80); 403 } else { 404 snd_soc_component_update_bits(component, 405 WCD9XXX_ANA_RX_SUPPLIES, 406 0x04, 0x00); /* set to Default */ 407 snd_soc_component_update_bits(component, 408 WCD9XXX_FLYBACK_VNEG_CTRL_4, 409 0xF0, 0x70); 410 } 411 } 412 413 static void wcd_clsh_v3_force_iq_ctl(struct snd_soc_component *component, 414 int mode, bool enable) 415 { 416 if (enable) { 417 snd_soc_component_update_bits(component, 418 WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, 419 0xE0, 0xA0); 420 /* 100usec delay is needed as per HW requirement */ 421 usleep_range(100, 110); 422 snd_soc_component_update_bits(component, 423 WCD9XXX_CLASSH_MODE_3, 424 0x02, 0x02); 425 snd_soc_component_update_bits(component, 426 WCD9XXX_CLASSH_MODE_2, 427 0xFF, 0x1C); 428 if (mode == CLS_H_LOHIFI || mode == CLS_AB_LOHIFI) { 429 snd_soc_component_update_bits(component, 430 WCD9XXX_HPH_NEW_INT_PA_MISC2, 431 0x20, 0x20); 432 snd_soc_component_update_bits(component, 433 WCD9XXX_RX_BIAS_HPH_LOWPOWER, 434 0xF0, 0xC0); 435 snd_soc_component_update_bits(component, 436 WCD9XXX_HPH_PA_CTL1, 437 0x0E, 0x02); 438 } 439 } else { 440 snd_soc_component_update_bits(component, 441 WCD9XXX_HPH_NEW_INT_PA_MISC2, 442 0x20, 0x00); 443 snd_soc_component_update_bits(component, 444 WCD9XXX_RX_BIAS_HPH_LOWPOWER, 445 0xF0, 0x80); 446 snd_soc_component_update_bits(component, 447 WCD9XXX_HPH_PA_CTL1, 448 0x0E, 0x06); 449 } 450 } 451 452 static void wcd_clsh_v3_flyback_ctrl(struct snd_soc_component *component, 453 struct wcd_clsh_ctrl *ctrl, 454 int mode, 455 bool enable) 456 { 457 /* enable/disable flyback */ 458 if ((enable && (++ctrl->flyback_users == 1)) || 459 (!enable && (--ctrl->flyback_users == 0))) { 460 snd_soc_component_update_bits(component, 461 WCD9XXX_FLYBACK_VNEG_CTRL_1, 462 0xE0, 0xE0); 463 snd_soc_component_update_bits(component, 464 WCD9XXX_ANA_RX_SUPPLIES, 465 (1 << 6), (enable << 6)); 466 /* 467 * 100us sleep is required after flyback enable/disable 468 * as per HW requirement 469 */ 470 usleep_range(100, 110); 471 snd_soc_component_update_bits(component, 472 WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, 473 0xE0, 0xE0); 474 /* 500usec delay is needed as per HW requirement */ 475 usleep_range(500, 500 + WCD_USLEEP_RANGE); 476 } 477 } 478 479 static void wcd_clsh_v3_set_flyback_current(struct snd_soc_component *component, 480 int mode) 481 { 482 snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF, 483 0x0F, 0x0A); 484 snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF, 485 0xF0, 0xA0); 486 /* Sleep needed to avoid click and pop as per HW requirement */ 487 usleep_range(100, 110); 488 } 489 490 static void wcd_clsh_v3_state_aux(struct wcd_clsh_ctrl *ctrl, int req_state, 491 bool is_enable, int mode) 492 { 493 struct snd_soc_component *component = ctrl->comp; 494 495 if (is_enable) { 496 wcd_clsh_v3_set_buck_mode(component, mode); 497 wcd_clsh_v3_set_flyback_mode(component, mode); 498 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); 499 wcd_clsh_v3_set_flyback_current(component, mode); 500 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); 501 } else { 502 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, false); 503 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, false); 504 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); 505 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); 506 } 507 } 508 509 static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state, 510 bool is_enable, int mode) 511 { 512 struct snd_soc_component *comp = ctrl->comp; 513 514 if (mode != CLS_AB) { 515 dev_err(comp->dev, "%s: LO cannot be in this mode: %d\n", 516 __func__, mode); 517 return; 518 } 519 520 if (is_enable) { 521 wcd_clsh_set_buck_regulator_mode(comp, mode); 522 wcd_clsh_set_buck_mode(comp, mode); 523 wcd_clsh_set_flyback_mode(comp, mode); 524 wcd_clsh_flyback_ctrl(ctrl, mode, true); 525 wcd_clsh_set_flyback_current(comp, mode); 526 wcd_clsh_buck_ctrl(ctrl, mode, true); 527 } else { 528 wcd_clsh_buck_ctrl(ctrl, mode, false); 529 wcd_clsh_flyback_ctrl(ctrl, mode, false); 530 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 531 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 532 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); 533 } 534 } 535 536 static void wcd_clsh_v3_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, 537 bool is_enable, int mode) 538 { 539 struct snd_soc_component *component = ctrl->comp; 540 541 if (mode == CLS_H_NORMAL) { 542 dev_dbg(component->dev, "%s: Normal mode not applicable for hph_r\n", 543 __func__); 544 return; 545 } 546 547 if (is_enable) { 548 wcd_clsh_v3_set_buck_regulator_mode(component, mode); 549 wcd_clsh_v3_set_flyback_mode(component, mode); 550 wcd_clsh_v3_force_iq_ctl(component, mode, true); 551 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); 552 wcd_clsh_v3_set_flyback_current(component, mode); 553 wcd_clsh_v3_set_buck_mode(component, mode); 554 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); 555 wcd_clsh_v3_set_hph_mode(component, mode); 556 } else { 557 wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); 558 559 /* buck and flyback set to default mode and disable */ 560 wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); 561 wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); 562 wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); 563 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); 564 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); 565 } 566 } 567 568 static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, 569 bool is_enable, int mode) 570 { 571 struct snd_soc_component *comp = ctrl->comp; 572 573 if (mode == CLS_H_NORMAL) { 574 dev_err(comp->dev, "%s: Normal mode not applicable for hph_r\n", 575 __func__); 576 return; 577 } 578 579 if (is_enable) { 580 if (mode != CLS_AB) { 581 wcd_enable_clsh_block(ctrl, true); 582 /* 583 * These K1 values depend on the Headphone Impedance 584 * For now it is assumed to be 16 ohm 585 */ 586 snd_soc_component_update_bits(comp, 587 WCD9XXX_A_CDC_CLSH_K1_MSB, 588 WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, 589 0x00); 590 snd_soc_component_update_bits(comp, 591 WCD9XXX_A_CDC_CLSH_K1_LSB, 592 WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, 593 0xC0); 594 snd_soc_component_update_bits(comp, 595 WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, 596 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 597 WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); 598 } 599 wcd_clsh_set_buck_regulator_mode(comp, mode); 600 wcd_clsh_set_flyback_mode(comp, mode); 601 wcd_clsh_flyback_ctrl(ctrl, mode, true); 602 wcd_clsh_set_flyback_current(comp, mode); 603 wcd_clsh_set_buck_mode(comp, mode); 604 wcd_clsh_buck_ctrl(ctrl, mode, true); 605 wcd_clsh_v2_set_hph_mode(comp, mode); 606 wcd_clsh_set_gain_path(ctrl, mode); 607 } else { 608 wcd_clsh_v2_set_hph_mode(comp, CLS_H_NORMAL); 609 610 if (mode != CLS_AB) { 611 snd_soc_component_update_bits(comp, 612 WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, 613 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 614 WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); 615 wcd_enable_clsh_block(ctrl, false); 616 } 617 /* buck and flyback set to default mode and disable */ 618 wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); 619 wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); 620 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 621 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 622 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); 623 } 624 } 625 626 static void wcd_clsh_v3_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, 627 bool is_enable, int mode) 628 { 629 struct snd_soc_component *component = ctrl->comp; 630 631 if (mode == CLS_H_NORMAL) { 632 dev_dbg(component->dev, "%s: Normal mode not applicable for hph_l\n", 633 __func__); 634 return; 635 } 636 637 if (is_enable) { 638 wcd_clsh_v3_set_buck_regulator_mode(component, mode); 639 wcd_clsh_v3_set_flyback_mode(component, mode); 640 wcd_clsh_v3_force_iq_ctl(component, mode, true); 641 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); 642 wcd_clsh_v3_set_flyback_current(component, mode); 643 wcd_clsh_v3_set_buck_mode(component, mode); 644 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); 645 wcd_clsh_v3_set_hph_mode(component, mode); 646 } else { 647 wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); 648 649 /* set buck and flyback to Default Mode */ 650 wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); 651 wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); 652 wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); 653 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); 654 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); 655 } 656 } 657 658 static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, 659 bool is_enable, int mode) 660 { 661 struct snd_soc_component *comp = ctrl->comp; 662 663 if (mode == CLS_H_NORMAL) { 664 dev_err(comp->dev, "%s: Normal mode not applicable for hph_l\n", 665 __func__); 666 return; 667 } 668 669 if (is_enable) { 670 if (mode != CLS_AB) { 671 wcd_enable_clsh_block(ctrl, true); 672 /* 673 * These K1 values depend on the Headphone Impedance 674 * For now it is assumed to be 16 ohm 675 */ 676 snd_soc_component_update_bits(comp, 677 WCD9XXX_A_CDC_CLSH_K1_MSB, 678 WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, 679 0x00); 680 snd_soc_component_update_bits(comp, 681 WCD9XXX_A_CDC_CLSH_K1_LSB, 682 WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, 683 0xC0); 684 snd_soc_component_update_bits(comp, 685 WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, 686 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 687 WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); 688 } 689 wcd_clsh_set_buck_regulator_mode(comp, mode); 690 wcd_clsh_set_flyback_mode(comp, mode); 691 wcd_clsh_flyback_ctrl(ctrl, mode, true); 692 wcd_clsh_set_flyback_current(comp, mode); 693 wcd_clsh_set_buck_mode(comp, mode); 694 wcd_clsh_buck_ctrl(ctrl, mode, true); 695 wcd_clsh_v2_set_hph_mode(comp, mode); 696 wcd_clsh_set_gain_path(ctrl, mode); 697 } else { 698 wcd_clsh_v2_set_hph_mode(comp, CLS_H_NORMAL); 699 700 if (mode != CLS_AB) { 701 snd_soc_component_update_bits(comp, 702 WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, 703 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 704 WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); 705 wcd_enable_clsh_block(ctrl, false); 706 } 707 /* set buck and flyback to Default Mode */ 708 wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); 709 wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); 710 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 711 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 712 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); 713 } 714 } 715 716 static void wcd_clsh_v3_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, 717 bool is_enable, int mode) 718 { 719 struct snd_soc_component *component = ctrl->comp; 720 721 if (is_enable) { 722 wcd_clsh_v3_set_buck_regulator_mode(component, mode); 723 wcd_clsh_v3_set_flyback_mode(component, mode); 724 wcd_clsh_v3_force_iq_ctl(component, mode, true); 725 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); 726 wcd_clsh_v3_set_flyback_current(component, mode); 727 wcd_clsh_v3_set_buck_mode(component, mode); 728 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); 729 wcd_clsh_v3_set_hph_mode(component, mode); 730 } else { 731 wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); 732 733 /* set buck and flyback to Default Mode */ 734 wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); 735 wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); 736 wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); 737 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); 738 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); 739 } 740 } 741 742 static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, 743 bool is_enable, int mode) 744 { 745 struct snd_soc_component *comp = ctrl->comp; 746 747 if (mode != CLS_H_NORMAL) { 748 dev_err(comp->dev, "%s: mode: %d cannot be used for EAR\n", 749 __func__, mode); 750 return; 751 } 752 753 if (is_enable) { 754 wcd_enable_clsh_block(ctrl, true); 755 snd_soc_component_update_bits(comp, 756 WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, 757 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 758 WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); 759 wcd_clsh_set_buck_mode(comp, mode); 760 wcd_clsh_set_flyback_mode(comp, mode); 761 wcd_clsh_flyback_ctrl(ctrl, mode, true); 762 wcd_clsh_set_flyback_current(comp, mode); 763 wcd_clsh_buck_ctrl(ctrl, mode, true); 764 } else { 765 snd_soc_component_update_bits(comp, 766 WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, 767 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 768 WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); 769 wcd_enable_clsh_block(ctrl, false); 770 wcd_clsh_buck_ctrl(ctrl, mode, false); 771 wcd_clsh_flyback_ctrl(ctrl, mode, false); 772 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 773 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 774 } 775 } 776 777 static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state, 778 bool is_enable, int mode) 779 { 780 switch (req_state) { 781 case WCD_CLSH_STATE_EAR: 782 if (ctrl->codec_version >= WCD937X) 783 wcd_clsh_v3_state_ear(ctrl, req_state, is_enable, mode); 784 else 785 wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); 786 break; 787 case WCD_CLSH_STATE_HPHL: 788 if (ctrl->codec_version >= WCD937X) 789 wcd_clsh_v3_state_hph_l(ctrl, req_state, is_enable, mode); 790 else 791 wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode); 792 break; 793 case WCD_CLSH_STATE_HPHR: 794 if (ctrl->codec_version >= WCD937X) 795 wcd_clsh_v3_state_hph_r(ctrl, req_state, is_enable, mode); 796 else 797 wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); 798 break; 799 case WCD_CLSH_STATE_LO: 800 if (ctrl->codec_version < WCD937X) 801 wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); 802 break; 803 case WCD_CLSH_STATE_AUX: 804 if (ctrl->codec_version >= WCD937X) 805 wcd_clsh_v3_state_aux(ctrl, req_state, is_enable, mode); 806 break; 807 default: 808 break; 809 } 810 811 return 0; 812 } 813 814 /* 815 * Function: wcd_clsh_is_state_valid 816 * Params: state 817 * Description: 818 * Provides information on valid states of Class H configuration 819 */ 820 static bool wcd_clsh_is_state_valid(int state) 821 { 822 switch (state) { 823 case WCD_CLSH_STATE_IDLE: 824 case WCD_CLSH_STATE_EAR: 825 case WCD_CLSH_STATE_HPHL: 826 case WCD_CLSH_STATE_HPHR: 827 case WCD_CLSH_STATE_LO: 828 case WCD_CLSH_STATE_AUX: 829 return true; 830 default: 831 return false; 832 }; 833 } 834 835 /* 836 * Function: wcd_clsh_fsm 837 * Params: ctrl, req_state, req_type, clsh_event 838 * Description: 839 * This function handles PRE DAC and POST DAC conditions of different devices 840 * and updates class H configuration of different combination of devices 841 * based on validity of their states. ctrl will contain current 842 * class h state information 843 */ 844 int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, 845 enum wcd_clsh_event clsh_event, 846 int nstate, 847 enum wcd_clsh_mode mode) 848 { 849 struct snd_soc_component *comp = ctrl->comp; 850 851 if (nstate == ctrl->state) 852 return 0; 853 854 if (!wcd_clsh_is_state_valid(nstate)) { 855 dev_err(comp->dev, "Class-H not a valid new state:\n"); 856 return -EINVAL; 857 } 858 859 switch (clsh_event) { 860 case WCD_CLSH_EVENT_PRE_DAC: 861 _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_ENABLE, mode); 862 break; 863 case WCD_CLSH_EVENT_POST_PA: 864 _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode); 865 break; 866 } 867 868 ctrl->state = nstate; 869 ctrl->mode = mode; 870 871 return 0; 872 } 873 EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_set_state); 874 875 int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl) 876 { 877 return ctrl->state; 878 } 879 EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_get_state); 880 881 struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp, 882 int version) 883 { 884 struct wcd_clsh_ctrl *ctrl; 885 886 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); 887 if (!ctrl) 888 return ERR_PTR(-ENOMEM); 889 890 ctrl->state = WCD_CLSH_STATE_IDLE; 891 ctrl->comp = comp; 892 ctrl->codec_version = version; 893 894 return ctrl; 895 } 896 EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_alloc); 897 898 void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl) 899 { 900 kfree(ctrl); 901 } 902 EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_free); 903 904 MODULE_DESCRIPTION("WCD93XX Class-H driver"); 905 MODULE_LICENSE("GPL"); 906