0001
0002
0003
0004
0005 #include <linux/slab.h>
0006 #include <sound/soc.h>
0007 #include <linux/kernel.h>
0008 #include <linux/delay.h>
0009 #include "wcd9335.h"
0010 #include "wcd-clsh-v2.h"
0011
0012 struct wcd_clsh_ctrl {
0013 int state;
0014 int mode;
0015 int flyback_users;
0016 int buck_users;
0017 int clsh_users;
0018 int codec_version;
0019 struct snd_soc_component *comp;
0020 };
0021
0022
0023 #define WCD9XXX_A_CDC_RX0_RX_PATH_CFG0 WCD9335_REG(0xB, 0x42)
0024 #define WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK BIT(6)
0025 #define WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE BIT(6)
0026 #define WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE 0
0027 #define WCD9XXX_A_CDC_RX1_RX_PATH_CFG0 WCD9335_REG(0xB, 0x56)
0028 #define WCD9XXX_A_CDC_RX2_RX_PATH_CFG0 WCD9335_REG(0xB, 0x6A)
0029 #define WCD9XXX_A_CDC_CLSH_K1_MSB WCD9335_REG(0xC, 0x08)
0030 #define WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK GENMASK(3, 0)
0031 #define WCD9XXX_A_CDC_CLSH_K1_LSB WCD9335_REG(0xC, 0x09)
0032 #define WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK GENMASK(7, 0)
0033 #define WCD9XXX_A_ANA_RX_SUPPLIES WCD9335_REG(0x6, 0x08)
0034 #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK BIT(1)
0035 #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H 0
0036 #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB BIT(1)
0037 #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK BIT(2)
0038 #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA BIT(2)
0039 #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT 0
0040 #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK BIT(3)
0041 #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA BIT(3)
0042 #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT 0
0043 #define WCD9XXX_A_ANA_RX_VNEG_EN_MASK BIT(6)
0044 #define WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT 6
0045 #define WCD9XXX_A_ANA_RX_VNEG_ENABLE BIT(6)
0046 #define WCD9XXX_A_ANA_RX_VNEG_DISABLE 0
0047 #define WCD9XXX_A_ANA_RX_VPOS_EN_MASK BIT(7)
0048 #define WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT 7
0049 #define WCD9XXX_A_ANA_RX_VPOS_ENABLE BIT(7)
0050 #define WCD9XXX_A_ANA_RX_VPOS_DISABLE 0
0051 #define WCD9XXX_A_ANA_HPH WCD9335_REG(0x6, 0x09)
0052 #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK GENMASK(3, 2)
0053 #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA 0x08
0054 #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP 0x04
0055 #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL 0x0
0056 #define WCD9XXX_A_CDC_CLSH_CRC WCD9335_REG(0xC, 0x01)
0057 #define WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK BIT(0)
0058 #define WCD9XXX_A_CDC_CLSH_CRC_CLK_ENABLE BIT(0)
0059 #define WCD9XXX_A_CDC_CLSH_CRC_CLK_DISABLE 0
0060 #define WCD9XXX_FLYBACK_EN WCD9335_REG(0x6, 0xA4)
0061 #define WCD9XXX_FLYBACK_EN_DELAY_SEL_MASK GENMASK(6, 5)
0062 #define WCD9XXX_FLYBACK_EN_DELAY_26P25_US 0x40
0063 #define WCD9XXX_FLYBACK_EN_RESET_BY_EXT_MASK BIT(4)
0064 #define WCD9XXX_FLYBACK_EN_PWDN_WITHOUT_DELAY BIT(4)
0065 #define WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY 0
0066 #define WCD9XXX_RX_BIAS_FLYB_BUFF WCD9335_REG(0x6, 0xC7)
0067 #define WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4)
0068 #define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(3, 0)
0069 #define WCD9XXX_HPH_L_EN WCD9335_REG(0x6, 0xD3)
0070 #define WCD9XXX_HPH_CONST_SEL_L_MASK GENMASK(7, 3)
0071 #define WCD9XXX_HPH_CONST_SEL_BYPASS 0
0072 #define WCD9XXX_HPH_CONST_SEL_LP_PATH 0x40
0073 #define WCD9XXX_HPH_CONST_SEL_HQ_PATH 0x80
0074 #define WCD9XXX_HPH_R_EN WCD9335_REG(0x6, 0xD6)
0075 #define WCD9XXX_HPH_REFBUFF_UHQA_CTL WCD9335_REG(0x6, 0xDD)
0076 #define WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK GENMASK(2, 0)
0077 #define WCD9XXX_CLASSH_CTRL_VCL_2 WCD9335_REG(0x6, 0x9B)
0078 #define WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK GENMASK(5, 4)
0079 #define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM 0x20
0080 #define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM 0x0
0081 #define WCD9XXX_CDC_RX1_RX_PATH_CTL WCD9335_REG(0xB, 0x55)
0082 #define WCD9XXX_CDC_RX2_RX_PATH_CTL WCD9335_REG(0xB, 0x69)
0083 #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL WCD9335_REG(0xD, 0x41)
0084 #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_EN_MASK BIT(0)
0085 #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_11P3_EN_MASK BIT(1)
0086 #define WCD9XXX_CLASSH_CTRL_CCL_1 WCD9335_REG(0x6, 0x9C)
0087 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK GENMASK(7, 4)
0088 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50
0089 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30
0090
0091 #define WCD9XXX_BASE_ADDRESS 0x3000
0092 #define WCD9XXX_ANA_RX_SUPPLIES (WCD9XXX_BASE_ADDRESS+0x008)
0093 #define WCD9XXX_ANA_HPH (WCD9XXX_BASE_ADDRESS+0x009)
0094 #define WCD9XXX_CLASSH_MODE_2 (WCD9XXX_BASE_ADDRESS+0x098)
0095 #define WCD9XXX_CLASSH_MODE_3 (WCD9XXX_BASE_ADDRESS+0x099)
0096 #define WCD9XXX_FLYBACK_VNEG_CTRL_1 (WCD9XXX_BASE_ADDRESS+0x0A5)
0097 #define WCD9XXX_FLYBACK_VNEG_CTRL_4 (WCD9XXX_BASE_ADDRESS+0x0A8)
0098 #define WCD9XXX_FLYBACK_VNEGDAC_CTRL_2 (WCD9XXX_BASE_ADDRESS+0x0AF)
0099 #define WCD9XXX_RX_BIAS_HPH_LOWPOWER (WCD9XXX_BASE_ADDRESS+0x0BF)
0100 #define WCD9XXX_V3_RX_BIAS_FLYB_BUFF (WCD9XXX_BASE_ADDRESS+0x0C7)
0101 #define WCD9XXX_HPH_PA_CTL1 (WCD9XXX_BASE_ADDRESS+0x0D1)
0102 #define WCD9XXX_HPH_NEW_INT_PA_MISC2 (WCD9XXX_BASE_ADDRESS+0x138)
0103
0104 #define CLSH_REQ_ENABLE true
0105 #define CLSH_REQ_DISABLE false
0106 #define WCD_USLEEP_RANGE 50
0107
0108 enum {
0109 DAC_GAIN_0DB = 0,
0110 DAC_GAIN_0P2DB,
0111 DAC_GAIN_0P4DB,
0112 DAC_GAIN_0P6DB,
0113 DAC_GAIN_0P8DB,
0114 DAC_GAIN_M0P2DB,
0115 DAC_GAIN_M0P4DB,
0116 DAC_GAIN_M0P6DB,
0117 };
0118
0119 static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl,
0120 bool enable)
0121 {
0122 struct snd_soc_component *comp = ctrl->comp;
0123
0124 if ((enable && ++ctrl->clsh_users == 1) ||
0125 (!enable && --ctrl->clsh_users == 0))
0126 snd_soc_component_update_bits(comp, WCD9XXX_A_CDC_CLSH_CRC,
0127 WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK,
0128 enable);
0129 if (ctrl->clsh_users < 0)
0130 ctrl->clsh_users = 0;
0131 }
0132
0133 static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp)
0134 {
0135 return snd_soc_component_read(comp, WCD9XXX_A_CDC_CLSH_CRC) &
0136 WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK;
0137 }
0138
0139 static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp,
0140 int mode)
0141 {
0142
0143 if (mode == CLS_H_HIFI)
0144 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
0145 WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK,
0146 WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA);
0147 else
0148 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
0149 WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK,
0150 WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT);
0151 }
0152
0153 static void wcd_clsh_v3_set_buck_mode(struct snd_soc_component *component,
0154 int mode)
0155 {
0156 if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
0157 mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI)
0158 snd_soc_component_update_bits(component,
0159 WCD9XXX_ANA_RX_SUPPLIES,
0160 0x08, 0x08);
0161 else
0162 snd_soc_component_update_bits(component,
0163 WCD9XXX_ANA_RX_SUPPLIES,
0164 0x08, 0x00);
0165 }
0166
0167 static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp,
0168 int mode)
0169 {
0170
0171 if (mode == CLS_H_HIFI)
0172 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
0173 WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK,
0174 WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA);
0175 else
0176 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
0177 WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK,
0178 WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT);
0179 }
0180
0181 static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl,
0182 int mode,
0183 bool enable)
0184 {
0185 struct snd_soc_component *comp = ctrl->comp;
0186
0187
0188 if ((enable && (++ctrl->buck_users == 1)) ||
0189 (!enable && (--ctrl->buck_users == 0)))
0190 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
0191 WCD9XXX_A_ANA_RX_VPOS_EN_MASK,
0192 enable << WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT);
0193
0194
0195
0196
0197 usleep_range(500, 500 + WCD_USLEEP_RANGE);
0198 }
0199
0200 static void wcd_clsh_v3_buck_ctrl(struct snd_soc_component *component,
0201 struct wcd_clsh_ctrl *ctrl,
0202 int mode,
0203 bool enable)
0204 {
0205
0206 if ((enable && (++ctrl->buck_users == 1)) ||
0207 (!enable && (--ctrl->buck_users == 0))) {
0208 snd_soc_component_update_bits(component,
0209 WCD9XXX_ANA_RX_SUPPLIES,
0210 (1 << 7), (enable << 7));
0211
0212
0213
0214
0215 usleep_range(500, 510);
0216 if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP ||
0217 mode == CLS_H_HIFI || mode == CLS_H_LP)
0218 snd_soc_component_update_bits(component,
0219 WCD9XXX_CLASSH_MODE_3,
0220 0x02, 0x00);
0221
0222 snd_soc_component_update_bits(component,
0223 WCD9XXX_CLASSH_MODE_2,
0224 0xFF, 0x3A);
0225
0226 usleep_range(500, 500 + WCD_USLEEP_RANGE);
0227 }
0228 }
0229
0230 static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl,
0231 int mode,
0232 bool enable)
0233 {
0234 struct snd_soc_component *comp = ctrl->comp;
0235
0236
0237 if ((enable && (++ctrl->flyback_users == 1)) ||
0238 (!enable && (--ctrl->flyback_users == 0))) {
0239 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
0240 WCD9XXX_A_ANA_RX_VNEG_EN_MASK,
0241 enable << WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT);
0242
0243 usleep_range(100, 110);
0244 }
0245
0246
0247
0248
0249 usleep_range(500, 500 + WCD_USLEEP_RANGE);
0250 }
0251
0252 static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode)
0253 {
0254 struct snd_soc_component *comp = ctrl->comp;
0255 int val = 0;
0256
0257 switch (mode) {
0258 case CLS_H_NORMAL:
0259 case CLS_AB:
0260 val = WCD9XXX_HPH_CONST_SEL_BYPASS;
0261 break;
0262 case CLS_H_HIFI:
0263 val = WCD9XXX_HPH_CONST_SEL_HQ_PATH;
0264 break;
0265 case CLS_H_LP:
0266 val = WCD9XXX_HPH_CONST_SEL_LP_PATH;
0267 break;
0268 }
0269
0270 snd_soc_component_update_bits(comp, WCD9XXX_HPH_L_EN,
0271 WCD9XXX_HPH_CONST_SEL_L_MASK,
0272 val);
0273
0274 snd_soc_component_update_bits(comp, WCD9XXX_HPH_R_EN,
0275 WCD9XXX_HPH_CONST_SEL_L_MASK,
0276 val);
0277 }
0278
0279 static void wcd_clsh_v2_set_hph_mode(struct snd_soc_component *comp, int mode)
0280 {
0281 int val = 0, gain = 0, res_val;
0282 int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
0283
0284 res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM;
0285 switch (mode) {
0286 case CLS_H_NORMAL:
0287 res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM;
0288 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL;
0289 gain = DAC_GAIN_0DB;
0290 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
0291 break;
0292 case CLS_AB:
0293 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL;
0294 gain = DAC_GAIN_0DB;
0295 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
0296 break;
0297 case CLS_H_HIFI:
0298 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA;
0299 gain = DAC_GAIN_M0P2DB;
0300 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
0301 break;
0302 case CLS_H_LP:
0303 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP;
0304 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA;
0305 break;
0306 }
0307
0308 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_HPH,
0309 WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val);
0310 snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_VCL_2,
0311 WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK,
0312 res_val);
0313 if (mode != CLS_H_LP)
0314 snd_soc_component_update_bits(comp,
0315 WCD9XXX_HPH_REFBUFF_UHQA_CTL,
0316 WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK,
0317 gain);
0318 snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_CCL_1,
0319 WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK,
0320 ipeak);
0321 }
0322
0323 static void wcd_clsh_v3_set_hph_mode(struct snd_soc_component *component,
0324 int mode)
0325 {
0326 u8 val;
0327
0328 switch (mode) {
0329 case CLS_H_NORMAL:
0330 val = 0x00;
0331 break;
0332 case CLS_AB:
0333 case CLS_H_ULP:
0334 val = 0x0C;
0335 break;
0336 case CLS_AB_HIFI:
0337 case CLS_H_HIFI:
0338 val = 0x08;
0339 break;
0340 case CLS_H_LP:
0341 case CLS_H_LOHIFI:
0342 case CLS_AB_LP:
0343 case CLS_AB_LOHIFI:
0344 val = 0x04;
0345 break;
0346 default:
0347 dev_err(component->dev, "%s:Invalid mode %d\n", __func__, mode);
0348 return;
0349 }
0350
0351 snd_soc_component_update_bits(component, WCD9XXX_ANA_HPH, 0x0C, val);
0352 }
0353
0354 void wcd_clsh_set_hph_mode(struct wcd_clsh_ctrl *ctrl, int mode)
0355 {
0356 struct snd_soc_component *comp = ctrl->comp;
0357
0358 if (ctrl->codec_version >= WCD937X)
0359 wcd_clsh_v3_set_hph_mode(comp, mode);
0360 else
0361 wcd_clsh_v2_set_hph_mode(comp, mode);
0362
0363 }
0364
0365 static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp,
0366 int mode)
0367 {
0368
0369 snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF,
0370 WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, 0x0A);
0371 snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF,
0372 WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, 0x0A);
0373
0374 usleep_range(100, 110);
0375 }
0376
0377 static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp,
0378 int mode)
0379 {
0380 if (mode == CLS_AB)
0381 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
0382 WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK,
0383 WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB);
0384 else
0385 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
0386 WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK,
0387 WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H);
0388 }
0389
0390 static void wcd_clsh_v3_set_buck_regulator_mode(struct snd_soc_component *component,
0391 int mode)
0392 {
0393 snd_soc_component_update_bits(component, WCD9XXX_ANA_RX_SUPPLIES,
0394 0x02, 0x00);
0395 }
0396
0397 static void wcd_clsh_v3_set_flyback_mode(struct snd_soc_component *component,
0398 int mode)
0399 {
0400 if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
0401 mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) {
0402 snd_soc_component_update_bits(component,
0403 WCD9XXX_ANA_RX_SUPPLIES,
0404 0x04, 0x04);
0405 snd_soc_component_update_bits(component,
0406 WCD9XXX_FLYBACK_VNEG_CTRL_4,
0407 0xF0, 0x80);
0408 } else {
0409 snd_soc_component_update_bits(component,
0410 WCD9XXX_ANA_RX_SUPPLIES,
0411 0x04, 0x00);
0412 snd_soc_component_update_bits(component,
0413 WCD9XXX_FLYBACK_VNEG_CTRL_4,
0414 0xF0, 0x70);
0415 }
0416 }
0417
0418 static void wcd_clsh_v3_force_iq_ctl(struct snd_soc_component *component,
0419 int mode, bool enable)
0420 {
0421 if (enable) {
0422 snd_soc_component_update_bits(component,
0423 WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
0424 0xE0, 0xA0);
0425
0426 usleep_range(100, 110);
0427 snd_soc_component_update_bits(component,
0428 WCD9XXX_CLASSH_MODE_3,
0429 0x02, 0x02);
0430 snd_soc_component_update_bits(component,
0431 WCD9XXX_CLASSH_MODE_2,
0432 0xFF, 0x1C);
0433 if (mode == CLS_H_LOHIFI || mode == CLS_AB_LOHIFI) {
0434 snd_soc_component_update_bits(component,
0435 WCD9XXX_HPH_NEW_INT_PA_MISC2,
0436 0x20, 0x20);
0437 snd_soc_component_update_bits(component,
0438 WCD9XXX_RX_BIAS_HPH_LOWPOWER,
0439 0xF0, 0xC0);
0440 snd_soc_component_update_bits(component,
0441 WCD9XXX_HPH_PA_CTL1,
0442 0x0E, 0x02);
0443 }
0444 } else {
0445 snd_soc_component_update_bits(component,
0446 WCD9XXX_HPH_NEW_INT_PA_MISC2,
0447 0x20, 0x00);
0448 snd_soc_component_update_bits(component,
0449 WCD9XXX_RX_BIAS_HPH_LOWPOWER,
0450 0xF0, 0x80);
0451 snd_soc_component_update_bits(component,
0452 WCD9XXX_HPH_PA_CTL1,
0453 0x0E, 0x06);
0454 }
0455 }
0456
0457 static void wcd_clsh_v3_flyback_ctrl(struct snd_soc_component *component,
0458 struct wcd_clsh_ctrl *ctrl,
0459 int mode,
0460 bool enable)
0461 {
0462
0463 if ((enable && (++ctrl->flyback_users == 1)) ||
0464 (!enable && (--ctrl->flyback_users == 0))) {
0465 snd_soc_component_update_bits(component,
0466 WCD9XXX_FLYBACK_VNEG_CTRL_1,
0467 0xE0, 0xE0);
0468 snd_soc_component_update_bits(component,
0469 WCD9XXX_ANA_RX_SUPPLIES,
0470 (1 << 6), (enable << 6));
0471
0472
0473
0474
0475 usleep_range(100, 110);
0476 snd_soc_component_update_bits(component,
0477 WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
0478 0xE0, 0xE0);
0479
0480 usleep_range(500, 500 + WCD_USLEEP_RANGE);
0481 }
0482 }
0483
0484 static void wcd_clsh_v3_set_flyback_current(struct snd_soc_component *component,
0485 int mode)
0486 {
0487 snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF,
0488 0x0F, 0x0A);
0489 snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF,
0490 0xF0, 0xA0);
0491
0492 usleep_range(100, 110);
0493 }
0494
0495 static void wcd_clsh_v3_state_aux(struct wcd_clsh_ctrl *ctrl, int req_state,
0496 bool is_enable, int mode)
0497 {
0498 struct snd_soc_component *component = ctrl->comp;
0499
0500 if (is_enable) {
0501 wcd_clsh_v3_set_buck_mode(component, mode);
0502 wcd_clsh_v3_set_flyback_mode(component, mode);
0503 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true);
0504 wcd_clsh_v3_set_flyback_current(component, mode);
0505 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true);
0506 } else {
0507 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, false);
0508 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, false);
0509 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL);
0510 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL);
0511 }
0512 }
0513
0514 static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state,
0515 bool is_enable, int mode)
0516 {
0517 struct snd_soc_component *comp = ctrl->comp;
0518
0519 if (mode != CLS_AB) {
0520 dev_err(comp->dev, "%s: LO cannot be in this mode: %d\n",
0521 __func__, mode);
0522 return;
0523 }
0524
0525 if (is_enable) {
0526 wcd_clsh_set_buck_regulator_mode(comp, mode);
0527 wcd_clsh_set_buck_mode(comp, mode);
0528 wcd_clsh_set_flyback_mode(comp, mode);
0529 wcd_clsh_flyback_ctrl(ctrl, mode, true);
0530 wcd_clsh_set_flyback_current(comp, mode);
0531 wcd_clsh_buck_ctrl(ctrl, mode, true);
0532 } else {
0533 wcd_clsh_buck_ctrl(ctrl, mode, false);
0534 wcd_clsh_flyback_ctrl(ctrl, mode, false);
0535 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
0536 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
0537 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
0538 }
0539 }
0540
0541 static void wcd_clsh_v3_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state,
0542 bool is_enable, int mode)
0543 {
0544 struct snd_soc_component *component = ctrl->comp;
0545
0546 if (mode == CLS_H_NORMAL) {
0547 dev_dbg(component->dev, "%s: Normal mode not applicable for hph_r\n",
0548 __func__);
0549 return;
0550 }
0551
0552 if (is_enable) {
0553 wcd_clsh_v3_set_buck_regulator_mode(component, mode);
0554 wcd_clsh_v3_set_flyback_mode(component, mode);
0555 wcd_clsh_v3_force_iq_ctl(component, mode, true);
0556 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true);
0557 wcd_clsh_v3_set_flyback_current(component, mode);
0558 wcd_clsh_v3_set_buck_mode(component, mode);
0559 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true);
0560 wcd_clsh_v3_set_hph_mode(component, mode);
0561 } else {
0562 wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL);
0563
0564
0565 wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false);
0566 wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false);
0567 wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false);
0568 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL);
0569 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL);
0570 }
0571 }
0572
0573 static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state,
0574 bool is_enable, int mode)
0575 {
0576 struct snd_soc_component *comp = ctrl->comp;
0577
0578 if (mode == CLS_H_NORMAL) {
0579 dev_err(comp->dev, "%s: Normal mode not applicable for hph_r\n",
0580 __func__);
0581 return;
0582 }
0583
0584 if (is_enable) {
0585 if (mode != CLS_AB) {
0586 wcd_enable_clsh_block(ctrl, true);
0587
0588
0589
0590
0591 snd_soc_component_update_bits(comp,
0592 WCD9XXX_A_CDC_CLSH_K1_MSB,
0593 WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK,
0594 0x00);
0595 snd_soc_component_update_bits(comp,
0596 WCD9XXX_A_CDC_CLSH_K1_LSB,
0597 WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK,
0598 0xC0);
0599 snd_soc_component_update_bits(comp,
0600 WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
0601 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
0602 WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
0603 }
0604 wcd_clsh_set_buck_regulator_mode(comp, mode);
0605 wcd_clsh_set_flyback_mode(comp, mode);
0606 wcd_clsh_flyback_ctrl(ctrl, mode, true);
0607 wcd_clsh_set_flyback_current(comp, mode);
0608 wcd_clsh_set_buck_mode(comp, mode);
0609 wcd_clsh_buck_ctrl(ctrl, mode, true);
0610 wcd_clsh_v2_set_hph_mode(comp, mode);
0611 wcd_clsh_set_gain_path(ctrl, mode);
0612 } else {
0613 wcd_clsh_v2_set_hph_mode(comp, CLS_H_NORMAL);
0614
0615 if (mode != CLS_AB) {
0616 snd_soc_component_update_bits(comp,
0617 WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
0618 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
0619 WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE);
0620 wcd_enable_clsh_block(ctrl, false);
0621 }
0622
0623 wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false);
0624 wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false);
0625 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
0626 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
0627 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
0628 }
0629 }
0630
0631 static void wcd_clsh_v3_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state,
0632 bool is_enable, int mode)
0633 {
0634 struct snd_soc_component *component = ctrl->comp;
0635
0636 if (mode == CLS_H_NORMAL) {
0637 dev_dbg(component->dev, "%s: Normal mode not applicable for hph_l\n",
0638 __func__);
0639 return;
0640 }
0641
0642 if (is_enable) {
0643 wcd_clsh_v3_set_buck_regulator_mode(component, mode);
0644 wcd_clsh_v3_set_flyback_mode(component, mode);
0645 wcd_clsh_v3_force_iq_ctl(component, mode, true);
0646 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true);
0647 wcd_clsh_v3_set_flyback_current(component, mode);
0648 wcd_clsh_v3_set_buck_mode(component, mode);
0649 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true);
0650 wcd_clsh_v3_set_hph_mode(component, mode);
0651 } else {
0652 wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL);
0653
0654
0655 wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false);
0656 wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false);
0657 wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false);
0658 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL);
0659 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL);
0660 }
0661 }
0662
0663 static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state,
0664 bool is_enable, int mode)
0665 {
0666 struct snd_soc_component *comp = ctrl->comp;
0667
0668 if (mode == CLS_H_NORMAL) {
0669 dev_err(comp->dev, "%s: Normal mode not applicable for hph_l\n",
0670 __func__);
0671 return;
0672 }
0673
0674 if (is_enable) {
0675 if (mode != CLS_AB) {
0676 wcd_enable_clsh_block(ctrl, true);
0677
0678
0679
0680
0681 snd_soc_component_update_bits(comp,
0682 WCD9XXX_A_CDC_CLSH_K1_MSB,
0683 WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK,
0684 0x00);
0685 snd_soc_component_update_bits(comp,
0686 WCD9XXX_A_CDC_CLSH_K1_LSB,
0687 WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK,
0688 0xC0);
0689 snd_soc_component_update_bits(comp,
0690 WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
0691 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
0692 WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
0693 }
0694 wcd_clsh_set_buck_regulator_mode(comp, mode);
0695 wcd_clsh_set_flyback_mode(comp, mode);
0696 wcd_clsh_flyback_ctrl(ctrl, mode, true);
0697 wcd_clsh_set_flyback_current(comp, mode);
0698 wcd_clsh_set_buck_mode(comp, mode);
0699 wcd_clsh_buck_ctrl(ctrl, mode, true);
0700 wcd_clsh_v2_set_hph_mode(comp, mode);
0701 wcd_clsh_set_gain_path(ctrl, mode);
0702 } else {
0703 wcd_clsh_v2_set_hph_mode(comp, CLS_H_NORMAL);
0704
0705 if (mode != CLS_AB) {
0706 snd_soc_component_update_bits(comp,
0707 WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
0708 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
0709 WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE);
0710 wcd_enable_clsh_block(ctrl, false);
0711 }
0712
0713 wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false);
0714 wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false);
0715 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
0716 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
0717 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
0718 }
0719 }
0720
0721 static void wcd_clsh_v3_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state,
0722 bool is_enable, int mode)
0723 {
0724 struct snd_soc_component *component = ctrl->comp;
0725
0726 if (is_enable) {
0727 wcd_clsh_v3_set_buck_regulator_mode(component, mode);
0728 wcd_clsh_v3_set_flyback_mode(component, mode);
0729 wcd_clsh_v3_force_iq_ctl(component, mode, true);
0730 wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true);
0731 wcd_clsh_v3_set_flyback_current(component, mode);
0732 wcd_clsh_v3_set_buck_mode(component, mode);
0733 wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true);
0734 wcd_clsh_v3_set_hph_mode(component, mode);
0735 } else {
0736 wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL);
0737
0738
0739 wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false);
0740 wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false);
0741 wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false);
0742 wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL);
0743 wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL);
0744 }
0745 }
0746
0747 static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state,
0748 bool is_enable, int mode)
0749 {
0750 struct snd_soc_component *comp = ctrl->comp;
0751
0752 if (mode != CLS_H_NORMAL) {
0753 dev_err(comp->dev, "%s: mode: %d cannot be used for EAR\n",
0754 __func__, mode);
0755 return;
0756 }
0757
0758 if (is_enable) {
0759 wcd_enable_clsh_block(ctrl, true);
0760 snd_soc_component_update_bits(comp,
0761 WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
0762 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
0763 WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
0764 wcd_clsh_set_buck_mode(comp, mode);
0765 wcd_clsh_set_flyback_mode(comp, mode);
0766 wcd_clsh_flyback_ctrl(ctrl, mode, true);
0767 wcd_clsh_set_flyback_current(comp, mode);
0768 wcd_clsh_buck_ctrl(ctrl, mode, true);
0769 } else {
0770 snd_soc_component_update_bits(comp,
0771 WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
0772 WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
0773 WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE);
0774 wcd_enable_clsh_block(ctrl, false);
0775 wcd_clsh_buck_ctrl(ctrl, mode, false);
0776 wcd_clsh_flyback_ctrl(ctrl, mode, false);
0777 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
0778 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
0779 }
0780 }
0781
0782 static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state,
0783 bool is_enable, int mode)
0784 {
0785 switch (req_state) {
0786 case WCD_CLSH_STATE_EAR:
0787 if (ctrl->codec_version >= WCD937X)
0788 wcd_clsh_v3_state_ear(ctrl, req_state, is_enable, mode);
0789 else
0790 wcd_clsh_state_ear(ctrl, req_state, is_enable, mode);
0791 break;
0792 case WCD_CLSH_STATE_HPHL:
0793 if (ctrl->codec_version >= WCD937X)
0794 wcd_clsh_v3_state_hph_l(ctrl, req_state, is_enable, mode);
0795 else
0796 wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode);
0797 break;
0798 case WCD_CLSH_STATE_HPHR:
0799 if (ctrl->codec_version >= WCD937X)
0800 wcd_clsh_v3_state_hph_r(ctrl, req_state, is_enable, mode);
0801 else
0802 wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode);
0803 break;
0804 case WCD_CLSH_STATE_LO:
0805 if (ctrl->codec_version < WCD937X)
0806 wcd_clsh_state_lo(ctrl, req_state, is_enable, mode);
0807 break;
0808 case WCD_CLSH_STATE_AUX:
0809 if (ctrl->codec_version >= WCD937X)
0810 wcd_clsh_v3_state_aux(ctrl, req_state, is_enable, mode);
0811 break;
0812 default:
0813 break;
0814 }
0815
0816 return 0;
0817 }
0818
0819
0820
0821
0822
0823
0824
0825 static bool wcd_clsh_is_state_valid(int state)
0826 {
0827 switch (state) {
0828 case WCD_CLSH_STATE_IDLE:
0829 case WCD_CLSH_STATE_EAR:
0830 case WCD_CLSH_STATE_HPHL:
0831 case WCD_CLSH_STATE_HPHR:
0832 case WCD_CLSH_STATE_LO:
0833 case WCD_CLSH_STATE_AUX:
0834 return true;
0835 default:
0836 return false;
0837 };
0838 }
0839
0840
0841
0842
0843
0844
0845
0846
0847
0848
0849 int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl,
0850 enum wcd_clsh_event clsh_event,
0851 int nstate,
0852 enum wcd_clsh_mode mode)
0853 {
0854 struct snd_soc_component *comp = ctrl->comp;
0855
0856 if (nstate == ctrl->state)
0857 return 0;
0858
0859 if (!wcd_clsh_is_state_valid(nstate)) {
0860 dev_err(comp->dev, "Class-H not a valid new state:\n");
0861 return -EINVAL;
0862 }
0863
0864 switch (clsh_event) {
0865 case WCD_CLSH_EVENT_PRE_DAC:
0866 _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_ENABLE, mode);
0867 break;
0868 case WCD_CLSH_EVENT_POST_PA:
0869 _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode);
0870 break;
0871 }
0872
0873 ctrl->state = nstate;
0874 ctrl->mode = mode;
0875
0876 return 0;
0877 }
0878
0879 int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl)
0880 {
0881 return ctrl->state;
0882 }
0883
0884 struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp,
0885 int version)
0886 {
0887 struct wcd_clsh_ctrl *ctrl;
0888
0889 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
0890 if (!ctrl)
0891 return ERR_PTR(-ENOMEM);
0892
0893 ctrl->state = WCD_CLSH_STATE_IDLE;
0894 ctrl->comp = comp;
0895 ctrl->codec_version = version;
0896
0897 return ctrl;
0898 }
0899
0900 void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl)
0901 {
0902 kfree(ctrl);
0903 }