wcd-mbhc-legacy.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975
  1. /* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/init.h>
  14. #include <linux/slab.h>
  15. #include <linux/of_gpio.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/device.h>
  18. #include <linux/printk.h>
  19. #include <linux/ratelimit.h>
  20. #include <linux/list.h>
  21. #include <linux/bitops.h>
  22. #include <linux/delay.h>
  23. #include <linux/pm_runtime.h>
  24. #include <linux/kernel.h>
  25. #include <linux/input.h>
  26. #include <linux/firmware.h>
  27. #include <linux/completion.h>
  28. #include <sound/soc.h>
  29. #include <sound/jack.h>
  30. #include "wcd-mbhc-legacy.h"
  31. #include "wcd-mbhc-v2.h"
  32. static int det_extn_cable_en;
  33. module_param(det_extn_cable_en, int, 0664);
  34. MODULE_PARM_DESC(det_extn_cable_en, "enable/disable extn cable detect");
  35. static bool wcd_mbhc_detect_anc_plug_type(struct wcd_mbhc *mbhc)
  36. {
  37. bool anc_mic_found = false;
  38. u16 val, hs_comp_res, btn_status = 0;
  39. unsigned long retry = 0;
  40. int valid_plug_cnt = 0, invalid_plug_cnt = 0;
  41. int btn_status_cnt = 0;
  42. bool is_check_btn_press = false;
  43. if (mbhc->mbhc_cfg->anc_micbias < MIC_BIAS_1 ||
  44. mbhc->mbhc_cfg->anc_micbias > MIC_BIAS_4)
  45. return false;
  46. if (!mbhc->mbhc_cb->mbhc_micbias_control)
  47. return false;
  48. WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, val);
  49. if (val)
  50. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
  51. mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
  52. mbhc->mbhc_cfg->anc_micbias,
  53. MICB_ENABLE);
  54. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x2);
  55. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 1);
  56. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
  57. /*
  58. * wait for button debounce time 20ms. If 4-pole plug is inserted
  59. * into 5-pole jack, then there will be a button press interrupt
  60. * during anc plug detection. In that case though Hs_comp_res is 0,
  61. * it should not be declared as ANC plug type
  62. */
  63. usleep_range(20000, 20100);
  64. /*
  65. * After enabling FSM, to handle slow insertion scenarios,
  66. * check hs_comp_result for few times to see if the IN3 voltage
  67. * is below the Vref
  68. */
  69. do {
  70. if (wcd_swch_level_remove(mbhc)) {
  71. pr_debug("%s: Switch level is low\n", __func__);
  72. goto exit;
  73. }
  74. pr_debug("%s: Retry attempt %lu\n", __func__, retry + 1);
  75. WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
  76. if (!hs_comp_res) {
  77. valid_plug_cnt++;
  78. is_check_btn_press = true;
  79. } else
  80. invalid_plug_cnt++;
  81. /* Wait 1ms before taking another reading */
  82. usleep_range(1000, 1100);
  83. WCD_MBHC_REG_READ(WCD_MBHC_FSM_STATUS, btn_status);
  84. if (btn_status)
  85. btn_status_cnt++;
  86. retry++;
  87. } while (retry < ANC_DETECT_RETRY_CNT);
  88. pr_debug("%s: valid: %d, invalid: %d, btn_status_cnt: %d\n",
  89. __func__, valid_plug_cnt, invalid_plug_cnt, btn_status_cnt);
  90. /* decision logic */
  91. if ((valid_plug_cnt > invalid_plug_cnt) && is_check_btn_press &&
  92. (btn_status_cnt == 0))
  93. anc_mic_found = true;
  94. exit:
  95. if (!val)
  96. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
  97. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 0);
  98. mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
  99. mbhc->mbhc_cfg->anc_micbias,
  100. MICB_DISABLE);
  101. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x0);
  102. pr_debug("%s: anc mic %sfound\n", __func__,
  103. anc_mic_found ? "" : "not ");
  104. return anc_mic_found;
  105. }
  106. /* To determine if cross connection occurred */
  107. static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
  108. {
  109. u16 swap_res = 0;
  110. enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_NONE;
  111. s16 reg1 = 0;
  112. bool hphl_sch_res = 0, hphr_sch_res = 0;
  113. if (wcd_swch_level_remove(mbhc)) {
  114. pr_debug("%s: Switch level is low\n", __func__);
  115. return -EINVAL;
  116. }
  117. /* If PA is enabled, dont check for cross-connection */
  118. if (mbhc->mbhc_cb->hph_pa_on_status)
  119. if (mbhc->mbhc_cb->hph_pa_on_status(mbhc->codec))
  120. return false;
  121. WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, reg1);
  122. /*
  123. * Check if there is any cross connection,
  124. * Micbias and schmitt trigger (HPHL-HPHR)
  125. * needs to be enabled. For some codecs like wcd9335,
  126. * pull-up will already be enabled when this function
  127. * is called for cross-connection identification. No
  128. * need to enable micbias in that case.
  129. */
  130. wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
  131. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 2);
  132. WCD_MBHC_REG_READ(WCD_MBHC_ELECT_RESULT, swap_res);
  133. pr_debug("%s: swap_res%x\n", __func__, swap_res);
  134. /*
  135. * Read reg hphl and hphr schmitt result with cross connection
  136. * bit. These bits will both be "0" in case of cross connection
  137. * otherwise, they stay at 1
  138. */
  139. WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch_res);
  140. WCD_MBHC_REG_READ(WCD_MBHC_HPHR_SCHMT_RESULT, hphr_sch_res);
  141. if (!(hphl_sch_res || hphr_sch_res)) {
  142. plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
  143. pr_debug("%s: Cross connection identified\n", __func__);
  144. } else {
  145. pr_debug("%s: No Cross connection found\n", __func__);
  146. }
  147. /* Disable schmitt trigger and restore micbias */
  148. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, reg1);
  149. pr_debug("%s: leave, plug type: %d\n", __func__, plug_type);
  150. return (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) ? true : false;
  151. }
  152. static bool wcd_is_special_headset(struct wcd_mbhc *mbhc)
  153. {
  154. struct snd_soc_codec *codec = mbhc->codec;
  155. int delay = 0, rc;
  156. bool ret = false;
  157. u16 hs_comp_res;
  158. bool is_spl_hs = false;
  159. /*
  160. * Increase micbias to 2.7V to detect headsets with
  161. * threshold on microphone
  162. */
  163. if (mbhc->mbhc_cb->mbhc_micbias_control &&
  164. !mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
  165. pr_debug("%s: callback fn micb_ctrl_thr_mic not defined\n",
  166. __func__);
  167. return false;
  168. } else if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
  169. rc = mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(codec,
  170. MIC_BIAS_2, true);
  171. if (rc) {
  172. pr_err("%s: Micbias control for thr mic failed, rc: %d\n",
  173. __func__, rc);
  174. return false;
  175. }
  176. }
  177. wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
  178. pr_debug("%s: special headset, start register writes\n", __func__);
  179. WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
  180. while (!is_spl_hs) {
  181. if (mbhc->hs_detect_work_stop) {
  182. pr_debug("%s: stop requested: %d\n", __func__,
  183. mbhc->hs_detect_work_stop);
  184. break;
  185. }
  186. delay = delay + 50;
  187. if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) {
  188. mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
  189. MBHC_COMMON_MICB_PRECHARGE,
  190. true);
  191. mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
  192. MBHC_COMMON_MICB_SET_VAL,
  193. true);
  194. }
  195. /* Wait for 50msec for MICBIAS to settle down */
  196. msleep(50);
  197. if (mbhc->mbhc_cb->set_auto_zeroing)
  198. mbhc->mbhc_cb->set_auto_zeroing(codec, true);
  199. /* Wait for 50msec for FSM to update result values */
  200. msleep(50);
  201. WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
  202. if (!(hs_comp_res)) {
  203. pr_debug("%s: Special headset detected in %d msecs\n",
  204. __func__, (delay * 2));
  205. is_spl_hs = true;
  206. }
  207. if (delay == SPECIAL_HS_DETECT_TIME_MS) {
  208. pr_debug("%s: Spl headset didn't get detect in 4 sec\n",
  209. __func__);
  210. break;
  211. }
  212. }
  213. if (is_spl_hs) {
  214. pr_debug("%s: Headset with threshold found\n", __func__);
  215. mbhc->micbias_enable = true;
  216. ret = true;
  217. }
  218. if (mbhc->mbhc_cb->mbhc_common_micb_ctrl)
  219. mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
  220. MBHC_COMMON_MICB_PRECHARGE,
  221. false);
  222. if (mbhc->mbhc_cb->set_micbias_value && !mbhc->micbias_enable)
  223. mbhc->mbhc_cb->set_micbias_value(codec);
  224. if (mbhc->mbhc_cb->set_auto_zeroing)
  225. mbhc->mbhc_cb->set_auto_zeroing(codec, false);
  226. if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
  227. !mbhc->micbias_enable)
  228. mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(codec, MIC_BIAS_2,
  229. false);
  230. pr_debug("%s: leave, micb_enable: %d\n", __func__,
  231. mbhc->micbias_enable);
  232. return ret;
  233. }
  234. static void wcd_mbhc_update_fsm_source(struct wcd_mbhc *mbhc,
  235. enum wcd_mbhc_plug_type plug_type)
  236. {
  237. bool micbias2;
  238. micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
  239. MIC_BIAS_2);
  240. switch (plug_type) {
  241. case MBHC_PLUG_TYPE_HEADPHONE:
  242. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
  243. break;
  244. case MBHC_PLUG_TYPE_HEADSET:
  245. case MBHC_PLUG_TYPE_ANC_HEADPHONE:
  246. if (!mbhc->is_hs_recording && !micbias2)
  247. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
  248. break;
  249. default:
  250. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
  251. break;
  252. };
  253. }
  254. static void wcd_enable_mbhc_supply(struct wcd_mbhc *mbhc,
  255. enum wcd_mbhc_plug_type plug_type)
  256. {
  257. struct snd_soc_codec *codec = mbhc->codec;
  258. /*
  259. * Do not disable micbias if recording is going on or
  260. * headset is inserted on the other side of the extn
  261. * cable. If headset has been detected current source
  262. * needs to be kept enabled for button detection to work.
  263. * If the accessory type is invalid or unsupported, we
  264. * dont need to enable either of them.
  265. */
  266. if (det_extn_cable_en && mbhc->is_extn_cable &&
  267. mbhc->mbhc_cb && mbhc->mbhc_cb->extn_use_mb &&
  268. mbhc->mbhc_cb->extn_use_mb(codec)) {
  269. if (plug_type == MBHC_PLUG_TYPE_HEADPHONE ||
  270. plug_type == MBHC_PLUG_TYPE_HEADSET)
  271. wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
  272. } else {
  273. if (plug_type == MBHC_PLUG_TYPE_HEADSET) {
  274. if (mbhc->is_hs_recording || mbhc->micbias_enable) {
  275. wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
  276. } else if ((test_bit(WCD_MBHC_EVENT_PA_HPHL,
  277. &mbhc->event_state)) ||
  278. (test_bit(WCD_MBHC_EVENT_PA_HPHR,
  279. &mbhc->event_state))) {
  280. wcd_enable_curr_micbias(mbhc,
  281. WCD_MBHC_EN_PULLUP);
  282. } else {
  283. wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
  284. }
  285. } else if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
  286. wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
  287. } else {
  288. wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_NONE);
  289. }
  290. }
  291. }
  292. static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc,
  293. int *spl_hs_cnt)
  294. {
  295. u16 hs_comp_res_1_8v = 0, hs_comp_res_2_7v = 0;
  296. bool spl_hs = false;
  297. if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
  298. goto done;
  299. if (!spl_hs_cnt) {
  300. pr_err("%s: spl_hs_cnt is NULL\n", __func__);
  301. goto done;
  302. }
  303. /* Read back hs_comp_res @ 1.8v Micbias */
  304. WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res_1_8v);
  305. if (!hs_comp_res_1_8v) {
  306. spl_hs = false;
  307. goto done;
  308. }
  309. /* Bump up MB2 to 2.7v */
  310. mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
  311. mbhc->mbhc_cfg->mbhc_micbias, true);
  312. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
  313. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
  314. usleep_range(10000, 10100);
  315. /* Read back HS_COMP_RESULT */
  316. WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res_2_7v);
  317. if (!hs_comp_res_2_7v && hs_comp_res_1_8v)
  318. spl_hs = true;
  319. if (spl_hs)
  320. *spl_hs_cnt += 1;
  321. /* MB2 back to 1.8v */
  322. if (*spl_hs_cnt != WCD_MBHC_SPL_HS_CNT) {
  323. mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
  324. mbhc->mbhc_cfg->mbhc_micbias, false);
  325. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
  326. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
  327. usleep_range(10000, 10100);
  328. }
  329. if (spl_hs)
  330. pr_debug("%s: Detected special HS (%d)\n", __func__, spl_hs);
  331. done:
  332. return spl_hs;
  333. }
  334. /* should be called under interrupt context that hold suspend */
  335. static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
  336. struct work_struct *work)
  337. {
  338. pr_debug("%s: scheduling correct_swch_plug\n", __func__);
  339. WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
  340. mbhc->hs_detect_work_stop = false;
  341. mbhc->mbhc_cb->lock_sleep(mbhc, true);
  342. schedule_work(work);
  343. }
  344. /* called under codec_resource_lock acquisition */
  345. static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
  346. struct work_struct *work)
  347. {
  348. pr_debug("%s: Canceling correct_plug_swch\n", __func__);
  349. mbhc->hs_detect_work_stop = true;
  350. WCD_MBHC_RSC_UNLOCK(mbhc);
  351. if (cancel_work_sync(work)) {
  352. pr_debug("%s: correct_plug_swch is canceled\n",
  353. __func__);
  354. mbhc->mbhc_cb->lock_sleep(mbhc, false);
  355. }
  356. WCD_MBHC_RSC_LOCK(mbhc);
  357. }
  358. /* called under codec_resource_lock acquisition */
  359. static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
  360. {
  361. struct snd_soc_codec *codec = mbhc->codec;
  362. bool micbias1 = false;
  363. pr_debug("%s: enter\n", __func__);
  364. WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
  365. if (mbhc->mbhc_cb->hph_pull_down_ctrl)
  366. mbhc->mbhc_cb->hph_pull_down_ctrl(codec, false);
  367. if (mbhc->mbhc_cb->micbias_enable_status)
  368. micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
  369. MIC_BIAS_1);
  370. if (mbhc->mbhc_cb->set_cap_mode)
  371. mbhc->mbhc_cb->set_cap_mode(codec, micbias1, true);
  372. if (mbhc->mbhc_cb->mbhc_micbias_control)
  373. mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
  374. MICB_ENABLE);
  375. else
  376. wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
  377. /* Re-initialize button press completion object */
  378. reinit_completion(&mbhc->btn_press_compl);
  379. wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
  380. pr_debug("%s: leave\n", __func__);
  381. }
  382. static void wcd_correct_swch_plug(struct work_struct *work)
  383. {
  384. struct wcd_mbhc *mbhc;
  385. struct snd_soc_codec *codec;
  386. enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
  387. unsigned long timeout;
  388. u16 hs_comp_res = 0, hphl_sch = 0, mic_sch = 0, btn_result = 0;
  389. bool wrk_complete = false;
  390. int pt_gnd_mic_swap_cnt = 0;
  391. int no_gnd_mic_swap_cnt = 0;
  392. bool is_pa_on = false, spl_hs = false, spl_hs_reported = false;
  393. bool micbias2 = false;
  394. bool micbias1 = false;
  395. int ret = 0;
  396. int rc, spl_hs_count = 0;
  397. int cross_conn;
  398. int try = 0;
  399. pr_debug("%s: enter\n", __func__);
  400. mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
  401. codec = mbhc->codec;
  402. /*
  403. * Enable micbias/pullup for detection in correct work.
  404. * This work will get scheduled from detect_plug_type which
  405. * will already request for pullup/micbias. If the pullup/micbias
  406. * is handled with ref-counts by individual codec drivers, there is
  407. * no need to enabale micbias/pullup here
  408. */
  409. wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
  410. /* Enable HW FSM */
  411. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
  412. /*
  413. * Check for any button press interrupts before starting 3-sec
  414. * loop.
  415. */
  416. rc = wait_for_completion_timeout(&mbhc->btn_press_compl,
  417. msecs_to_jiffies(WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS));
  418. WCD_MBHC_REG_READ(WCD_MBHC_BTN_RESULT, btn_result);
  419. WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
  420. if (!rc) {
  421. pr_debug("%s No btn press interrupt\n", __func__);
  422. if (!btn_result && !hs_comp_res)
  423. plug_type = MBHC_PLUG_TYPE_HEADSET;
  424. else if (!btn_result && hs_comp_res)
  425. plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
  426. else
  427. plug_type = MBHC_PLUG_TYPE_INVALID;
  428. } else {
  429. if (!btn_result && !hs_comp_res)
  430. plug_type = MBHC_PLUG_TYPE_HEADPHONE;
  431. else
  432. plug_type = MBHC_PLUG_TYPE_INVALID;
  433. }
  434. do {
  435. cross_conn = wcd_check_cross_conn(mbhc);
  436. try++;
  437. } while (try < GND_MIC_SWAP_THRESHOLD);
  438. /*
  439. * Check for cross connection 4 times.
  440. * Consider the result of the fourth iteration.
  441. */
  442. if (cross_conn > 0) {
  443. pr_debug("%s: cross con found, start polling\n",
  444. __func__);
  445. plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
  446. pr_debug("%s: Plug found, plug type is %d\n",
  447. __func__, plug_type);
  448. goto correct_plug_type;
  449. }
  450. if ((plug_type == MBHC_PLUG_TYPE_HEADSET ||
  451. plug_type == MBHC_PLUG_TYPE_HEADPHONE) &&
  452. (!wcd_swch_level_remove(mbhc))) {
  453. WCD_MBHC_RSC_LOCK(mbhc);
  454. if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH)
  455. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
  456. 0);
  457. wcd_mbhc_find_plug_and_report(mbhc, plug_type);
  458. WCD_MBHC_RSC_UNLOCK(mbhc);
  459. }
  460. correct_plug_type:
  461. timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
  462. while (!time_after(jiffies, timeout)) {
  463. if (mbhc->hs_detect_work_stop) {
  464. pr_debug("%s: stop requested: %d\n", __func__,
  465. mbhc->hs_detect_work_stop);
  466. wcd_enable_curr_micbias(mbhc,
  467. WCD_MBHC_EN_NONE);
  468. if (mbhc->micbias_enable) {
  469. mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
  470. mbhc->codec, MIC_BIAS_2, false);
  471. if (mbhc->mbhc_cb->set_micbias_value)
  472. mbhc->mbhc_cb->set_micbias_value(
  473. mbhc->codec);
  474. mbhc->micbias_enable = false;
  475. }
  476. goto exit;
  477. }
  478. if (mbhc->btn_press_intr) {
  479. wcd_cancel_btn_work(mbhc);
  480. mbhc->btn_press_intr = false;
  481. }
  482. /* Toggle FSM */
  483. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
  484. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
  485. /* allow sometime and re-check stop requested again */
  486. msleep(20);
  487. if (mbhc->hs_detect_work_stop) {
  488. pr_debug("%s: stop requested: %d\n", __func__,
  489. mbhc->hs_detect_work_stop);
  490. wcd_enable_curr_micbias(mbhc,
  491. WCD_MBHC_EN_NONE);
  492. if (mbhc->micbias_enable) {
  493. mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
  494. mbhc->codec, MIC_BIAS_2, false);
  495. if (mbhc->mbhc_cb->set_micbias_value)
  496. mbhc->mbhc_cb->set_micbias_value(
  497. mbhc->codec);
  498. mbhc->micbias_enable = false;
  499. }
  500. goto exit;
  501. }
  502. WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
  503. pr_debug("%s: hs_comp_res: %x\n", __func__, hs_comp_res);
  504. if (mbhc->mbhc_cb->hph_pa_on_status)
  505. is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(codec);
  506. /*
  507. * instead of hogging system by contineous polling, wait for
  508. * sometime and re-check stop request again.
  509. */
  510. msleep(180);
  511. if (hs_comp_res && (spl_hs_count < WCD_MBHC_SPL_HS_CNT)) {
  512. spl_hs = wcd_mbhc_check_for_spl_headset(mbhc,
  513. &spl_hs_count);
  514. if (spl_hs_count == WCD_MBHC_SPL_HS_CNT) {
  515. hs_comp_res = 0;
  516. spl_hs = true;
  517. mbhc->micbias_enable = true;
  518. }
  519. }
  520. if ((!hs_comp_res) && (!is_pa_on)) {
  521. /* Check for cross connection*/
  522. ret = wcd_check_cross_conn(mbhc);
  523. if (ret < 0) {
  524. continue;
  525. } else if (ret > 0) {
  526. pt_gnd_mic_swap_cnt++;
  527. no_gnd_mic_swap_cnt = 0;
  528. if (pt_gnd_mic_swap_cnt <
  529. GND_MIC_SWAP_THRESHOLD) {
  530. continue;
  531. } else if (pt_gnd_mic_swap_cnt >
  532. GND_MIC_SWAP_THRESHOLD) {
  533. /*
  534. * This is due to GND/MIC switch didn't
  535. * work, Report unsupported plug.
  536. */
  537. pr_debug("%s: switch didn't work\n",
  538. __func__);
  539. plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
  540. goto report;
  541. } else {
  542. plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
  543. }
  544. } else {
  545. no_gnd_mic_swap_cnt++;
  546. pt_gnd_mic_swap_cnt = 0;
  547. plug_type = MBHC_PLUG_TYPE_HEADSET;
  548. if ((no_gnd_mic_swap_cnt <
  549. GND_MIC_SWAP_THRESHOLD) &&
  550. (spl_hs_count != WCD_MBHC_SPL_HS_CNT)) {
  551. continue;
  552. } else {
  553. no_gnd_mic_swap_cnt = 0;
  554. }
  555. }
  556. if ((pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) &&
  557. (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
  558. /*
  559. * if switch is toggled, check again,
  560. * otherwise report unsupported plug
  561. */
  562. if (mbhc->mbhc_cfg->swap_gnd_mic &&
  563. mbhc->mbhc_cfg->swap_gnd_mic(codec,
  564. true)) {
  565. pr_debug("%s: US_EU gpio present,flip switch\n"
  566. , __func__);
  567. continue;
  568. }
  569. }
  570. }
  571. WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
  572. WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
  573. if (hs_comp_res && !(hphl_sch || mic_sch)) {
  574. pr_debug("%s: cable is extension cable\n", __func__);
  575. plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
  576. wrk_complete = true;
  577. } else {
  578. pr_debug("%s: cable might be headset: %d\n", __func__,
  579. plug_type);
  580. if (!(plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
  581. plug_type = MBHC_PLUG_TYPE_HEADSET;
  582. if (!spl_hs_reported &&
  583. spl_hs_count == WCD_MBHC_SPL_HS_CNT) {
  584. spl_hs_reported = true;
  585. WCD_MBHC_RSC_LOCK(mbhc);
  586. wcd_mbhc_find_plug_and_report(mbhc,
  587. plug_type);
  588. WCD_MBHC_RSC_UNLOCK(mbhc);
  589. continue;
  590. } else if (spl_hs_reported)
  591. continue;
  592. /*
  593. * Report headset only if not already reported
  594. * and if there is not button press without
  595. * release
  596. */
  597. if (((mbhc->current_plug !=
  598. MBHC_PLUG_TYPE_HEADSET) &&
  599. (mbhc->current_plug !=
  600. MBHC_PLUG_TYPE_ANC_HEADPHONE)) &&
  601. !wcd_swch_level_remove(mbhc) &&
  602. !mbhc->btn_press_intr) {
  603. pr_debug("%s: cable is %sheadset\n",
  604. __func__,
  605. ((spl_hs_count ==
  606. WCD_MBHC_SPL_HS_CNT) ?
  607. "special ":""));
  608. goto report;
  609. }
  610. }
  611. wrk_complete = false;
  612. }
  613. }
  614. if (!wrk_complete && mbhc->btn_press_intr) {
  615. pr_debug("%s: Can be slow insertion of headphone\n", __func__);
  616. wcd_cancel_btn_work(mbhc);
  617. plug_type = MBHC_PLUG_TYPE_HEADPHONE;
  618. }
  619. /*
  620. * If plug_tye is headset, we might have already reported either in
  621. * detect_plug-type or in above while loop, no need to report again
  622. */
  623. if (!wrk_complete && ((plug_type == MBHC_PLUG_TYPE_HEADSET) ||
  624. (plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE))) {
  625. pr_debug("%s: plug_type:0x%x already reported\n",
  626. __func__, mbhc->current_plug);
  627. goto enable_supply;
  628. }
  629. if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH &&
  630. (!det_extn_cable_en)) {
  631. if (wcd_is_special_headset(mbhc)) {
  632. pr_debug("%s: Special headset found %d\n",
  633. __func__, plug_type);
  634. plug_type = MBHC_PLUG_TYPE_HEADSET;
  635. goto report;
  636. }
  637. }
  638. report:
  639. if (wcd_swch_level_remove(mbhc)) {
  640. pr_debug("%s: Switch level is low\n", __func__);
  641. goto exit;
  642. }
  643. if (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP && mbhc->btn_press_intr) {
  644. pr_debug("%s: insertion of headphone with swap\n", __func__);
  645. wcd_cancel_btn_work(mbhc);
  646. plug_type = MBHC_PLUG_TYPE_HEADPHONE;
  647. }
  648. pr_debug("%s: Valid plug found, plug type %d wrk_cmpt %d btn_intr %d\n",
  649. __func__, plug_type, wrk_complete,
  650. mbhc->btn_press_intr);
  651. WCD_MBHC_RSC_LOCK(mbhc);
  652. wcd_mbhc_find_plug_and_report(mbhc, plug_type);
  653. WCD_MBHC_RSC_UNLOCK(mbhc);
  654. enable_supply:
  655. if (mbhc->mbhc_cb->mbhc_micbias_control)
  656. wcd_mbhc_update_fsm_source(mbhc, plug_type);
  657. else
  658. wcd_enable_mbhc_supply(mbhc, plug_type);
  659. exit:
  660. if (mbhc->mbhc_cb->mbhc_micbias_control &&
  661. !mbhc->micbias_enable)
  662. mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
  663. MICB_DISABLE);
  664. /*
  665. * If plug type is corrected from special headset to headphone,
  666. * clear the micbias enable flag, set micbias back to 1.8V and
  667. * disable micbias.
  668. */
  669. if (plug_type == MBHC_PLUG_TYPE_HEADPHONE &&
  670. mbhc->micbias_enable) {
  671. if (mbhc->mbhc_cb->mbhc_micbias_control)
  672. mbhc->mbhc_cb->mbhc_micbias_control(
  673. codec, MIC_BIAS_2,
  674. MICB_DISABLE);
  675. if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
  676. mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
  677. codec,
  678. MIC_BIAS_2, false);
  679. if (mbhc->mbhc_cb->set_micbias_value) {
  680. mbhc->mbhc_cb->set_micbias_value(codec);
  681. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
  682. }
  683. mbhc->micbias_enable = false;
  684. }
  685. if (mbhc->mbhc_cb->micbias_enable_status) {
  686. micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
  687. MIC_BIAS_1);
  688. micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
  689. MIC_BIAS_2);
  690. }
  691. if (mbhc->mbhc_cfg->detect_extn_cable &&
  692. ((plug_type == MBHC_PLUG_TYPE_HEADPHONE) ||
  693. (plug_type == MBHC_PLUG_TYPE_HEADSET)) &&
  694. !mbhc->hs_detect_work_stop) {
  695. WCD_MBHC_RSC_LOCK(mbhc);
  696. wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, true);
  697. WCD_MBHC_RSC_UNLOCK(mbhc);
  698. }
  699. if (mbhc->mbhc_cb->set_cap_mode)
  700. mbhc->mbhc_cb->set_cap_mode(codec, micbias1, micbias2);
  701. if (mbhc->mbhc_cb->hph_pull_down_ctrl)
  702. mbhc->mbhc_cb->hph_pull_down_ctrl(codec, true);
  703. mbhc->mbhc_cb->lock_sleep(mbhc, false);
  704. pr_debug("%s: leave\n", __func__);
  705. }
  706. static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data)
  707. {
  708. struct wcd_mbhc *mbhc = data;
  709. u8 hs_comp_result = 0, hphl_sch = 0, mic_sch = 0;
  710. static u16 hphl_trigerred;
  711. static u16 mic_trigerred;
  712. unsigned long timeout;
  713. bool removed = true;
  714. int retry = 0;
  715. pr_debug("%s: enter\n", __func__);
  716. WCD_MBHC_RSC_LOCK(mbhc);
  717. timeout = jiffies +
  718. msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS);
  719. do {
  720. retry++;
  721. /*
  722. * read the result register every 10ms to look for
  723. * any change in HS_COMP_RESULT bit
  724. */
  725. usleep_range(10000, 10100);
  726. WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_result);
  727. pr_debug("%s: Check result reg for fake removal: hs_comp_res %x\n",
  728. __func__, hs_comp_result);
  729. if ((!hs_comp_result) &&
  730. retry > FAKE_REM_RETRY_ATTEMPTS) {
  731. removed = false;
  732. break;
  733. }
  734. } while (!time_after(jiffies, timeout));
  735. if (wcd_swch_level_remove(mbhc)) {
  736. pr_debug("%s: Switch level is low ", __func__);
  737. goto exit;
  738. }
  739. pr_debug("%s: headset %s actually removed\n", __func__,
  740. removed ? "" : "not ");
  741. WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
  742. WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
  743. WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_result);
  744. if (removed) {
  745. if (!(hphl_sch && mic_sch && hs_comp_result)) {
  746. /*
  747. * extension cable is still plugged in
  748. * report it as LINEOUT device
  749. */
  750. goto report_unplug;
  751. } else {
  752. if (!mic_sch) {
  753. mic_trigerred++;
  754. pr_debug("%s: Removal MIC trigerred %d\n",
  755. __func__, mic_trigerred);
  756. }
  757. if (!hphl_sch) {
  758. hphl_trigerred++;
  759. pr_debug("%s: Removal HPHL trigerred %d\n",
  760. __func__, hphl_trigerred);
  761. }
  762. if (mic_trigerred && hphl_trigerred) {
  763. /*
  764. * extension cable is still plugged in
  765. * report it as LINEOUT device
  766. */
  767. goto report_unplug;
  768. }
  769. }
  770. }
  771. exit:
  772. WCD_MBHC_RSC_UNLOCK(mbhc);
  773. pr_debug("%s: leave\n", __func__);
  774. return IRQ_HANDLED;
  775. report_unplug:
  776. wcd_mbhc_elec_hs_report_unplug(mbhc);
  777. hphl_trigerred = 0;
  778. mic_trigerred = 0;
  779. WCD_MBHC_RSC_UNLOCK(mbhc);
  780. pr_debug("%s: leave\n", __func__);
  781. return IRQ_HANDLED;
  782. }
  783. static irqreturn_t wcd_mbhc_hs_ins_irq(int irq, void *data)
  784. {
  785. struct wcd_mbhc *mbhc = data;
  786. bool detection_type = 0, hphl_sch = 0, mic_sch = 0;
  787. u16 elect_result = 0;
  788. static u16 hphl_trigerred;
  789. static u16 mic_trigerred;
  790. pr_debug("%s: enter\n", __func__);
  791. if (!mbhc->mbhc_cfg->detect_extn_cable) {
  792. pr_debug("%s: Returning as Extension cable feature not enabled\n",
  793. __func__);
  794. return IRQ_HANDLED;
  795. }
  796. WCD_MBHC_RSC_LOCK(mbhc);
  797. WCD_MBHC_REG_READ(WCD_MBHC_ELECT_DETECTION_TYPE, detection_type);
  798. WCD_MBHC_REG_READ(WCD_MBHC_ELECT_RESULT, elect_result);
  799. pr_debug("%s: detection_type %d, elect_result %x\n", __func__,
  800. detection_type, elect_result);
  801. if (detection_type) {
  802. /* check if both Left and MIC Schmitt triggers are triggered */
  803. WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
  804. WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
  805. if (hphl_sch && mic_sch) {
  806. /* Go for plug type determination */
  807. pr_debug("%s: Go for plug type determination\n",
  808. __func__);
  809. goto determine_plug;
  810. } else {
  811. if (mic_sch) {
  812. mic_trigerred++;
  813. pr_debug("%s: Insertion MIC trigerred %d\n",
  814. __func__, mic_trigerred);
  815. WCD_MBHC_REG_UPDATE_BITS(
  816. WCD_MBHC_ELECT_SCHMT_ISRC,
  817. 0);
  818. msleep(20);
  819. WCD_MBHC_REG_UPDATE_BITS(
  820. WCD_MBHC_ELECT_SCHMT_ISRC,
  821. 1);
  822. }
  823. if (hphl_sch) {
  824. hphl_trigerred++;
  825. pr_debug("%s: Insertion HPHL trigerred %d\n",
  826. __func__, hphl_trigerred);
  827. }
  828. if (mic_trigerred && hphl_trigerred) {
  829. /* Go for plug type determination */
  830. pr_debug("%s: Go for plug type determination\n",
  831. __func__);
  832. goto determine_plug;
  833. }
  834. }
  835. }
  836. WCD_MBHC_RSC_UNLOCK(mbhc);
  837. pr_debug("%s: leave\n", __func__);
  838. return IRQ_HANDLED;
  839. determine_plug:
  840. /*
  841. * Disable HPHL trigger and MIC Schmitt triggers.
  842. * Setup for insertion detection.
  843. */
  844. pr_debug("%s: Disable insertion interrupt\n", __func__);
  845. wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
  846. false);
  847. WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
  848. hphl_trigerred = 0;
  849. mic_trigerred = 0;
  850. mbhc->is_extn_cable = true;
  851. mbhc->btn_press_intr = false;
  852. wcd_mbhc_detect_plug_type(mbhc);
  853. WCD_MBHC_RSC_UNLOCK(mbhc);
  854. pr_debug("%s: leave\n", __func__);
  855. return IRQ_HANDLED;
  856. }
  857. static struct wcd_mbhc_fn mbhc_fn = {
  858. .wcd_mbhc_hs_ins_irq = wcd_mbhc_hs_ins_irq,
  859. .wcd_mbhc_hs_rem_irq = wcd_mbhc_hs_rem_irq,
  860. .wcd_mbhc_detect_plug_type = wcd_mbhc_detect_plug_type,
  861. .wcd_mbhc_detect_anc_plug_type = wcd_mbhc_detect_anc_plug_type,
  862. .wcd_cancel_hs_detect_plug = wcd_cancel_hs_detect_plug,
  863. };
  864. /* Function: wcd_mbhc_legacy_init
  865. * @mbhc: MBHC function pointer
  866. * Description: Initialize MBHC legacy based function pointers to MBHC structure
  867. */
  868. void wcd_mbhc_legacy_init(struct wcd_mbhc *mbhc)
  869. {
  870. if (!mbhc) {
  871. pr_err("%s: mbhc is NULL\n", __func__);
  872. return;
  873. }
  874. mbhc->mbhc_fn = &mbhc_fn;
  875. INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
  876. }
  877. EXPORT_SYMBOL(wcd_mbhc_legacy_init);