wcd-clsh.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. // SPDX-License-Identifier: GPL-2.0-only
  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 <asoc/wcd-clsh.h>
  12. #define WCD_USLEEP_RANGE 50
  13. static void (*clsh_state_fp[NUM_CLSH_STATES])(struct snd_soc_component *,
  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_component *component,
  93. int mode)
  94. {
  95. if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
  96. mode == CLS_AB_HIFI)
  97. snd_soc_component_update_bits(component,
  98. WCD9XXX_ANA_RX_SUPPLIES,
  99. 0x08, 0x08); /* set to HIFI */
  100. else
  101. snd_soc_component_update_bits(component,
  102. WCD9XXX_ANA_RX_SUPPLIES,
  103. 0x08, 0x00); /* set to default */
  104. }
  105. static inline void wcd_clsh_set_flyback_mode(
  106. struct snd_soc_component *component,
  107. int mode)
  108. {
  109. if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
  110. mode == CLS_AB_HIFI) {
  111. snd_soc_component_update_bits(component,
  112. WCD9XXX_ANA_RX_SUPPLIES,
  113. 0x04, 0x04);
  114. snd_soc_component_update_bits(component,
  115. WCD9XXX_FLYBACK_VNEG_CTRL_4,
  116. 0xF0, 0x80);
  117. } else {
  118. snd_soc_component_update_bits(component,
  119. WCD9XXX_ANA_RX_SUPPLIES,
  120. 0x04, 0x00); /* set to Default */
  121. snd_soc_component_update_bits(component,
  122. WCD9XXX_FLYBACK_VNEG_CTRL_4,
  123. 0xF0, 0x70);
  124. }
  125. }
  126. static inline void wcd_clsh_force_iq_ctl(struct snd_soc_component *component,
  127. int mode, bool enable)
  128. {
  129. if (enable) {
  130. snd_soc_component_update_bits(component,
  131. WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
  132. 0xE0, 0xA0);
  133. /* 100usec delay is needed as per HW requirement */
  134. usleep_range(100, 110);
  135. snd_soc_component_update_bits(component,
  136. WCD9XXX_CLASSH_MODE_3,
  137. 0x02, 0x02);
  138. snd_soc_component_update_bits(component,
  139. WCD9XXX_CLASSH_MODE_2,
  140. 0xFF, 0x1C);
  141. if (mode == CLS_H_LOHIFI) {
  142. snd_soc_component_update_bits(component,
  143. WCD9XXX_HPH_NEW_INT_PA_MISC2,
  144. 0x20, 0x20);
  145. snd_soc_component_update_bits(component,
  146. WCD9XXX_RX_BIAS_HPH_LOWPOWER,
  147. 0xF0, 0xC0);
  148. snd_soc_component_update_bits(component,
  149. WCD9XXX_HPH_PA_CTL1,
  150. 0x0E, 0x02);
  151. }
  152. } else {
  153. snd_soc_component_update_bits(component,
  154. WCD9XXX_HPH_NEW_INT_PA_MISC2,
  155. 0x20, 0x00);
  156. snd_soc_component_update_bits(component,
  157. WCD9XXX_RX_BIAS_HPH_LOWPOWER,
  158. 0xF0, 0x80);
  159. snd_soc_component_update_bits(component,
  160. WCD9XXX_HPH_PA_CTL1,
  161. 0x0E, 0x06);
  162. }
  163. }
  164. static void wcd_clsh_buck_ctrl(struct snd_soc_component *component,
  165. struct wcd_clsh_cdc_info *clsh_d,
  166. int mode,
  167. bool enable)
  168. {
  169. /* enable/disable buck */
  170. if ((enable && (++clsh_d->buck_users == 1)) ||
  171. (!enable && (--clsh_d->buck_users == 0))) {
  172. snd_soc_component_update_bits(component,
  173. WCD9XXX_ANA_RX_SUPPLIES,
  174. (1 << 7), (enable << 7));
  175. /*
  176. * 500us sleep is required after buck enable/disable
  177. * as per HW requirement
  178. */
  179. usleep_range(500, 510);
  180. if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP ||
  181. mode == CLS_H_HIFI || mode == CLS_H_LP)
  182. snd_soc_component_update_bits(component,
  183. WCD9XXX_CLASSH_MODE_3,
  184. 0x02, 0x00);
  185. snd_soc_component_update_bits(component,
  186. WCD9XXX_CLASSH_MODE_2,
  187. 0xFF, 0x3A);
  188. /* 500usec delay is needed as per HW requirement */
  189. usleep_range(500, 500 + WCD_USLEEP_RANGE);
  190. }
  191. dev_dbg(component->dev, "%s: buck_users %d, enable %d, mode: %s\n",
  192. __func__, clsh_d->buck_users, enable, mode_to_str(mode));
  193. }
  194. static void wcd_clsh_flyback_ctrl(struct snd_soc_component *component,
  195. struct wcd_clsh_cdc_info *clsh_d,
  196. int mode,
  197. bool enable)
  198. {
  199. /* enable/disable flyback */
  200. if ((enable && (++clsh_d->flyback_users == 1)) ||
  201. (!enable && (--clsh_d->flyback_users == 0))) {
  202. snd_soc_component_update_bits(component,
  203. WCD9XXX_ANA_RX_SUPPLIES,
  204. (1 << 6), (enable << 6));
  205. /*
  206. * 100us sleep is required after flyback enable/disable
  207. * as per HW requirement
  208. */
  209. usleep_range(100, 110);
  210. snd_soc_component_update_bits(component,
  211. WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
  212. 0xE0, 0xE0);
  213. /* 500usec delay is needed as per HW requirement */
  214. usleep_range(500, 500 + WCD_USLEEP_RANGE);
  215. }
  216. dev_dbg(component->dev, "%s: flyback_users %d, enable %d, mode: %s\n",
  217. __func__, clsh_d->flyback_users, enable, mode_to_str(mode));
  218. }
  219. static void wcd_clsh_set_hph_mode(struct snd_soc_component *component,
  220. int mode)
  221. {
  222. u8 val = 0;
  223. switch (mode) {
  224. case CLS_H_NORMAL:
  225. case CLS_H_LOHIFI:
  226. val = 0x00;
  227. break;
  228. case CLS_AB:
  229. case CLS_H_ULP:
  230. val = 0x0C;
  231. break;
  232. case CLS_AB_HIFI:
  233. case CLS_H_HIFI:
  234. val = 0x08;
  235. break;
  236. case CLS_H_LP:
  237. val = 0x04;
  238. break;
  239. default:
  240. dev_err(component->dev, "%s:Invalid mode %d\n", __func__, mode);
  241. return;
  242. };
  243. snd_soc_component_update_bits(component, WCD9XXX_ANA_HPH, 0x0C, val);
  244. }
  245. static void wcd_clsh_set_flyback_current(struct snd_soc_component *component,
  246. int mode)
  247. {
  248. snd_soc_component_update_bits(component, WCD9XXX_RX_BIAS_FLYB_BUFF,
  249. 0x0F, 0x0A);
  250. snd_soc_component_update_bits(component, WCD9XXX_RX_BIAS_FLYB_BUFF,
  251. 0xF0, 0xA0);
  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(
  256. struct snd_soc_component *component,
  257. int mode)
  258. {
  259. snd_soc_component_update_bits(component, WCD9XXX_ANA_RX_SUPPLIES,
  260. 0x02, 0x00);
  261. }
  262. static void wcd_clsh_state_ear_aux(struct snd_soc_component *component,
  263. struct wcd_clsh_cdc_info *clsh_d,
  264. u8 req_state, bool is_enable, int mode)
  265. {
  266. dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
  267. mode_to_str(mode), is_enable ? "enable" : "disable");
  268. }
  269. static void wcd_clsh_state_hph_aux(struct snd_soc_component *component,
  270. struct wcd_clsh_cdc_info *clsh_d,
  271. u8 req_state, bool is_enable, int mode)
  272. {
  273. dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
  274. mode_to_str(mode), is_enable ? "enable" : "disable");
  275. }
  276. static void wcd_clsh_state_hph_ear(struct snd_soc_component *component,
  277. struct wcd_clsh_cdc_info *clsh_d,
  278. u8 req_state, bool is_enable, int mode)
  279. {
  280. dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
  281. mode_to_str(mode), is_enable ? "enable" : "disable");
  282. }
  283. static void wcd_clsh_state_hph_st(struct snd_soc_component *component,
  284. struct wcd_clsh_cdc_info *clsh_d,
  285. u8 req_state, bool is_enable, int mode)
  286. {
  287. dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
  288. mode_to_str(mode), is_enable ? "enable" : "disable");
  289. }
  290. static void wcd_clsh_state_hph_r(struct snd_soc_component *component,
  291. struct wcd_clsh_cdc_info *clsh_d,
  292. u8 req_state, bool is_enable, int mode)
  293. {
  294. dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
  295. mode_to_str(mode), is_enable ? "enable" : "disable");
  296. if (mode == CLS_H_NORMAL) {
  297. dev_dbg(component->dev, "%s: Normal mode not applicable for hph_r\n",
  298. __func__);
  299. return;
  300. }
  301. if (is_enable) {
  302. wcd_clsh_set_buck_regulator_mode(component, mode);
  303. wcd_clsh_set_flyback_mode(component, mode);
  304. wcd_clsh_force_iq_ctl(component, mode, true);
  305. wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
  306. wcd_clsh_set_flyback_current(component, mode);
  307. wcd_clsh_set_buck_mode(component, mode);
  308. wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
  309. wcd_clsh_set_hph_mode(component, mode);
  310. } else {
  311. wcd_clsh_set_hph_mode(component, CLS_H_NORMAL);
  312. /* buck and flyback set to default mode and disable */
  313. wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false);
  314. wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false);
  315. wcd_clsh_force_iq_ctl(component, CLS_H_NORMAL, false);
  316. wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
  317. wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
  318. }
  319. }
  320. static void wcd_clsh_state_hph_l(struct snd_soc_component *component,
  321. struct wcd_clsh_cdc_info *clsh_d,
  322. u8 req_state, bool is_enable, int mode)
  323. {
  324. dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
  325. mode_to_str(mode), is_enable ? "enable" : "disable");
  326. if (mode == CLS_H_NORMAL) {
  327. dev_dbg(component->dev, "%s: Normal mode not applicable for hph_l\n",
  328. __func__);
  329. return;
  330. }
  331. if (is_enable) {
  332. wcd_clsh_set_buck_regulator_mode(component, mode);
  333. wcd_clsh_set_flyback_mode(component, mode);
  334. wcd_clsh_force_iq_ctl(component, mode, true);
  335. wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
  336. wcd_clsh_set_flyback_current(component, mode);
  337. wcd_clsh_set_buck_mode(component, mode);
  338. wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
  339. wcd_clsh_set_hph_mode(component, mode);
  340. } else {
  341. wcd_clsh_set_hph_mode(component, CLS_H_NORMAL);
  342. /* set buck and flyback to Default Mode */
  343. wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false);
  344. wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false);
  345. wcd_clsh_force_iq_ctl(component, CLS_H_NORMAL, false);
  346. wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
  347. wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
  348. }
  349. }
  350. static void wcd_clsh_state_aux(struct snd_soc_component *component,
  351. struct wcd_clsh_cdc_info *clsh_d,
  352. u8 req_state, bool is_enable, int mode)
  353. {
  354. dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
  355. mode_to_str(mode), is_enable ? "enable" : "disable");
  356. if (is_enable) {
  357. wcd_clsh_set_buck_mode(component, mode);
  358. wcd_clsh_set_flyback_mode(component, mode);
  359. wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
  360. wcd_clsh_set_flyback_current(component, mode);
  361. wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
  362. } else {
  363. wcd_clsh_buck_ctrl(component, clsh_d, mode, false);
  364. wcd_clsh_flyback_ctrl(component, clsh_d, mode, false);
  365. wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
  366. wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
  367. }
  368. }
  369. static void wcd_clsh_state_ear(struct snd_soc_component *component,
  370. struct wcd_clsh_cdc_info *clsh_d,
  371. u8 req_state, bool is_enable, int mode)
  372. {
  373. dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
  374. mode_to_str(mode),
  375. is_enable ? "enable" : "disable");
  376. if (is_enable) {
  377. wcd_clsh_set_buck_regulator_mode(component, mode);
  378. wcd_clsh_set_flyback_mode(component, mode);
  379. wcd_clsh_force_iq_ctl(component, mode, true);
  380. wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
  381. wcd_clsh_set_flyback_current(component, mode);
  382. wcd_clsh_set_buck_mode(component, mode);
  383. wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
  384. wcd_clsh_set_hph_mode(component, mode);
  385. } else {
  386. wcd_clsh_set_hph_mode(component, CLS_H_NORMAL);
  387. /* set buck and flyback to Default Mode */
  388. wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false);
  389. wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false);
  390. wcd_clsh_force_iq_ctl(component, CLS_H_NORMAL, false);
  391. wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
  392. wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
  393. }
  394. }
  395. static void wcd_clsh_state_err(struct snd_soc_component *component,
  396. struct wcd_clsh_cdc_info *clsh_d,
  397. u8 req_state, bool is_enable, int mode)
  398. {
  399. char msg[128];
  400. dev_err(component->dev,
  401. "%s Wrong request for class H state machine requested to %s %s\n",
  402. __func__, is_enable ? "enable" : "disable",
  403. state_to_str(req_state, msg, sizeof(msg)));
  404. }
  405. /*
  406. * Function: wcd_clsh_is_state_valid
  407. * Params: state
  408. * Description:
  409. * Provides information on valid states of Class H configuration
  410. */
  411. static bool wcd_clsh_is_state_valid(u8 state)
  412. {
  413. switch (state) {
  414. case WCD_CLSH_STATE_IDLE:
  415. case WCD_CLSH_STATE_EAR:
  416. case WCD_CLSH_STATE_HPHL:
  417. case WCD_CLSH_STATE_HPHR:
  418. case WCD_CLSH_STATE_HPH_ST:
  419. case WCD_CLSH_STATE_AUX:
  420. case WCD_CLSH_STATE_HPHL_AUX:
  421. case WCD_CLSH_STATE_HPHR_AUX:
  422. case WCD_CLSH_STATE_HPH_ST_AUX:
  423. case WCD_CLSH_STATE_EAR_AUX:
  424. return true;
  425. default:
  426. return false;
  427. };
  428. }
  429. /*
  430. * Function: wcd_cls_h_fsm
  431. * Params: component, cdc_clsh_d, req_state, req_type, clsh_event
  432. * Description:
  433. * This function handles PRE DAC and POST DAC conditions of different devices
  434. * and updates class H configuration of different combination of devices
  435. * based on validity of their states. cdc_clsh_d will contain current
  436. * class h state information
  437. */
  438. void wcd_cls_h_fsm(struct snd_soc_component *component,
  439. struct wcd_clsh_cdc_info *cdc_clsh_d,
  440. u8 clsh_event, u8 req_state,
  441. int int_mode)
  442. {
  443. u8 old_state, new_state;
  444. char msg0[128], msg1[128];
  445. switch (clsh_event) {
  446. case WCD_CLSH_EVENT_PRE_DAC:
  447. old_state = cdc_clsh_d->state;
  448. new_state = old_state | req_state;
  449. if (!wcd_clsh_is_state_valid(new_state)) {
  450. dev_err(component->dev,
  451. "%s: Class-H not a valid new state: %s\n",
  452. __func__,
  453. state_to_str(new_state, msg0, sizeof(msg0)));
  454. return;
  455. }
  456. if (new_state == old_state) {
  457. dev_err(component->dev,
  458. "%s: Class-H already in requested state: %s\n",
  459. __func__,
  460. state_to_str(new_state, msg0, sizeof(msg0)));
  461. return;
  462. }
  463. cdc_clsh_d->state = new_state;
  464. wcd_clsh_set_int_mode(cdc_clsh_d, req_state, int_mode);
  465. (*clsh_state_fp[new_state]) (component, cdc_clsh_d, req_state,
  466. CLSH_REQ_ENABLE, int_mode);
  467. dev_dbg(component->dev,
  468. "%s: ClassH state transition from %s to %s\n",
  469. __func__, state_to_str(old_state, msg0, sizeof(msg0)),
  470. state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
  471. break;
  472. case WCD_CLSH_EVENT_POST_PA:
  473. old_state = cdc_clsh_d->state;
  474. new_state = old_state & (~req_state);
  475. if (new_state < NUM_CLSH_STATES) {
  476. if (!wcd_clsh_is_state_valid(old_state)) {
  477. dev_err(component->dev,
  478. "%s:Invalid old state:%s\n",
  479. __func__,
  480. state_to_str(old_state, msg0,
  481. sizeof(msg0)));
  482. return;
  483. }
  484. if (new_state == old_state) {
  485. dev_err(component->dev,
  486. "%s: Class-H already in requested state: %s\n",
  487. __func__,
  488. state_to_str(new_state, msg0,
  489. sizeof(msg0)));
  490. return;
  491. }
  492. (*clsh_state_fp[old_state]) (component, cdc_clsh_d,
  493. req_state, CLSH_REQ_DISABLE,
  494. int_mode);
  495. cdc_clsh_d->state = new_state;
  496. wcd_clsh_set_int_mode(cdc_clsh_d, req_state, CLS_NONE);
  497. dev_dbg(component->dev, "%s: ClassH state transition from %s to %s\n",
  498. __func__, state_to_str(old_state, msg0,
  499. sizeof(msg0)),
  500. state_to_str(cdc_clsh_d->state, msg1,
  501. sizeof(msg1)));
  502. }
  503. break;
  504. };
  505. }
  506. EXPORT_SYMBOL(wcd_cls_h_fsm);
  507. /*
  508. * wcd_cls_h_init: Called to init clsh info
  509. *
  510. * @clsh: pointer for clsh state information.
  511. */
  512. void wcd_cls_h_init(struct wcd_clsh_cdc_info *clsh)
  513. {
  514. int i;
  515. clsh->state = WCD_CLSH_STATE_IDLE;
  516. for (i = 0; i < NUM_CLSH_STATES; i++)
  517. clsh_state_fp[i] = wcd_clsh_state_err;
  518. clsh_state_fp[WCD_CLSH_STATE_EAR] = wcd_clsh_state_ear;
  519. clsh_state_fp[WCD_CLSH_STATE_HPHL] = wcd_clsh_state_hph_l;
  520. clsh_state_fp[WCD_CLSH_STATE_HPHR] = wcd_clsh_state_hph_r;
  521. clsh_state_fp[WCD_CLSH_STATE_HPH_ST] = wcd_clsh_state_hph_st;
  522. clsh_state_fp[WCD_CLSH_STATE_AUX] = wcd_clsh_state_aux;
  523. clsh_state_fp[WCD_CLSH_STATE_HPHL_AUX] = wcd_clsh_state_hph_aux;
  524. clsh_state_fp[WCD_CLSH_STATE_HPHR_AUX] = wcd_clsh_state_hph_aux;
  525. clsh_state_fp[WCD_CLSH_STATE_HPH_ST_AUX] =
  526. wcd_clsh_state_hph_aux;
  527. clsh_state_fp[WCD_CLSH_STATE_EAR_AUX] = wcd_clsh_state_ear_aux;
  528. clsh_state_fp[WCD_CLSH_STATE_HPHL_EAR] = wcd_clsh_state_hph_ear;
  529. clsh_state_fp[WCD_CLSH_STATE_HPHR_EAR] = wcd_clsh_state_hph_ear;
  530. clsh_state_fp[WCD_CLSH_STATE_HPH_ST_EAR] = wcd_clsh_state_hph_ear;
  531. /* Set interpolaotr modes to NONE */
  532. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_EAR, CLS_NONE);
  533. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHL, CLS_NONE);
  534. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHR, CLS_NONE);
  535. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_AUX, CLS_NONE);
  536. clsh->flyback_users = 0;
  537. clsh->buck_users = 0;
  538. }
  539. EXPORT_SYMBOL(wcd_cls_h_init);
  540. MODULE_DESCRIPTION("WCD Class-H Driver");
  541. MODULE_LICENSE("GPL v2");