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