root/sound/soc/codecs/wcd-clsh-v2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wcd_enable_clsh_block
  2. wcd_clsh_enable_status
  3. wcd_clsh_set_buck_mode
  4. wcd_clsh_set_flyback_mode
  5. wcd_clsh_buck_ctrl
  6. wcd_clsh_flyback_ctrl
  7. wcd_clsh_set_gain_path
  8. wcd_clsh_set_hph_mode
  9. wcd_clsh_set_flyback_current
  10. wcd_clsh_set_buck_regulator_mode
  11. wcd_clsh_state_lo
  12. wcd_clsh_state_hph_r
  13. wcd_clsh_state_hph_l
  14. wcd_clsh_state_ear
  15. _wcd_clsh_ctrl_set_state
  16. wcd_clsh_is_state_valid
  17. wcd_clsh_ctrl_set_state
  18. wcd_clsh_ctrl_get_state
  19. wcd_clsh_ctrl_alloc
  20. wcd_clsh_ctrl_free

   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 CLSH_REQ_ENABLE         true
  92 #define CLSH_REQ_DISABLE        false
  93 #define WCD_USLEEP_RANGE        50
  94 
  95 enum {
  96         DAC_GAIN_0DB = 0,
  97         DAC_GAIN_0P2DB,
  98         DAC_GAIN_0P4DB,
  99         DAC_GAIN_0P6DB,
 100         DAC_GAIN_0P8DB,
 101         DAC_GAIN_M0P2DB,
 102         DAC_GAIN_M0P4DB,
 103         DAC_GAIN_M0P6DB,
 104 };
 105 
 106 static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl,
 107                                          bool enable)
 108 {
 109         struct snd_soc_component *comp = ctrl->comp;
 110 
 111         if ((enable && ++ctrl->clsh_users == 1) ||
 112             (!enable && --ctrl->clsh_users == 0))
 113                 snd_soc_component_update_bits(comp, WCD9XXX_A_CDC_CLSH_CRC,
 114                                       WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK,
 115                                       enable);
 116         if (ctrl->clsh_users < 0)
 117                 ctrl->clsh_users = 0;
 118 }
 119 
 120 static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp)
 121 {
 122         return snd_soc_component_read32(comp, WCD9XXX_A_CDC_CLSH_CRC) &
 123                                         WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK;
 124 }
 125 
 126 static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp,
 127                                           int mode)
 128 {
 129         /* set to HIFI */
 130         if (mode == CLS_H_HIFI)
 131                 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
 132                                         WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK,
 133                                         WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA);
 134         else
 135                 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
 136                                         WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK,
 137                                         WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT);
 138 }
 139 
 140 static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp,
 141                                              int mode)
 142 {
 143         /* set to HIFI */
 144         if (mode == CLS_H_HIFI)
 145                 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
 146                                         WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK,
 147                                         WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA);
 148         else
 149                 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
 150                                         WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK,
 151                                         WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT);
 152 }
 153 
 154 static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl,
 155                                int mode,
 156                                bool enable)
 157 {
 158         struct snd_soc_component *comp = ctrl->comp;
 159 
 160         /* enable/disable buck */
 161         if ((enable && (++ctrl->buck_users == 1)) ||
 162            (!enable && (--ctrl->buck_users == 0)))
 163                 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
 164                                 WCD9XXX_A_ANA_RX_VPOS_EN_MASK,
 165                                 enable << WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT);
 166         /*
 167          * 500us sleep is required after buck enable/disable
 168          * as per HW requirement
 169          */
 170         usleep_range(500, 500 + WCD_USLEEP_RANGE);
 171 }
 172 
 173 static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl,
 174                                   int mode,
 175                                   bool enable)
 176 {
 177         struct snd_soc_component *comp = ctrl->comp;
 178 
 179         /* enable/disable flyback */
 180         if ((enable && (++ctrl->flyback_users == 1)) ||
 181            (!enable && (--ctrl->flyback_users == 0))) {
 182                 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
 183                                 WCD9XXX_A_ANA_RX_VNEG_EN_MASK,
 184                                 enable << WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT);
 185                 /* 100usec delay is needed as per HW requirement */
 186                 usleep_range(100, 110);
 187         }
 188         /*
 189          * 500us sleep is required after flyback enable/disable
 190          * as per HW requirement
 191          */
 192         usleep_range(500, 500 + WCD_USLEEP_RANGE);
 193 }
 194 
 195 static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode)
 196 {
 197         struct snd_soc_component *comp = ctrl->comp;
 198         int val = 0;
 199 
 200         switch (mode) {
 201         case CLS_H_NORMAL:
 202         case CLS_AB:
 203                 val = WCD9XXX_HPH_CONST_SEL_BYPASS;
 204                 break;
 205         case CLS_H_HIFI:
 206                 val = WCD9XXX_HPH_CONST_SEL_HQ_PATH;
 207                 break;
 208         case CLS_H_LP:
 209                 val = WCD9XXX_HPH_CONST_SEL_LP_PATH;
 210                 break;
 211         }
 212 
 213         snd_soc_component_update_bits(comp, WCD9XXX_HPH_L_EN,
 214                                         WCD9XXX_HPH_CONST_SEL_L_MASK,
 215                                         val);
 216 
 217         snd_soc_component_update_bits(comp, WCD9XXX_HPH_R_EN,
 218                                         WCD9XXX_HPH_CONST_SEL_L_MASK,
 219                                         val);
 220 }
 221 
 222 static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp,
 223                                   int mode)
 224 {
 225         int val = 0, gain = 0, res_val;
 226         int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
 227 
 228         res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM;
 229         switch (mode) {
 230         case CLS_H_NORMAL:
 231                 res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM;
 232                 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL;
 233                 gain = DAC_GAIN_0DB;
 234                 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
 235                 break;
 236         case CLS_AB:
 237                 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL;
 238                 gain = DAC_GAIN_0DB;
 239                 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
 240                 break;
 241         case CLS_H_HIFI:
 242                 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA;
 243                 gain = DAC_GAIN_M0P2DB;
 244                 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
 245                 break;
 246         case CLS_H_LP:
 247                 val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP;
 248                 ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA;
 249                 break;
 250         }
 251 
 252         snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_HPH,
 253                                         WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val);
 254         snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_VCL_2,
 255                                 WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK,
 256                                 res_val);
 257         if (mode != CLS_H_LP)
 258                 snd_soc_component_update_bits(comp,
 259                                         WCD9XXX_HPH_REFBUFF_UHQA_CTL,
 260                                         WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK,
 261                                         gain);
 262         snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_CCL_1,
 263                                 WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK,
 264                                 ipeak);
 265 }
 266 
 267 static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp,
 268                                          int mode)
 269 {
 270 
 271         snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF,
 272                                 WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, 0x0A);
 273         snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF,
 274                                 WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, 0x0A);
 275         /* Sleep needed to avoid click and pop as per HW requirement */
 276         usleep_range(100, 110);
 277 }
 278 
 279 static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp,
 280                                              int mode)
 281 {
 282         if (mode == CLS_AB)
 283                 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
 284                                         WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK,
 285                                         WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB);
 286         else
 287                 snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
 288                                         WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK,
 289                                         WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H);
 290 }
 291 
 292 static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state,
 293                               bool is_enable, int mode)
 294 {
 295         struct snd_soc_component *comp = ctrl->comp;
 296 
 297         if (mode != CLS_AB) {
 298                 dev_err(comp->dev, "%s: LO cannot be in this mode: %d\n",
 299                         __func__, mode);
 300                 return;
 301         }
 302 
 303         if (is_enable) {
 304                 wcd_clsh_set_buck_regulator_mode(comp, mode);
 305                 wcd_clsh_set_buck_mode(comp, mode);
 306                 wcd_clsh_set_flyback_mode(comp, mode);
 307                 wcd_clsh_flyback_ctrl(ctrl, mode, true);
 308                 wcd_clsh_set_flyback_current(comp, mode);
 309                 wcd_clsh_buck_ctrl(ctrl, mode, true);
 310         } else {
 311                 wcd_clsh_buck_ctrl(ctrl, mode, false);
 312                 wcd_clsh_flyback_ctrl(ctrl, mode, false);
 313                 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
 314                 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
 315                 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
 316         }
 317 }
 318 
 319 static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state,
 320                                  bool is_enable, int mode)
 321 {
 322         struct snd_soc_component *comp = ctrl->comp;
 323 
 324         if (mode == CLS_H_NORMAL) {
 325                 dev_err(comp->dev, "%s: Normal mode not applicable for hph_r\n",
 326                         __func__);
 327                 return;
 328         }
 329 
 330         if (is_enable) {
 331                 if (mode != CLS_AB) {
 332                         wcd_enable_clsh_block(ctrl, true);
 333                         /*
 334                          * These K1 values depend on the Headphone Impedance
 335                          * For now it is assumed to be 16 ohm
 336                          */
 337                         snd_soc_component_update_bits(comp,
 338                                         WCD9XXX_A_CDC_CLSH_K1_MSB,
 339                                         WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK,
 340                                         0x00);
 341                         snd_soc_component_update_bits(comp,
 342                                         WCD9XXX_A_CDC_CLSH_K1_LSB,
 343                                         WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK,
 344                                         0xC0);
 345                         snd_soc_component_update_bits(comp,
 346                                             WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
 347                                             WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
 348                                             WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
 349                 }
 350                 wcd_clsh_set_buck_regulator_mode(comp, mode);
 351                 wcd_clsh_set_flyback_mode(comp, mode);
 352                 wcd_clsh_flyback_ctrl(ctrl, mode, true);
 353                 wcd_clsh_set_flyback_current(comp, mode);
 354                 wcd_clsh_set_buck_mode(comp, mode);
 355                 wcd_clsh_buck_ctrl(ctrl, mode, true);
 356                 wcd_clsh_set_hph_mode(comp, mode);
 357                 wcd_clsh_set_gain_path(ctrl, mode);
 358         } else {
 359                 wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL);
 360 
 361                 if (mode != CLS_AB) {
 362                         snd_soc_component_update_bits(comp,
 363                                             WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
 364                                             WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
 365                                             WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE);
 366                         wcd_enable_clsh_block(ctrl, false);
 367                 }
 368                 /* buck and flyback set to default mode and disable */
 369                 wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false);
 370                 wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false);
 371                 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
 372                 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
 373                 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
 374         }
 375 }
 376 
 377 static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state,
 378                                  bool is_enable, int mode)
 379 {
 380         struct snd_soc_component *comp = ctrl->comp;
 381 
 382         if (mode == CLS_H_NORMAL) {
 383                 dev_err(comp->dev, "%s: Normal mode not applicable for hph_l\n",
 384                         __func__);
 385                 return;
 386         }
 387 
 388         if (is_enable) {
 389                 if (mode != CLS_AB) {
 390                         wcd_enable_clsh_block(ctrl, true);
 391                         /*
 392                          * These K1 values depend on the Headphone Impedance
 393                          * For now it is assumed to be 16 ohm
 394                          */
 395                         snd_soc_component_update_bits(comp,
 396                                         WCD9XXX_A_CDC_CLSH_K1_MSB,
 397                                         WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK,
 398                                         0x00);
 399                         snd_soc_component_update_bits(comp,
 400                                         WCD9XXX_A_CDC_CLSH_K1_LSB,
 401                                         WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK,
 402                                         0xC0);
 403                         snd_soc_component_update_bits(comp,
 404                                             WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
 405                                             WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
 406                                             WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
 407                 }
 408                 wcd_clsh_set_buck_regulator_mode(comp, mode);
 409                 wcd_clsh_set_flyback_mode(comp, mode);
 410                 wcd_clsh_flyback_ctrl(ctrl, mode, true);
 411                 wcd_clsh_set_flyback_current(comp, mode);
 412                 wcd_clsh_set_buck_mode(comp, mode);
 413                 wcd_clsh_buck_ctrl(ctrl, mode, true);
 414                 wcd_clsh_set_hph_mode(comp, mode);
 415                 wcd_clsh_set_gain_path(ctrl, mode);
 416         } else {
 417                 wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL);
 418 
 419                 if (mode != CLS_AB) {
 420                         snd_soc_component_update_bits(comp,
 421                                             WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
 422                                             WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
 423                                             WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE);
 424                         wcd_enable_clsh_block(ctrl, false);
 425                 }
 426                 /* set buck and flyback to Default Mode */
 427                 wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false);
 428                 wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false);
 429                 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
 430                 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
 431                 wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
 432         }
 433 }
 434 
 435 static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state,
 436                                bool is_enable, int mode)
 437 {
 438         struct snd_soc_component *comp = ctrl->comp;
 439 
 440         if (mode != CLS_H_NORMAL) {
 441                 dev_err(comp->dev, "%s: mode: %d cannot be used for EAR\n",
 442                         __func__, mode);
 443                 return;
 444         }
 445 
 446         if (is_enable) {
 447                 wcd_enable_clsh_block(ctrl, true);
 448                 snd_soc_component_update_bits(comp,
 449                                         WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
 450                                         WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
 451                                         WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
 452                 wcd_clsh_set_buck_mode(comp, mode);
 453                 wcd_clsh_set_flyback_mode(comp, mode);
 454                 wcd_clsh_flyback_ctrl(ctrl, mode, true);
 455                 wcd_clsh_set_flyback_current(comp, mode);
 456                 wcd_clsh_buck_ctrl(ctrl, mode, true);
 457         } else {
 458                 snd_soc_component_update_bits(comp,
 459                                         WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
 460                                         WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
 461                                         WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE);
 462                 wcd_enable_clsh_block(ctrl, false);
 463                 wcd_clsh_buck_ctrl(ctrl, mode, false);
 464                 wcd_clsh_flyback_ctrl(ctrl, mode, false);
 465                 wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
 466                 wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
 467         }
 468 }
 469 
 470 static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state,
 471                                     bool is_enable, int mode)
 472 {
 473         switch (req_state) {
 474         case WCD_CLSH_STATE_EAR:
 475                 wcd_clsh_state_ear(ctrl, req_state, is_enable, mode);
 476                 break;
 477         case WCD_CLSH_STATE_HPHL:
 478                 wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode);
 479                 break;
 480         case WCD_CLSH_STATE_HPHR:
 481                 wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode);
 482                 break;
 483                 break;
 484         case WCD_CLSH_STATE_LO:
 485                 wcd_clsh_state_lo(ctrl, req_state, is_enable, mode);
 486                 break;
 487         default:
 488                 break;
 489         }
 490 
 491         return 0;
 492 }
 493 
 494 /*
 495  * Function: wcd_clsh_is_state_valid
 496  * Params: state
 497  * Description:
 498  * Provides information on valid states of Class H configuration
 499  */
 500 static bool wcd_clsh_is_state_valid(int state)
 501 {
 502         switch (state) {
 503         case WCD_CLSH_STATE_IDLE:
 504         case WCD_CLSH_STATE_EAR:
 505         case WCD_CLSH_STATE_HPHL:
 506         case WCD_CLSH_STATE_HPHR:
 507         case WCD_CLSH_STATE_LO:
 508                 return true;
 509         default:
 510                 return false;
 511         };
 512 }
 513 
 514 /*
 515  * Function: wcd_clsh_fsm
 516  * Params: ctrl, req_state, req_type, clsh_event
 517  * Description:
 518  * This function handles PRE DAC and POST DAC conditions of different devices
 519  * and updates class H configuration of different combination of devices
 520  * based on validity of their states. ctrl will contain current
 521  * class h state information
 522  */
 523 int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl,
 524                             enum wcd_clsh_event clsh_event,
 525                             int nstate,
 526                             enum wcd_clsh_mode mode)
 527 {
 528         struct snd_soc_component *comp = ctrl->comp;
 529 
 530         if (nstate == ctrl->state)
 531                 return 0;
 532 
 533         if (!wcd_clsh_is_state_valid(nstate)) {
 534                 dev_err(comp->dev, "Class-H not a valid new state:\n");
 535                 return -EINVAL;
 536         }
 537 
 538         switch (clsh_event) {
 539         case WCD_CLSH_EVENT_PRE_DAC:
 540                 _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_ENABLE, mode);
 541                 break;
 542         case WCD_CLSH_EVENT_POST_PA:
 543                 _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode);
 544                 break;
 545         }
 546 
 547         ctrl->state = nstate;
 548         ctrl->mode = mode;
 549 
 550         return 0;
 551 }
 552 
 553 int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl)
 554 {
 555         return ctrl->state;
 556 }
 557 
 558 struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp,
 559                                           int version)
 560 {
 561         struct wcd_clsh_ctrl *ctrl;
 562 
 563         ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
 564         if (!ctrl)
 565                 return ERR_PTR(-ENOMEM);
 566 
 567         ctrl->state = WCD_CLSH_STATE_IDLE;
 568         ctrl->comp = comp;
 569 
 570         return ctrl;
 571 }
 572 
 573 void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl)
 574 {
 575         kfree(ctrl);
 576 }

/* [<][>][^][v][top][bottom][index][help] */