Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
0003 // Copyright (c) 2017-2018, Linaro Limited
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 /* Class-H registers for codecs from and above WCD9335 */
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     /* set to HIFI */
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); /* set to HIFI */
0161     else
0162         snd_soc_component_update_bits(component,
0163                 WCD9XXX_ANA_RX_SUPPLIES,
0164                 0x08, 0x00); /* set to default */
0165 }
0166 
0167 static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp,
0168                          int mode)
0169 {
0170     /* set to HIFI */
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     /* enable/disable buck */
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      * 500us sleep is required after buck enable/disable
0195      * as per HW requirement
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     /* enable/disable buck */
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          * 500us sleep is required after buck enable/disable
0213          * as per HW requirement
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         /* 500usec delay is needed as per HW requirement */
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     /* enable/disable flyback */
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         /* 100usec delay is needed as per HW requirement */
0243         usleep_range(100, 110);
0244     }
0245     /*
0246      * 500us sleep is required after flyback enable/disable
0247      * as per HW requirement
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     /* Sleep needed to avoid click and pop as per HW requirement */
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); /* set to Default */
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         /* 100usec delay is needed as per HW requirement */
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     /* enable/disable flyback */
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          * 100us sleep is required after flyback enable/disable
0473          * as per HW requirement
0474          */
0475         usleep_range(100, 110);
0476         snd_soc_component_update_bits(component,
0477                 WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
0478                 0xE0, 0xE0);
0479         /* 500usec delay is needed as per HW requirement */
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     /* Sleep needed to avoid click and pop as per HW requirement */
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         /* buck and flyback set to default mode and disable */
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              * These K1 values depend on the Headphone Impedance
0589              * For now it is assumed to be 16 ohm
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         /* buck and flyback set to default mode and disable */
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         /* set buck and flyback to Default Mode */
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              * These K1 values depend on the Headphone Impedance
0679              * For now it is assumed to be 16 ohm
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         /* set buck and flyback to Default Mode */
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         /* set buck and flyback to Default Mode */
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  * Function: wcd_clsh_is_state_valid
0821  * Params: state
0822  * Description:
0823  * Provides information on valid states of Class H configuration
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  * Function: wcd_clsh_fsm
0842  * Params: ctrl, req_state, req_type, clsh_event
0843  * Description:
0844  * This function handles PRE DAC and POST DAC conditions of different devices
0845  * and updates class H configuration of different combination of devices
0846  * based on validity of their states. ctrl will contain current
0847  * class h state information
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 }