wcd-clsh.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/module.h>
  6. #include <linux/slab.h>
  7. #include <sound/soc.h>
  8. #include <linux/kernel.h>
  9. #include <linux/delay.h>
  10. #include <asoc/wcd9xxx_registers.h>
  11. #include "wcd-clsh.h"
  12. #define WCD_USLEEP_RANGE 50
  13. static void (*clsh_state_fp[NUM_CLSH_STATES])(struct snd_soc_codec *,
  14. struct wcd_clsh_cdc_info *,
  15. u8 req_state, bool en, int mode);
  16. static const char *mode_to_str(int mode)
  17. {
  18. switch (mode) {
  19. case CLS_H_NORMAL:
  20. return WCD_CLSH_STRINGIFY(CLS_H_NORMAL);
  21. case CLS_H_HIFI:
  22. return WCD_CLSH_STRINGIFY(CLS_H_HIFI);
  23. case CLS_H_LOHIFI:
  24. return WCD_CLSH_STRINGIFY(CLS_H_LOHIFI);
  25. case CLS_H_LP:
  26. return WCD_CLSH_STRINGIFY(CLS_H_LP);
  27. case CLS_H_ULP:
  28. return WCD_CLSH_STRINGIFY(CLS_H_ULP);
  29. case CLS_AB:
  30. return WCD_CLSH_STRINGIFY(CLS_AB);
  31. case CLS_AB_HIFI:
  32. return WCD_CLSH_STRINGIFY(CLS_AB_HIFI);
  33. default:
  34. return WCD_CLSH_STRINGIFY(CLS_H_INVALID);
  35. };
  36. }
  37. static const char *state_to_str(u8 state, char *buf, size_t buflen)
  38. {
  39. int i;
  40. int cnt = 0;
  41. /*
  42. * This array of strings should match with enum wcd_clsh_state_bit.
  43. */
  44. static const char *const states[] = {
  45. "STATE_EAR",
  46. "STATE_HPH_L",
  47. "STATE_HPH_R",
  48. "STATE_AUX",
  49. };
  50. if (state == WCD_CLSH_STATE_IDLE) {
  51. snprintf(buf, buflen, "[STATE_IDLE]");
  52. goto done;
  53. }
  54. buf[0] = '\0';
  55. for (i = 0; i < ARRAY_SIZE(states); i++) {
  56. if (!(state & (1 << i)))
  57. continue;
  58. cnt = snprintf(buf, buflen - cnt - 1, "%s%s%s", buf,
  59. buf[0] == '\0' ? "[" : "|",
  60. states[i]);
  61. }
  62. if (cnt > 0)
  63. strlcat(buf + cnt, "]", buflen);
  64. done:
  65. if (buf[0] == '\0')
  66. snprintf(buf, buflen, "[STATE_UNKNOWN]");
  67. return buf;
  68. }
  69. static inline int wcd_clsh_get_int_mode(struct wcd_clsh_cdc_info *clsh_d,
  70. int clsh_state)
  71. {
  72. int mode;
  73. if ((clsh_state != WCD_CLSH_STATE_EAR) &&
  74. (clsh_state != WCD_CLSH_STATE_HPHL) &&
  75. (clsh_state != WCD_CLSH_STATE_HPHR) &&
  76. (clsh_state != WCD_CLSH_STATE_AUX))
  77. mode = CLS_NONE;
  78. else
  79. mode = clsh_d->interpolator_modes[ffs(clsh_state)];
  80. return mode;
  81. }
  82. static inline void wcd_clsh_set_int_mode(struct wcd_clsh_cdc_info *clsh_d,
  83. int clsh_state, int mode)
  84. {
  85. if ((clsh_state != WCD_CLSH_STATE_EAR) &&
  86. (clsh_state != WCD_CLSH_STATE_HPHL) &&
  87. (clsh_state != WCD_CLSH_STATE_HPHR) &&
  88. (clsh_state != WCD_CLSH_STATE_AUX))
  89. return;
  90. clsh_d->interpolator_modes[ffs(clsh_state)] = mode;
  91. }
  92. static inline void wcd_clsh_set_buck_mode(struct snd_soc_codec *codec,
  93. int mode)
  94. {
  95. if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
  96. mode == CLS_AB_HIFI)
  97. snd_soc_update_bits(codec, WCD9XXX_ANA_RX_SUPPLIES,
  98. 0x08, 0x08); /* set to HIFI */
  99. else
  100. snd_soc_update_bits(codec, WCD9XXX_ANA_RX_SUPPLIES,
  101. 0x08, 0x00); /* set to default */
  102. }
  103. static inline void wcd_clsh_set_flyback_mode(struct snd_soc_codec *codec,
  104. int mode)
  105. {
  106. if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
  107. mode == CLS_AB_HIFI) {
  108. snd_soc_update_bits(codec, WCD9XXX_ANA_RX_SUPPLIES,
  109. 0x04, 0x04);
  110. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_4,
  111. 0xF0, 0x80);
  112. } else {
  113. snd_soc_update_bits(codec, WCD9XXX_ANA_RX_SUPPLIES,
  114. 0x04, 0x00); /* set to Default */
  115. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_4,
  116. 0xF0, 0x70);
  117. }
  118. }
  119. static inline void wcd_clsh_force_iq_ctl(struct snd_soc_codec *codec,
  120. int mode, bool enable)
  121. {
  122. if (enable) {
  123. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
  124. 0xE0, 0xA0);
  125. /* 100usec delay is needed as per HW requirement */
  126. usleep_range(100, 110);
  127. snd_soc_update_bits(codec, WCD9XXX_CLASSH_MODE_3,
  128. 0x02, 0x02);
  129. snd_soc_update_bits(codec, WCD9XXX_CLASSH_MODE_2,
  130. 0xFF, 0x1C);
  131. if (mode == CLS_H_LOHIFI) {
  132. snd_soc_update_bits(codec, WCD9XXX_HPH_NEW_INT_PA_MISC2,
  133. 0x20, 0x20);
  134. snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_HPH_LOWPOWER,
  135. 0xF0, 0xC0);
  136. snd_soc_update_bits(codec, WCD9XXX_HPH_PA_CTL1,
  137. 0x0E, 0x02);
  138. }
  139. } else {
  140. snd_soc_update_bits(codec, WCD9XXX_HPH_NEW_INT_PA_MISC2,
  141. 0x20, 0x00);
  142. snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_HPH_LOWPOWER,
  143. 0xF0, 0x80);
  144. snd_soc_update_bits(codec, WCD9XXX_HPH_PA_CTL1,
  145. 0x0E, 0x06);
  146. }
  147. }
  148. static void wcd_clsh_buck_ctrl(struct snd_soc_codec *codec,
  149. struct wcd_clsh_cdc_info *clsh_d,
  150. int mode,
  151. bool enable)
  152. {
  153. /* enable/disable buck */
  154. if ((enable && (++clsh_d->buck_users == 1)) ||
  155. (!enable && (--clsh_d->buck_users == 0))) {
  156. snd_soc_update_bits(codec, WCD9XXX_ANA_RX_SUPPLIES,
  157. (1 << 7), (enable << 7));
  158. /*
  159. * 500us sleep is required after buck enable/disable
  160. * as per HW requirement
  161. */
  162. usleep_range(500, 510);
  163. if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP ||
  164. mode == CLS_H_HIFI || mode == CLS_H_LP)
  165. snd_soc_update_bits(codec, WCD9XXX_CLASSH_MODE_3,
  166. 0x02, 0x00);
  167. snd_soc_update_bits(codec, WCD9XXX_CLASSH_MODE_2, 0xFF, 0x3A);
  168. /* 500usec delay is needed as per HW requirement */
  169. usleep_range(500, 500 + WCD_USLEEP_RANGE);
  170. }
  171. dev_dbg(codec->dev, "%s: buck_users %d, enable %d, mode: %s\n",
  172. __func__, clsh_d->buck_users, enable, mode_to_str(mode));
  173. }
  174. static void wcd_clsh_flyback_ctrl(struct snd_soc_codec *codec,
  175. struct wcd_clsh_cdc_info *clsh_d,
  176. int mode,
  177. bool enable)
  178. {
  179. /* enable/disable flyback */
  180. if ((enable && (++clsh_d->flyback_users == 1)) ||
  181. (!enable && (--clsh_d->flyback_users == 0))) {
  182. snd_soc_update_bits(codec, WCD9XXX_ANA_RX_SUPPLIES,
  183. (1 << 6), (enable << 6));
  184. /*
  185. * 100us sleep is required after flyback enable/disable
  186. * as per HW requirement
  187. */
  188. usleep_range(100, 110);
  189. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
  190. 0xE0, 0xE0);
  191. /* 500usec delay is needed as per HW requirement */
  192. usleep_range(500, 500 + WCD_USLEEP_RANGE);
  193. }
  194. dev_dbg(codec->dev, "%s: flyback_users %d, enable %d, mode: %s\n",
  195. __func__, clsh_d->flyback_users, enable, mode_to_str(mode));
  196. }
  197. static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec,
  198. int mode)
  199. {
  200. u8 val = 0;
  201. switch (mode) {
  202. case CLS_H_NORMAL:
  203. case CLS_H_LOHIFI:
  204. val = 0x00;
  205. break;
  206. case CLS_AB:
  207. case CLS_H_ULP:
  208. val = 0x0C;
  209. break;
  210. case CLS_AB_HIFI:
  211. case CLS_H_HIFI:
  212. val = 0x08;
  213. break;
  214. case CLS_H_LP:
  215. val = 0x04;
  216. break;
  217. default:
  218. dev_err(codec->dev, "%s:Invalid mode %d\n", __func__, mode);
  219. return;
  220. };
  221. snd_soc_update_bits(codec, WCD9XXX_ANA_HPH, 0x0C, val);
  222. }
  223. static void wcd_clsh_set_flyback_current(struct snd_soc_codec *codec, int mode)
  224. {
  225. snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_FLYB_BUFF, 0x0F, 0x0A);
  226. snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_FLYB_BUFF, 0xF0, 0xA0);
  227. /* Sleep needed to avoid click and pop as per HW requirement */
  228. usleep_range(100, 110);
  229. }
  230. static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_codec *codec,
  231. int mode)
  232. {
  233. snd_soc_update_bits(codec, WCD9XXX_ANA_RX_SUPPLIES,
  234. 0x02, 0x00);
  235. }
  236. static void wcd_clsh_state_ear_aux(struct snd_soc_codec *codec,
  237. struct wcd_clsh_cdc_info *clsh_d,
  238. u8 req_state, bool is_enable, int mode)
  239. {
  240. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  241. is_enable ? "enable" : "disable");
  242. }
  243. static void wcd_clsh_state_hph_aux(struct snd_soc_codec *codec,
  244. struct wcd_clsh_cdc_info *clsh_d,
  245. u8 req_state, bool is_enable, int mode)
  246. {
  247. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  248. is_enable ? "enable" : "disable");
  249. }
  250. static void wcd_clsh_state_hph_ear(struct snd_soc_codec *codec,
  251. struct wcd_clsh_cdc_info *clsh_d,
  252. u8 req_state, bool is_enable, int mode)
  253. {
  254. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  255. is_enable ? "enable" : "disable");
  256. }
  257. static void wcd_clsh_state_hph_st(struct snd_soc_codec *codec,
  258. struct wcd_clsh_cdc_info *clsh_d,
  259. u8 req_state, bool is_enable, int mode)
  260. {
  261. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  262. is_enable ? "enable" : "disable");
  263. }
  264. static void wcd_clsh_state_hph_r(struct snd_soc_codec *codec,
  265. struct wcd_clsh_cdc_info *clsh_d,
  266. u8 req_state, bool is_enable, int mode)
  267. {
  268. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  269. is_enable ? "enable" : "disable");
  270. if (mode == CLS_H_NORMAL) {
  271. dev_dbg(codec->dev, "%s: Normal mode not applicable for hph_r\n",
  272. __func__);
  273. return;
  274. }
  275. if (is_enable) {
  276. wcd_clsh_set_buck_regulator_mode(codec, mode);
  277. wcd_clsh_set_flyback_mode(codec, mode);
  278. wcd_clsh_force_iq_ctl(codec, mode, true);
  279. wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
  280. wcd_clsh_set_flyback_current(codec, mode);
  281. wcd_clsh_set_buck_mode(codec, mode);
  282. wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
  283. wcd_clsh_set_hph_mode(codec, mode);
  284. } else {
  285. wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);
  286. /* buck and flyback set to default mode and disable */
  287. wcd_clsh_flyback_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
  288. wcd_clsh_buck_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
  289. wcd_clsh_force_iq_ctl(codec, CLS_H_NORMAL, false);
  290. wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
  291. wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
  292. }
  293. }
  294. static void wcd_clsh_state_hph_l(struct snd_soc_codec *codec,
  295. struct wcd_clsh_cdc_info *clsh_d,
  296. u8 req_state, bool is_enable, int mode)
  297. {
  298. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  299. is_enable ? "enable" : "disable");
  300. if (mode == CLS_H_NORMAL) {
  301. dev_dbg(codec->dev, "%s: Normal mode not applicable for hph_l\n",
  302. __func__);
  303. return;
  304. }
  305. if (is_enable) {
  306. wcd_clsh_set_buck_regulator_mode(codec, mode);
  307. wcd_clsh_set_flyback_mode(codec, mode);
  308. wcd_clsh_force_iq_ctl(codec, mode, true);
  309. wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
  310. wcd_clsh_set_flyback_current(codec, mode);
  311. wcd_clsh_set_buck_mode(codec, mode);
  312. wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
  313. wcd_clsh_set_hph_mode(codec, mode);
  314. } else {
  315. wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);
  316. /* set buck and flyback to Default Mode */
  317. wcd_clsh_flyback_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
  318. wcd_clsh_buck_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
  319. wcd_clsh_force_iq_ctl(codec, CLS_H_NORMAL, false);
  320. wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
  321. wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
  322. }
  323. }
  324. static void wcd_clsh_state_aux(struct snd_soc_codec *codec,
  325. struct wcd_clsh_cdc_info *clsh_d,
  326. u8 req_state, bool is_enable, int mode)
  327. {
  328. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  329. is_enable ? "enable" : "disable");
  330. if (is_enable) {
  331. wcd_clsh_set_buck_mode(codec, mode);
  332. wcd_clsh_set_flyback_mode(codec, mode);
  333. wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
  334. wcd_clsh_set_flyback_current(codec, mode);
  335. wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
  336. } else {
  337. wcd_clsh_buck_ctrl(codec, clsh_d, mode, false);
  338. wcd_clsh_flyback_ctrl(codec, clsh_d, mode, false);
  339. wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
  340. wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
  341. }
  342. }
  343. static void wcd_clsh_state_ear(struct snd_soc_codec *codec,
  344. struct wcd_clsh_cdc_info *clsh_d,
  345. u8 req_state, bool is_enable, int mode)
  346. {
  347. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  348. is_enable ? "enable" : "disable");
  349. if (is_enable) {
  350. wcd_clsh_set_buck_regulator_mode(codec, mode);
  351. wcd_clsh_set_flyback_mode(codec, mode);
  352. wcd_clsh_force_iq_ctl(codec, mode, true);
  353. wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
  354. wcd_clsh_set_flyback_current(codec, mode);
  355. wcd_clsh_set_buck_mode(codec, mode);
  356. wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
  357. wcd_clsh_set_hph_mode(codec, mode);
  358. } else {
  359. wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);
  360. /* set buck and flyback to Default Mode */
  361. wcd_clsh_flyback_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
  362. wcd_clsh_buck_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
  363. wcd_clsh_force_iq_ctl(codec, CLS_H_NORMAL, false);
  364. wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
  365. wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
  366. }
  367. }
  368. static void wcd_clsh_state_err(struct snd_soc_codec *codec,
  369. struct wcd_clsh_cdc_info *clsh_d,
  370. u8 req_state, bool is_enable, int mode)
  371. {
  372. char msg[128];
  373. dev_err(codec->dev,
  374. "%s Wrong request for class H state machine requested to %s %s\n",
  375. __func__, is_enable ? "enable" : "disable",
  376. state_to_str(req_state, msg, sizeof(msg)));
  377. }
  378. /*
  379. * Function: wcd_clsh_is_state_valid
  380. * Params: state
  381. * Description:
  382. * Provides information on valid states of Class H configuration
  383. */
  384. static bool wcd_clsh_is_state_valid(u8 state)
  385. {
  386. switch (state) {
  387. case WCD_CLSH_STATE_IDLE:
  388. case WCD_CLSH_STATE_EAR:
  389. case WCD_CLSH_STATE_HPHL:
  390. case WCD_CLSH_STATE_HPHR:
  391. case WCD_CLSH_STATE_HPH_ST:
  392. case WCD_CLSH_STATE_AUX:
  393. case WCD_CLSH_STATE_HPHL_AUX:
  394. case WCD_CLSH_STATE_HPHR_AUX:
  395. case WCD_CLSH_STATE_HPH_ST_AUX:
  396. case WCD_CLSH_STATE_EAR_AUX:
  397. return true;
  398. default:
  399. return false;
  400. };
  401. }
  402. /*
  403. * Function: wcd_cls_h_fsm
  404. * Params: codec, cdc_clsh_d, req_state, req_type, clsh_event
  405. * Description:
  406. * This function handles PRE DAC and POST DAC conditions of different devices
  407. * and updates class H configuration of different combination of devices
  408. * based on validity of their states. cdc_clsh_d will contain current
  409. * class h state information
  410. */
  411. void wcd_cls_h_fsm(struct snd_soc_codec *codec,
  412. struct wcd_clsh_cdc_info *cdc_clsh_d,
  413. u8 clsh_event, u8 req_state,
  414. int int_mode)
  415. {
  416. u8 old_state, new_state;
  417. char msg0[128], msg1[128];
  418. switch (clsh_event) {
  419. case WCD_CLSH_EVENT_PRE_DAC:
  420. old_state = cdc_clsh_d->state;
  421. new_state = old_state | req_state;
  422. if (!wcd_clsh_is_state_valid(new_state)) {
  423. dev_err(codec->dev,
  424. "%s: Class-H not a valid new state: %s\n",
  425. __func__,
  426. state_to_str(new_state, msg0, sizeof(msg0)));
  427. return;
  428. }
  429. if (new_state == old_state) {
  430. dev_err(codec->dev,
  431. "%s: Class-H already in requested state: %s\n",
  432. __func__,
  433. state_to_str(new_state, msg0, sizeof(msg0)));
  434. return;
  435. }
  436. cdc_clsh_d->state = new_state;
  437. wcd_clsh_set_int_mode(cdc_clsh_d, req_state, int_mode);
  438. (*clsh_state_fp[new_state]) (codec, cdc_clsh_d, req_state,
  439. CLSH_REQ_ENABLE, int_mode);
  440. dev_dbg(codec->dev,
  441. "%s: ClassH state transition from %s to %s\n",
  442. __func__, state_to_str(old_state, msg0, sizeof(msg0)),
  443. state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
  444. break;
  445. case WCD_CLSH_EVENT_POST_PA:
  446. old_state = cdc_clsh_d->state;
  447. new_state = old_state & (~req_state);
  448. if (new_state < NUM_CLSH_STATES) {
  449. if (!wcd_clsh_is_state_valid(old_state)) {
  450. dev_err(codec->dev,
  451. "%s:Invalid old state:%s\n",
  452. __func__,
  453. state_to_str(old_state, msg0,
  454. sizeof(msg0)));
  455. return;
  456. }
  457. if (new_state == old_state) {
  458. dev_err(codec->dev,
  459. "%s: Class-H already in requested state: %s\n",
  460. __func__,
  461. state_to_str(new_state, msg0,
  462. sizeof(msg0)));
  463. return;
  464. }
  465. (*clsh_state_fp[old_state]) (codec, cdc_clsh_d,
  466. req_state, CLSH_REQ_DISABLE,
  467. int_mode);
  468. cdc_clsh_d->state = new_state;
  469. wcd_clsh_set_int_mode(cdc_clsh_d, req_state, CLS_NONE);
  470. dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
  471. __func__, state_to_str(old_state, msg0,
  472. sizeof(msg0)),
  473. state_to_str(cdc_clsh_d->state, msg1,
  474. sizeof(msg1)));
  475. }
  476. break;
  477. };
  478. }
  479. EXPORT_SYMBOL(wcd_cls_h_fsm);
  480. /*
  481. * wcd_cls_h_init: Called to init clsh info
  482. *
  483. * @clsh: pointer for clsh state information.
  484. */
  485. void wcd_cls_h_init(struct wcd_clsh_cdc_info *clsh)
  486. {
  487. int i;
  488. clsh->state = WCD_CLSH_STATE_IDLE;
  489. for (i = 0; i < NUM_CLSH_STATES; i++)
  490. clsh_state_fp[i] = wcd_clsh_state_err;
  491. clsh_state_fp[WCD_CLSH_STATE_EAR] = wcd_clsh_state_ear;
  492. clsh_state_fp[WCD_CLSH_STATE_HPHL] = wcd_clsh_state_hph_l;
  493. clsh_state_fp[WCD_CLSH_STATE_HPHR] = wcd_clsh_state_hph_r;
  494. clsh_state_fp[WCD_CLSH_STATE_HPH_ST] = wcd_clsh_state_hph_st;
  495. clsh_state_fp[WCD_CLSH_STATE_AUX] = wcd_clsh_state_aux;
  496. clsh_state_fp[WCD_CLSH_STATE_HPHL_AUX] = wcd_clsh_state_hph_aux;
  497. clsh_state_fp[WCD_CLSH_STATE_HPHR_AUX] = wcd_clsh_state_hph_aux;
  498. clsh_state_fp[WCD_CLSH_STATE_HPH_ST_AUX] =
  499. wcd_clsh_state_hph_aux;
  500. clsh_state_fp[WCD_CLSH_STATE_EAR_AUX] = wcd_clsh_state_ear_aux;
  501. clsh_state_fp[WCD_CLSH_STATE_HPHL_EAR] = wcd_clsh_state_hph_ear;
  502. clsh_state_fp[WCD_CLSH_STATE_HPHR_EAR] = wcd_clsh_state_hph_ear;
  503. clsh_state_fp[WCD_CLSH_STATE_HPH_ST_EAR] = wcd_clsh_state_hph_ear;
  504. /* Set interpolaotr modes to NONE */
  505. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_EAR, CLS_NONE);
  506. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHL, CLS_NONE);
  507. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHR, CLS_NONE);
  508. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_AUX, CLS_NONE);
  509. clsh->flyback_users = 0;
  510. clsh->buck_users = 0;
  511. }
  512. EXPORT_SYMBOL(wcd_cls_h_init);
  513. MODULE_DESCRIPTION("WCD Class-H Driver");
  514. MODULE_LICENSE("GPL v2");