wcd-clsh-v2.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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. #include <linux/slab.h>
  5. #include <sound/soc.h>
  6. #include <linux/kernel.h>
  7. #include <linux/delay.h>
  8. #include "wcd9335.h"
  9. #include "wcd-clsh-v2.h"
  10. struct wcd_clsh_ctrl {
  11. int state;
  12. int mode;
  13. int flyback_users;
  14. int buck_users;
  15. int clsh_users;
  16. int codec_version;
  17. struct snd_soc_component *comp;
  18. };
  19. /* Class-H registers for codecs from and above WCD9335 */
  20. #define WCD9XXX_A_CDC_RX0_RX_PATH_CFG0 WCD9335_REG(0xB, 0x42)
  21. #define WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK BIT(6)
  22. #define WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE BIT(6)
  23. #define WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE 0
  24. #define WCD9XXX_A_CDC_RX1_RX_PATH_CFG0 WCD9335_REG(0xB, 0x56)
  25. #define WCD9XXX_A_CDC_RX2_RX_PATH_CFG0 WCD9335_REG(0xB, 0x6A)
  26. #define WCD9XXX_A_CDC_CLSH_K1_MSB WCD9335_REG(0xC, 0x08)
  27. #define WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK GENMASK(3, 0)
  28. #define WCD9XXX_A_CDC_CLSH_K1_LSB WCD9335_REG(0xC, 0x09)
  29. #define WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK GENMASK(7, 0)
  30. #define WCD9XXX_A_ANA_RX_SUPPLIES WCD9335_REG(0x6, 0x08)
  31. #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK BIT(1)
  32. #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H 0
  33. #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB BIT(1)
  34. #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK BIT(2)
  35. #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA BIT(2)
  36. #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT 0
  37. #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK BIT(3)
  38. #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA BIT(3)
  39. #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT 0
  40. #define WCD9XXX_A_ANA_RX_VNEG_EN_MASK BIT(6)
  41. #define WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT 6
  42. #define WCD9XXX_A_ANA_RX_VNEG_ENABLE BIT(6)
  43. #define WCD9XXX_A_ANA_RX_VNEG_DISABLE 0
  44. #define WCD9XXX_A_ANA_RX_VPOS_EN_MASK BIT(7)
  45. #define WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT 7
  46. #define WCD9XXX_A_ANA_RX_VPOS_ENABLE BIT(7)
  47. #define WCD9XXX_A_ANA_RX_VPOS_DISABLE 0
  48. #define WCD9XXX_A_ANA_HPH WCD9335_REG(0x6, 0x09)
  49. #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK GENMASK(3, 2)
  50. #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA 0x08
  51. #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP 0x04
  52. #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL 0x0
  53. #define WCD9XXX_A_CDC_CLSH_CRC WCD9335_REG(0xC, 0x01)
  54. #define WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK BIT(0)
  55. #define WCD9XXX_A_CDC_CLSH_CRC_CLK_ENABLE BIT(0)
  56. #define WCD9XXX_A_CDC_CLSH_CRC_CLK_DISABLE 0
  57. #define WCD9XXX_FLYBACK_EN WCD9335_REG(0x6, 0xA4)
  58. #define WCD9XXX_FLYBACK_EN_DELAY_SEL_MASK GENMASK(6, 5)
  59. #define WCD9XXX_FLYBACK_EN_DELAY_26P25_US 0x40
  60. #define WCD9XXX_FLYBACK_EN_RESET_BY_EXT_MASK BIT(4)
  61. #define WCD9XXX_FLYBACK_EN_PWDN_WITHOUT_DELAY BIT(4)
  62. #define WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY 0
  63. #define WCD9XXX_RX_BIAS_FLYB_BUFF WCD9335_REG(0x6, 0xC7)
  64. #define WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4)
  65. #define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(3, 0)
  66. #define WCD9XXX_HPH_L_EN WCD9335_REG(0x6, 0xD3)
  67. #define WCD9XXX_HPH_CONST_SEL_L_MASK GENMASK(7, 3)
  68. #define WCD9XXX_HPH_CONST_SEL_BYPASS 0
  69. #define WCD9XXX_HPH_CONST_SEL_LP_PATH 0x40
  70. #define WCD9XXX_HPH_CONST_SEL_HQ_PATH 0x80
  71. #define WCD9XXX_HPH_R_EN WCD9335_REG(0x6, 0xD6)
  72. #define WCD9XXX_HPH_REFBUFF_UHQA_CTL WCD9335_REG(0x6, 0xDD)
  73. #define WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK GENMASK(2, 0)
  74. #define WCD9XXX_CLASSH_CTRL_VCL_2 WCD9335_REG(0x6, 0x9B)
  75. #define WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK GENMASK(5, 4)
  76. #define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM 0x20
  77. #define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM 0x0
  78. #define WCD9XXX_CDC_RX1_RX_PATH_CTL WCD9335_REG(0xB, 0x55)
  79. #define WCD9XXX_CDC_RX2_RX_PATH_CTL WCD9335_REG(0xB, 0x69)
  80. #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL WCD9335_REG(0xD, 0x41)
  81. #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_EN_MASK BIT(0)
  82. #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_11P3_EN_MASK BIT(1)
  83. #define WCD9XXX_CLASSH_CTRL_CCL_1 WCD9335_REG(0x6, 0x9C)
  84. #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK GENMASK(7, 4)
  85. #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50
  86. #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30
  87. #define CLSH_REQ_ENABLE true
  88. #define CLSH_REQ_DISABLE false
  89. #define WCD_USLEEP_RANGE 50
  90. enum {
  91. DAC_GAIN_0DB = 0,
  92. DAC_GAIN_0P2DB,
  93. DAC_GAIN_0P4DB,
  94. DAC_GAIN_0P6DB,
  95. DAC_GAIN_0P8DB,
  96. DAC_GAIN_M0P2DB,
  97. DAC_GAIN_M0P4DB,
  98. DAC_GAIN_M0P6DB,
  99. };
  100. static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl,
  101. bool enable)
  102. {
  103. struct snd_soc_component *comp = ctrl->comp;
  104. if ((enable && ++ctrl->clsh_users == 1) ||
  105. (!enable && --ctrl->clsh_users == 0))
  106. snd_soc_component_update_bits(comp, WCD9XXX_A_CDC_CLSH_CRC,
  107. WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK,
  108. enable);
  109. if (ctrl->clsh_users < 0)
  110. ctrl->clsh_users = 0;
  111. }
  112. static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp)
  113. {
  114. return snd_soc_component_read(comp, WCD9XXX_A_CDC_CLSH_CRC) &
  115. WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK;
  116. }
  117. static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp,
  118. int mode)
  119. {
  120. /* set to HIFI */
  121. if (mode == CLS_H_HIFI)
  122. snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
  123. WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK,
  124. WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA);
  125. else
  126. snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
  127. WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK,
  128. WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT);
  129. }
  130. static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp,
  131. int mode)
  132. {
  133. /* set to HIFI */
  134. if (mode == CLS_H_HIFI)
  135. snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
  136. WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK,
  137. WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA);
  138. else
  139. snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
  140. WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK,
  141. WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT);
  142. }
  143. static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl,
  144. int mode,
  145. bool enable)
  146. {
  147. struct snd_soc_component *comp = ctrl->comp;
  148. /* enable/disable buck */
  149. if ((enable && (++ctrl->buck_users == 1)) ||
  150. (!enable && (--ctrl->buck_users == 0)))
  151. snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
  152. WCD9XXX_A_ANA_RX_VPOS_EN_MASK,
  153. enable << WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT);
  154. /*
  155. * 500us sleep is required after buck enable/disable
  156. * as per HW requirement
  157. */
  158. usleep_range(500, 500 + WCD_USLEEP_RANGE);
  159. }
  160. static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl,
  161. int mode,
  162. bool enable)
  163. {
  164. struct snd_soc_component *comp = ctrl->comp;
  165. /* enable/disable flyback */
  166. if ((enable && (++ctrl->flyback_users == 1)) ||
  167. (!enable && (--ctrl->flyback_users == 0))) {
  168. snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
  169. WCD9XXX_A_ANA_RX_VNEG_EN_MASK,
  170. enable << WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT);
  171. /* 100usec delay is needed as per HW requirement */
  172. usleep_range(100, 110);
  173. }
  174. /*
  175. * 500us sleep is required after flyback enable/disable
  176. * as per HW requirement
  177. */
  178. usleep_range(500, 500 + WCD_USLEEP_RANGE);
  179. }
  180. static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode)
  181. {
  182. struct snd_soc_component *comp = ctrl->comp;
  183. int val = 0;
  184. switch (mode) {
  185. case CLS_H_NORMAL:
  186. case CLS_AB:
  187. val = WCD9XXX_HPH_CONST_SEL_BYPASS;
  188. break;
  189. case CLS_H_HIFI:
  190. val = WCD9XXX_HPH_CONST_SEL_HQ_PATH;
  191. break;
  192. case CLS_H_LP:
  193. val = WCD9XXX_HPH_CONST_SEL_LP_PATH;
  194. break;
  195. }
  196. snd_soc_component_update_bits(comp, WCD9XXX_HPH_L_EN,
  197. WCD9XXX_HPH_CONST_SEL_L_MASK,
  198. val);
  199. snd_soc_component_update_bits(comp, WCD9XXX_HPH_R_EN,
  200. WCD9XXX_HPH_CONST_SEL_L_MASK,
  201. val);
  202. }
  203. static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp,
  204. int mode)
  205. {
  206. int val = 0, gain = 0, res_val;
  207. int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
  208. res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM;
  209. switch (mode) {
  210. case CLS_H_NORMAL:
  211. res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM;
  212. val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL;
  213. gain = DAC_GAIN_0DB;
  214. ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
  215. break;
  216. case CLS_AB:
  217. val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL;
  218. gain = DAC_GAIN_0DB;
  219. ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
  220. break;
  221. case CLS_H_HIFI:
  222. val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA;
  223. gain = DAC_GAIN_M0P2DB;
  224. ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
  225. break;
  226. case CLS_H_LP:
  227. val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP;
  228. ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA;
  229. break;
  230. }
  231. snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_HPH,
  232. WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val);
  233. snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_VCL_2,
  234. WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK,
  235. res_val);
  236. if (mode != CLS_H_LP)
  237. snd_soc_component_update_bits(comp,
  238. WCD9XXX_HPH_REFBUFF_UHQA_CTL,
  239. WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK,
  240. gain);
  241. snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_CCL_1,
  242. WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK,
  243. ipeak);
  244. }
  245. static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp,
  246. int mode)
  247. {
  248. snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF,
  249. WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, 0x0A);
  250. snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF,
  251. WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, 0x0A);
  252. /* Sleep needed to avoid click and pop as per HW requirement */
  253. usleep_range(100, 110);
  254. }
  255. static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp,
  256. int mode)
  257. {
  258. if (mode == CLS_AB)
  259. snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
  260. WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK,
  261. WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB);
  262. else
  263. snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
  264. WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK,
  265. WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H);
  266. }
  267. static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state,
  268. bool is_enable, int mode)
  269. {
  270. struct snd_soc_component *comp = ctrl->comp;
  271. if (mode != CLS_AB) {
  272. dev_err(comp->dev, "%s: LO cannot be in this mode: %d\n",
  273. __func__, mode);
  274. return;
  275. }
  276. if (is_enable) {
  277. wcd_clsh_set_buck_regulator_mode(comp, mode);
  278. wcd_clsh_set_buck_mode(comp, mode);
  279. wcd_clsh_set_flyback_mode(comp, mode);
  280. wcd_clsh_flyback_ctrl(ctrl, mode, true);
  281. wcd_clsh_set_flyback_current(comp, mode);
  282. wcd_clsh_buck_ctrl(ctrl, mode, true);
  283. } else {
  284. wcd_clsh_buck_ctrl(ctrl, mode, false);
  285. wcd_clsh_flyback_ctrl(ctrl, mode, false);
  286. wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
  287. wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
  288. wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
  289. }
  290. }
  291. static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state,
  292. bool is_enable, int mode)
  293. {
  294. struct snd_soc_component *comp = ctrl->comp;
  295. if (mode == CLS_H_NORMAL) {
  296. dev_err(comp->dev, "%s: Normal mode not applicable for hph_r\n",
  297. __func__);
  298. return;
  299. }
  300. if (is_enable) {
  301. if (mode != CLS_AB) {
  302. wcd_enable_clsh_block(ctrl, true);
  303. /*
  304. * These K1 values depend on the Headphone Impedance
  305. * For now it is assumed to be 16 ohm
  306. */
  307. snd_soc_component_update_bits(comp,
  308. WCD9XXX_A_CDC_CLSH_K1_MSB,
  309. WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK,
  310. 0x00);
  311. snd_soc_component_update_bits(comp,
  312. WCD9XXX_A_CDC_CLSH_K1_LSB,
  313. WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK,
  314. 0xC0);
  315. snd_soc_component_update_bits(comp,
  316. WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
  317. WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
  318. WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
  319. }
  320. wcd_clsh_set_buck_regulator_mode(comp, mode);
  321. wcd_clsh_set_flyback_mode(comp, mode);
  322. wcd_clsh_flyback_ctrl(ctrl, mode, true);
  323. wcd_clsh_set_flyback_current(comp, mode);
  324. wcd_clsh_set_buck_mode(comp, mode);
  325. wcd_clsh_buck_ctrl(ctrl, mode, true);
  326. wcd_clsh_set_hph_mode(comp, mode);
  327. wcd_clsh_set_gain_path(ctrl, mode);
  328. } else {
  329. wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL);
  330. if (mode != CLS_AB) {
  331. snd_soc_component_update_bits(comp,
  332. WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
  333. WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
  334. WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE);
  335. wcd_enable_clsh_block(ctrl, false);
  336. }
  337. /* buck and flyback set to default mode and disable */
  338. wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false);
  339. wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false);
  340. wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
  341. wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
  342. wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
  343. }
  344. }
  345. static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state,
  346. bool is_enable, int mode)
  347. {
  348. struct snd_soc_component *comp = ctrl->comp;
  349. if (mode == CLS_H_NORMAL) {
  350. dev_err(comp->dev, "%s: Normal mode not applicable for hph_l\n",
  351. __func__);
  352. return;
  353. }
  354. if (is_enable) {
  355. if (mode != CLS_AB) {
  356. wcd_enable_clsh_block(ctrl, true);
  357. /*
  358. * These K1 values depend on the Headphone Impedance
  359. * For now it is assumed to be 16 ohm
  360. */
  361. snd_soc_component_update_bits(comp,
  362. WCD9XXX_A_CDC_CLSH_K1_MSB,
  363. WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK,
  364. 0x00);
  365. snd_soc_component_update_bits(comp,
  366. WCD9XXX_A_CDC_CLSH_K1_LSB,
  367. WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK,
  368. 0xC0);
  369. snd_soc_component_update_bits(comp,
  370. WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
  371. WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
  372. WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
  373. }
  374. wcd_clsh_set_buck_regulator_mode(comp, mode);
  375. wcd_clsh_set_flyback_mode(comp, mode);
  376. wcd_clsh_flyback_ctrl(ctrl, mode, true);
  377. wcd_clsh_set_flyback_current(comp, mode);
  378. wcd_clsh_set_buck_mode(comp, mode);
  379. wcd_clsh_buck_ctrl(ctrl, mode, true);
  380. wcd_clsh_set_hph_mode(comp, mode);
  381. wcd_clsh_set_gain_path(ctrl, mode);
  382. } else {
  383. wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL);
  384. if (mode != CLS_AB) {
  385. snd_soc_component_update_bits(comp,
  386. WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
  387. WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
  388. WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE);
  389. wcd_enable_clsh_block(ctrl, false);
  390. }
  391. /* set buck and flyback to Default Mode */
  392. wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false);
  393. wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false);
  394. wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
  395. wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
  396. wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
  397. }
  398. }
  399. static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state,
  400. bool is_enable, int mode)
  401. {
  402. struct snd_soc_component *comp = ctrl->comp;
  403. if (mode != CLS_H_NORMAL) {
  404. dev_err(comp->dev, "%s: mode: %d cannot be used for EAR\n",
  405. __func__, mode);
  406. return;
  407. }
  408. if (is_enable) {
  409. wcd_enable_clsh_block(ctrl, true);
  410. snd_soc_component_update_bits(comp,
  411. WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
  412. WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
  413. WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
  414. wcd_clsh_set_buck_mode(comp, mode);
  415. wcd_clsh_set_flyback_mode(comp, mode);
  416. wcd_clsh_flyback_ctrl(ctrl, mode, true);
  417. wcd_clsh_set_flyback_current(comp, mode);
  418. wcd_clsh_buck_ctrl(ctrl, mode, true);
  419. } else {
  420. snd_soc_component_update_bits(comp,
  421. WCD9XXX_A_CDC_RX0_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. wcd_clsh_buck_ctrl(ctrl, mode, false);
  426. wcd_clsh_flyback_ctrl(ctrl, mode, false);
  427. wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
  428. wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
  429. }
  430. }
  431. static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state,
  432. bool is_enable, int mode)
  433. {
  434. switch (req_state) {
  435. case WCD_CLSH_STATE_EAR:
  436. wcd_clsh_state_ear(ctrl, req_state, is_enable, mode);
  437. break;
  438. case WCD_CLSH_STATE_HPHL:
  439. wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode);
  440. break;
  441. case WCD_CLSH_STATE_HPHR:
  442. wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode);
  443. break;
  444. break;
  445. case WCD_CLSH_STATE_LO:
  446. wcd_clsh_state_lo(ctrl, req_state, is_enable, mode);
  447. break;
  448. default:
  449. break;
  450. }
  451. return 0;
  452. }
  453. /*
  454. * Function: wcd_clsh_is_state_valid
  455. * Params: state
  456. * Description:
  457. * Provides information on valid states of Class H configuration
  458. */
  459. static bool wcd_clsh_is_state_valid(int state)
  460. {
  461. switch (state) {
  462. case WCD_CLSH_STATE_IDLE:
  463. case WCD_CLSH_STATE_EAR:
  464. case WCD_CLSH_STATE_HPHL:
  465. case WCD_CLSH_STATE_HPHR:
  466. case WCD_CLSH_STATE_LO:
  467. return true;
  468. default:
  469. return false;
  470. };
  471. }
  472. /*
  473. * Function: wcd_clsh_fsm
  474. * Params: ctrl, req_state, req_type, clsh_event
  475. * Description:
  476. * This function handles PRE DAC and POST DAC conditions of different devices
  477. * and updates class H configuration of different combination of devices
  478. * based on validity of their states. ctrl will contain current
  479. * class h state information
  480. */
  481. int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl,
  482. enum wcd_clsh_event clsh_event,
  483. int nstate,
  484. enum wcd_clsh_mode mode)
  485. {
  486. struct snd_soc_component *comp = ctrl->comp;
  487. if (nstate == ctrl->state)
  488. return 0;
  489. if (!wcd_clsh_is_state_valid(nstate)) {
  490. dev_err(comp->dev, "Class-H not a valid new state:\n");
  491. return -EINVAL;
  492. }
  493. switch (clsh_event) {
  494. case WCD_CLSH_EVENT_PRE_DAC:
  495. _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_ENABLE, mode);
  496. break;
  497. case WCD_CLSH_EVENT_POST_PA:
  498. _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode);
  499. break;
  500. }
  501. ctrl->state = nstate;
  502. ctrl->mode = mode;
  503. return 0;
  504. }
  505. int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl)
  506. {
  507. return ctrl->state;
  508. }
  509. struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp,
  510. int version)
  511. {
  512. struct wcd_clsh_ctrl *ctrl;
  513. ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
  514. if (!ctrl)
  515. return ERR_PTR(-ENOMEM);
  516. ctrl->state = WCD_CLSH_STATE_IDLE;
  517. ctrl->comp = comp;
  518. return ctrl;
  519. }
  520. void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl)
  521. {
  522. kfree(ctrl);
  523. }