cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wcd-clsh-v2.c (28153B)


      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}