wcd939x-mbhc.c 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/module.h>
  7. #include <linux/init.h>
  8. #include <linux/platform_device.h>
  9. #include <linux/device.h>
  10. #include <linux/printk.h>
  11. #include <linux/ratelimit.h>
  12. #include <linux/kernel.h>
  13. #include <linux/gpio.h>
  14. #include <linux/delay.h>
  15. #include <linux/regmap.h>
  16. #include <sound/pcm.h>
  17. #include <sound/pcm_params.h>
  18. #include <sound/soc.h>
  19. #include <sound/soc-dapm.h>
  20. #include <asoc/wcdcal-hwdep.h>
  21. #include <asoc/wcd-mbhc-v2-api.h>
  22. #include "wcd939x-registers.h"
  23. #include "internal.h"
  24. #if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
  25. #include <linux/soc/qcom/wcd939x-i2c.h>
  26. #endif
  27. #define WCD939X_ZDET_SUPPORTED true
  28. /* Z value defined in milliohm */
  29. #define WCD939X_ZDET_VAL_32 32000
  30. #define WCD939X_ZDET_VAL_400 400000
  31. #define WCD939X_ZDET_VAL_1200 1200000
  32. #define WCD939X_ZDET_VAL_100K 100000000
  33. /* Z floating defined in ohms */
  34. #define WCD939X_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE
  35. #define WCD939X_ZDET_NUM_MEASUREMENTS 900
  36. #define WCD939X_MBHC_GET_C1(c) ((c & 0xC000) >> 14)
  37. #define WCD939X_MBHC_GET_X1(x) (x & 0x3FFF)
  38. /* Z value compared in milliOhm */
  39. #define WCD939X_MBHC_IS_SECOND_RAMP_REQUIRED(z) false
  40. #define WCD939X_MBHC_ZDET_CONST (1071 * 1024)
  41. #define WCD939X_MBHC_MOISTURE_RREF R_24_KOHM
  42. #define OHMS_TO_MILLIOHMS 1000
  43. #define FLOAT_TO_FIXED_XTALK (1UL << 16)
  44. #define MAX_XTALK_ALPHA 255
  45. #define MIN_RL_EFF_MOHMS 1
  46. #define MAX_RL_EFF_MOHMS 900000
  47. #define HD2_CODE_BASE_VALUE 0x1D
  48. #define HD2_CODE_INV_RESOLUTION 4201025
  49. static struct wcd_mbhc_register
  50. wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
  51. WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
  52. WCD939X_MBHC_MECH, 0x80, 7, 0),
  53. WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
  54. WCD939X_MBHC_MECH, 0x40, 6, 0),
  55. WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
  56. WCD939X_MBHC_MECH, 0x20, 5, 0),
  57. WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
  58. WCD939X_PLUG_DETECT_CTL, 0x30, 4, 0),
  59. WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
  60. WCD939X_MBHC_ELECT, 0x08, 3, 0),
  61. WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
  62. WCD939X_MECH_DET_CURRENT, 0x1F, 0, 0),
  63. WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
  64. WCD939X_MBHC_MECH, 0x04, 2, 0),
  65. WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
  66. WCD939X_MBHC_MECH, 0x10, 4, 0),
  67. WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
  68. WCD939X_MBHC_MECH, 0x08, 3, 0),
  69. WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
  70. WCD939X_MBHC_MECH, 0x01, 0, 0),
  71. WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
  72. WCD939X_MBHC_ELECT, 0x06, 1, 0),
  73. WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
  74. WCD939X_MBHC_ELECT, 0x80, 7, 0),
  75. WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
  76. WCD939X_PLUG_DETECT_CTL, 0x0F, 0, 0),
  77. WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
  78. WCD939X_CTL_1, 0x03, 0, 0),
  79. WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
  80. WCD939X_CTL_2, 0x03, 0, 0),
  81. WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
  82. WCD939X_MBHC_RESULT_3, 0x08, 3, 0),
  83. WCD_MBHC_REGISTER("WCD_MBHC_IN2P_CLAMP_STATE",
  84. WCD939X_MBHC_RESULT_3, 0x10, 4, 0),
  85. WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
  86. WCD939X_MBHC_RESULT_3, 0x20, 5, 0),
  87. WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
  88. WCD939X_MBHC_RESULT_3, 0x80, 7, 0),
  89. WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
  90. WCD939X_MBHC_RESULT_3, 0x40, 6, 0),
  91. WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
  92. WCD939X_HPH_OCP_CTL, 0x10, 4, 0),
  93. WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
  94. WCD939X_MBHC_RESULT_3, 0x07, 0, 0),
  95. WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
  96. WCD939X_MBHC_ELECT, 0x70, 4, 0),
  97. WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
  98. WCD939X_MBHC_RESULT_3, 0xFF, 0, 0),
  99. WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
  100. WCD939X_MICB2, 0xC0, 6, 0),
  101. WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
  102. WCD939X_CNP_WG_TIME, 0xFF, 0, 0),
  103. WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
  104. WCD939X_HPH, 0x40, 6, 0),
  105. WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
  106. WCD939X_HPH, 0x80, 7, 0),
  107. WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
  108. WCD939X_HPH, 0xC0, 6, 0),
  109. WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
  110. WCD939X_MBHC_RESULT_3, 0x10, 4, 0),
  111. WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
  112. 0, 0, 0, 0),
  113. WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN",
  114. WCD939X_CTL_BCS, 0x02, 1, 0),
  115. WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS",
  116. WCD939X_FSM_STATUS, 0x01, 0, 0),
  117. WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL",
  118. WCD939X_CTL_2, 0x70, 4, 0),
  119. WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS",
  120. WCD939X_FSM_STATUS, 0x20, 5, 0),
  121. WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND",
  122. WCD939X_PA_CTL2, 0x40, 6, 0),
  123. WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND",
  124. WCD939X_PA_CTL2, 0x10, 4, 0),
  125. WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN",
  126. WCD939X_L_TEST, 0x01, 0, 0),
  127. WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN",
  128. WCD939X_R_TEST, 0x01, 0, 0),
  129. WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS",
  130. WCD939X_INTR_STATUS_0, 0x80, 7, 0),
  131. WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS",
  132. WCD939X_INTR_STATUS_0, 0x20, 5, 0),
  133. WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN",
  134. WCD939X_CTL_1, 0x08, 3, 0),
  135. WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", WCD939X_FSM_STATUS,
  136. 0x40, 6, 0),
  137. WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", WCD939X_FSM_STATUS,
  138. 0x80, 7, 0),
  139. WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", WCD939X_ADC_RESULT,
  140. 0xFF, 0, 0),
  141. WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT", WCD939X_MICB2, 0x3F, 0, 0),
  142. WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE",
  143. WCD939X_CTL_1, 0x10, 4, 0),
  144. WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE",
  145. WCD939X_CTL_1, 0x04, 2, 0),
  146. WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN",
  147. WCD939X_MBHC_ZDET, 0x02, 1, 0),
  148. };
  149. static const struct wcd_mbhc_intr intr_ids = {
  150. .mbhc_sw_intr = WCD939X_IRQ_MBHC_SW_DET,
  151. .mbhc_btn_press_intr = WCD939X_IRQ_MBHC_BUTTON_PRESS_DET,
  152. .mbhc_btn_release_intr = WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET,
  153. .mbhc_hs_ins_intr = WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
  154. .mbhc_hs_rem_intr = WCD939X_IRQ_MBHC_ELECT_INS_REM_DET,
  155. .hph_left_ocp = WCD939X_IRQ_HPHL_OCP_INT,
  156. .hph_right_ocp = WCD939X_IRQ_HPHR_OCP_INT,
  157. };
  158. struct wcd939x_mbhc_zdet_param {
  159. u16 ldo_ctl;
  160. u16 noff;
  161. u16 nshift;
  162. u16 btn5;
  163. u16 btn6;
  164. u16 btn7;
  165. };
  166. static int wcd939x_mbhc_request_irq(struct snd_soc_component *component,
  167. int irq, irq_handler_t handler,
  168. const char *name, void *data)
  169. {
  170. struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev);
  171. return wcd_request_irq(&wcd939x->irq_info, irq, name, handler, data);
  172. }
  173. static void wcd939x_mbhc_irq_control(struct snd_soc_component *component,
  174. int irq, bool enable)
  175. {
  176. struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev);
  177. if (enable)
  178. wcd_enable_irq(&wcd939x->irq_info, irq);
  179. else
  180. wcd_disable_irq(&wcd939x->irq_info, irq);
  181. }
  182. static int wcd939x_mbhc_free_irq(struct snd_soc_component *component,
  183. int irq, void *data)
  184. {
  185. struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev);
  186. wcd_free_irq(&wcd939x->irq_info, irq, data);
  187. return 0;
  188. }
  189. static void wcd939x_mbhc_clk_setup(struct snd_soc_component *component,
  190. bool enable)
  191. {
  192. if (enable)
  193. snd_soc_component_update_bits(component, WCD939X_CTL_1,
  194. 0x80, 0x80);
  195. else
  196. snd_soc_component_update_bits(component, WCD939X_CTL_1,
  197. 0x80, 0x00);
  198. }
  199. static int wcd939x_mbhc_btn_to_num(struct snd_soc_component *component)
  200. {
  201. return snd_soc_component_read(component, WCD939X_MBHC_RESULT_3) & 0x7;
  202. }
  203. static void wcd939x_mbhc_mbhc_bias_control(struct snd_soc_component *component,
  204. bool enable)
  205. {
  206. if (enable)
  207. snd_soc_component_update_bits(component, WCD939X_MBHC_ELECT,
  208. 0x01, 0x01);
  209. else
  210. snd_soc_component_update_bits(component, WCD939X_MBHC_ELECT,
  211. 0x01, 0x00);
  212. }
  213. static void wcd939x_mbhc_program_btn_thr(struct snd_soc_component *component,
  214. s16 *btn_low, s16 *btn_high,
  215. int num_btn, bool is_micbias)
  216. {
  217. int i;
  218. int vth;
  219. if (num_btn > WCD_MBHC_DEF_BUTTONS) {
  220. dev_err_ratelimited(component->dev, "%s: invalid number of buttons: %d\n",
  221. __func__, num_btn);
  222. return;
  223. }
  224. for (i = 0; i < num_btn; i++) {
  225. vth = ((btn_high[i] * 2) / 25) & 0x3F;
  226. snd_soc_component_update_bits(component, WCD939X_MBHC_BTN0 + i,
  227. 0xFC, vth << 2);
  228. dev_dbg(component->dev, "%s: btn_high[%d]: %d, vth: %d\n",
  229. __func__, i, btn_high[i], vth);
  230. }
  231. }
  232. static bool wcd939x_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock)
  233. {
  234. struct snd_soc_component *component = mbhc->component;
  235. struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev);
  236. wcd939x->wakeup((void*)wcd939x, lock);
  237. return true;
  238. }
  239. static int wcd939x_mbhc_register_notifier(struct wcd_mbhc *mbhc,
  240. struct notifier_block *nblock,
  241. bool enable)
  242. {
  243. struct wcd939x_mbhc *wcd939x_mbhc;
  244. wcd939x_mbhc = container_of(mbhc, struct wcd939x_mbhc, wcd_mbhc);
  245. if (enable)
  246. return blocking_notifier_chain_register(&wcd939x_mbhc->notifier,
  247. nblock);
  248. else
  249. return blocking_notifier_chain_unregister(
  250. &wcd939x_mbhc->notifier, nblock);
  251. }
  252. static bool wcd939x_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num)
  253. {
  254. u8 val = 0;
  255. if (micb_num == MIC_BIAS_2) {
  256. val = ((snd_soc_component_read(mbhc->component,
  257. WCD939X_MICB2) & 0xC0)
  258. >> 6);
  259. if (val == 0x01)
  260. return true;
  261. }
  262. return false;
  263. }
  264. static bool wcd939x_mbhc_hph_pa_on_status(struct snd_soc_component *component)
  265. {
  266. return (snd_soc_component_read(component, WCD939X_HPH) & 0xC0) ?
  267. true : false;
  268. }
  269. static void wcd939x_mbhc_hph_l_pull_up_control(
  270. struct snd_soc_component *component,
  271. int pull_up_cur)
  272. {
  273. /* Default pull up current to 2uA */
  274. if (pull_up_cur > HS_PULLUP_I_OFF || pull_up_cur < HS_PULLUP_I_3P0_UA ||
  275. pull_up_cur == HS_PULLUP_I_DEFAULT)
  276. pull_up_cur = HS_PULLUP_I_2P0_UA;
  277. dev_dbg(component->dev, "%s: HS pull up current:%d\n",
  278. __func__, pull_up_cur);
  279. snd_soc_component_update_bits(component,
  280. WCD939X_MECH_DET_CURRENT,
  281. 0x1F, pull_up_cur);
  282. }
  283. static int wcd939x_mbhc_request_micbias(struct snd_soc_component *component,
  284. int micb_num, int req)
  285. {
  286. int ret = 0;
  287. ret = wcd939x_micbias_control(component, micb_num, req, false);
  288. return ret;
  289. }
  290. static void wcd939x_mbhc_micb_ramp_control(struct snd_soc_component *component,
  291. bool enable)
  292. {
  293. if (enable) {
  294. snd_soc_component_update_bits(component, WCD939X_MICB2_RAMP,
  295. 0x1C, 0x0C);
  296. snd_soc_component_update_bits(component, WCD939X_MICB2_RAMP,
  297. 0x80, 0x80);
  298. } else {
  299. snd_soc_component_update_bits(component, WCD939X_MICB2_RAMP,
  300. 0x80, 0x00);
  301. snd_soc_component_update_bits(component, WCD939X_MICB2_RAMP,
  302. 0x1C, 0x00);
  303. }
  304. }
  305. static struct firmware_cal *wcd939x_get_hwdep_fw_cal(struct wcd_mbhc *mbhc,
  306. enum wcd_cal_type type)
  307. {
  308. struct wcd939x_mbhc *wcd939x_mbhc;
  309. struct firmware_cal *hwdep_cal;
  310. struct snd_soc_component *component = mbhc->component;
  311. wcd939x_mbhc = container_of(mbhc, struct wcd939x_mbhc, wcd_mbhc);
  312. if (!component) {
  313. pr_err_ratelimited("%s: NULL component pointer\n", __func__);
  314. return NULL;
  315. }
  316. hwdep_cal = wcdcal_get_fw_cal(wcd939x_mbhc->fw_data, type);
  317. if (!hwdep_cal)
  318. dev_err_ratelimited(component->dev, "%s: cal not sent by %d\n",
  319. __func__, type);
  320. return hwdep_cal;
  321. }
  322. static int wcd939x_mbhc_micb_ctrl_threshold_mic(
  323. struct snd_soc_component *component,
  324. int micb_num, bool req_en)
  325. {
  326. struct wcd939x_pdata *pdata = dev_get_platdata(component->dev);
  327. int rc, micb_mv;
  328. if (micb_num != MIC_BIAS_2)
  329. return -EINVAL;
  330. /*
  331. * If device tree micbias level is already above the minimum
  332. * voltage needed to detect threshold microphone, then do
  333. * not change the micbias, just return.
  334. */
  335. if (pdata->micbias.micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
  336. return 0;
  337. micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : pdata->micbias.micb2_mv;
  338. rc = wcd939x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);
  339. return rc;
  340. }
  341. static inline void wcd939x_mbhc_get_result_params(struct wcd939x_priv *wcd939x,
  342. s16 *d1_a, u16 noff,
  343. int32_t *zdet)
  344. {
  345. int i;
  346. int val, val1;
  347. s16 c1;
  348. s32 x1, d1;
  349. int32_t denom;
  350. int minCode_param[] = {
  351. 3277, 1639, 820, 410, 205, 103, 52, 26
  352. };
  353. regmap_update_bits(wcd939x->regmap, WCD939X_MBHC_ZDET, 0x20, 0x20);
  354. for (i = 0; i < WCD939X_ZDET_NUM_MEASUREMENTS; i++) {
  355. regmap_read(wcd939x->regmap, WCD939X_MBHC_RESULT_2, &val);
  356. if (val & 0x80)
  357. break;
  358. }
  359. val = val << 0x8;
  360. regmap_read(wcd939x->regmap, WCD939X_MBHC_RESULT_1, &val1);
  361. val |= val1;
  362. regmap_update_bits(wcd939x->regmap, WCD939X_MBHC_ZDET, 0x20, 0x00);
  363. x1 = WCD939X_MBHC_GET_X1(val);
  364. c1 = WCD939X_MBHC_GET_C1(val);
  365. /* If ramp is not complete, give additional 5ms */
  366. if ((c1 < 2) && x1)
  367. usleep_range(5000, 5050);
  368. if (!c1 || !x1) {
  369. dev_dbg(wcd939x->dev,
  370. "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n",
  371. __func__, c1, x1);
  372. goto ramp_down;
  373. }
  374. d1 = d1_a[c1];
  375. denom = (x1 * d1) - (1 << (14 - noff));
  376. if (denom > 0)
  377. *zdet = (WCD939X_MBHC_ZDET_CONST * 1000) / denom;
  378. else if (x1 < minCode_param[noff])
  379. *zdet = WCD939X_ZDET_FLOATING_IMPEDANCE;
  380. dev_dbg(wcd939x->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n",
  381. __func__, d1, c1, x1, *zdet);
  382. ramp_down:
  383. i = 0;
  384. while (x1) {
  385. regmap_read(wcd939x->regmap,
  386. WCD939X_MBHC_RESULT_1, &val);
  387. regmap_read(wcd939x->regmap,
  388. WCD939X_MBHC_RESULT_2, &val1);
  389. val = val << 0x08;
  390. val |= val1;
  391. x1 = WCD939X_MBHC_GET_X1(val);
  392. i++;
  393. if (i == WCD939X_ZDET_NUM_MEASUREMENTS)
  394. break;
  395. }
  396. }
  397. static void wcd939x_mbhc_zdet_ramp(struct snd_soc_component *component,
  398. struct wcd939x_mbhc_zdet_param *zdet_param,
  399. int32_t *zl, int32_t *zr, s16 *d1_a)
  400. {
  401. struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev);
  402. int32_t zdet = 0;
  403. snd_soc_component_update_bits(component, WCD939X_ZDET_ANA_CTL, 0xF0,
  404. 0x80 | (zdet_param->ldo_ctl << 4));
  405. snd_soc_component_update_bits(component, WCD939X_MBHC_BTN5, 0xFC,
  406. zdet_param->btn5);
  407. snd_soc_component_update_bits(component, WCD939X_MBHC_BTN6, 0xFC,
  408. zdet_param->btn6);
  409. snd_soc_component_update_bits(component, WCD939X_MBHC_BTN7, 0xFC,
  410. zdet_param->btn7);
  411. snd_soc_component_update_bits(component, WCD939X_ZDET_ANA_CTL,
  412. 0x0F, zdet_param->noff);
  413. snd_soc_component_update_bits(component, WCD939X_ZDET_RAMP_CTL,
  414. 0x0F, zdet_param->nshift);
  415. snd_soc_component_update_bits(component, WCD939X_ZDET_RAMP_CTL,
  416. 0x70, 0x60); /*acc1_min_63 */
  417. if (!zl)
  418. goto z_right;
  419. /* Start impedance measurement for HPH_L */
  420. regmap_update_bits(wcd939x->regmap,
  421. WCD939X_MBHC_ZDET, 0x80, 0x80);
  422. dev_dbg(wcd939x->dev, "%s: ramp for HPH_L, noff = %d\n",
  423. __func__, zdet_param->noff);
  424. wcd939x_mbhc_get_result_params(wcd939x, d1_a, zdet_param->noff, &zdet);
  425. regmap_update_bits(wcd939x->regmap,
  426. WCD939X_MBHC_ZDET, 0x80, 0x00);
  427. *zl = zdet;
  428. z_right:
  429. if (!zr)
  430. return;
  431. /* Start impedance measurement for HPH_R */
  432. regmap_update_bits(wcd939x->regmap,
  433. WCD939X_MBHC_ZDET, 0x40, 0x40);
  434. dev_dbg(wcd939x->dev, "%s: ramp for HPH_R, noff = %d\n",
  435. __func__, zdet_param->noff);
  436. wcd939x_mbhc_get_result_params(wcd939x, d1_a, zdet_param->noff, &zdet);
  437. regmap_update_bits(wcd939x->regmap,
  438. WCD939X_MBHC_ZDET, 0x40, 0x00);
  439. *zr = zdet;
  440. }
  441. static inline void wcd939x_wcd_mbhc_qfuse_cal(
  442. struct snd_soc_component *component,
  443. int32_t *z_val, int flag_l_r)
  444. {
  445. s16 q1;
  446. int q1_cal;
  447. q1 = snd_soc_component_read(component,
  448. WCD939X_EFUSE_REG_21 + flag_l_r);
  449. if (q1 & 0x80)
  450. q1_cal = (10000 - ((q1 & 0x7F) * 10));
  451. else
  452. q1_cal = (10000 + (q1 * 10));
  453. if (q1_cal > 0)
  454. *z_val = ((*z_val) * 10000) / q1_cal;
  455. }
  456. static void update_hd2_codes(struct regmap *regmap, u32 r_gnd_res_tot_mohms, u32 r_load_eff)
  457. {
  458. u64 hd2_delta = 0;
  459. if (!regmap)
  460. return;
  461. hd2_delta = (HD2_CODE_INV_RESOLUTION * (u64) r_gnd_res_tot_mohms +
  462. FLOAT_TO_FIXED_XTALK * (u64) ((r_gnd_res_tot_mohms + r_load_eff) / 2)) /
  463. (FLOAT_TO_FIXED_XTALK * (u64) (r_gnd_res_tot_mohms + r_load_eff));
  464. if (hd2_delta >= HD2_CODE_BASE_VALUE) {
  465. regmap_update_bits(regmap, WCD939X_RDAC_HD2_CTL_L, 0x1F, 0x00);
  466. regmap_update_bits(regmap, WCD939X_RDAC_HD2_CTL_R, 0x1F, 0x00);
  467. } else {
  468. regmap_update_bits(regmap, WCD939X_RDAC_HD2_CTL_L, 0x1F,
  469. HD2_CODE_BASE_VALUE - hd2_delta);
  470. regmap_update_bits(regmap, WCD939X_RDAC_HD2_CTL_R, 0x1F,
  471. HD2_CODE_BASE_VALUE - hd2_delta);
  472. }
  473. }
  474. static u8 get_xtalk_scale(u32 gain)
  475. {
  476. u8 i;
  477. int target, residue;
  478. if (gain == 0)
  479. return MAX_XTALK_SCALE;
  480. target = FLOAT_TO_FIXED_XTALK / ((int) gain);
  481. residue = target;
  482. for (i = 0; i <= MAX_XTALK_SCALE; i++) {
  483. residue = target - (1 << ((int)((u32) i)));
  484. if (residue < 0)
  485. return i;
  486. }
  487. return MAX_XTALK_SCALE;
  488. }
  489. static u8 get_xtalk_alpha(u32 gain, u8 scale)
  490. {
  491. u32 two_exp_scale, round_offset, alpha;
  492. if (gain == 0)
  493. return MIN_XTALK_ALPHA;
  494. two_exp_scale = 1 << ((u32) scale);
  495. round_offset = FLOAT_TO_FIXED_XTALK / 2;
  496. alpha = (((gain * two_exp_scale - FLOAT_TO_FIXED_XTALK) * 255) + round_offset)
  497. / FLOAT_TO_FIXED_XTALK;
  498. return (alpha <= MAX_XTALK_ALPHA) ? ((u8) alpha) : MAX_XTALK_ALPHA;
  499. }
  500. static u32 get_v_common_gnd_factor(u32 r_gnd_res_tot_mohms, u32 r_load_eff_mohms,
  501. u32 r_aud_res_tot_mohms)
  502. {
  503. /* Proof 1: The numerator does not overflow.
  504. * r_gnd_res_tot_mohms = r_gnd_int_fet_mohms + r_gnd_ext_fet_mohms + r_gnd_par_tot_mohms =
  505. * r_gnd_int_fet_mohms + r_gnd_ext_fet_mohms + r_gnd_par_route1_mohms +
  506. * r_gnd_par_route2_mohms
  507. *
  508. * r_gnd_int_fet_mohms, r_gnd_ext_fet_mohms, r_gnd_par_route{1,2}_mohms are all less
  509. * than MAX_USBCSS_HS_IMPEDANCE_MOHMS
  510. * -->
  511. * FLOAT_TO_FIXED_XTALK * r_gnd_res_tot_mohms <=
  512. * FLOAT_TO_FIXED_XTALK * 4 * MAX_USBCSS_HS_IMPEDANCE_MOHMS =
  513. * (1 << 16) * 4 * 20,000 = 65,536 * 80,000 = 3,932,160,000 <= 2^32 - 1 =
  514. * 4,294,967,295 = U32_MAX
  515. *
  516. * Proof 2: The denominator is greater than 0.
  517. * r_load_eff_mohms >= MIN_RL_EFF_MOHMS = 1 > 0
  518. * -->
  519. * r_load_eff_mohms + r_aud_res_tot_mohms + r_gnd_res_tot_mohms > 0
  520. *
  521. * Proof 3: The deonominator does not overflow.
  522. * r_load_eff_mohms <= MAX_RL_EFF_MOHMS
  523. * r_aud_res_tot_mohms and r_gnd_res_tot_mohms <= MAX_USBCSS_HS_IMPEDANCE_MOHMS
  524. * -->
  525. * r_load_eff_mohms + r_aud_res_tot_mohms + r_gnd_res_tot_mohms <=
  526. * MAX_RL_EFF_MOHMS + 2 * MAX_USBCSS_HS_IMPEDANCE_MOHMS = 900,000 + 2 * 20,000 = 940,000
  527. * <= U32_MAX = 2^32 - 1 = 4,294,967,295
  528. */
  529. return FLOAT_TO_FIXED_XTALK * r_gnd_res_tot_mohms /
  530. (r_load_eff_mohms + r_aud_res_tot_mohms + r_gnd_res_tot_mohms);
  531. }
  532. static u32 get_v_feedback_tap_factor_digital(u32 r_gnd_int_fet_mohms, u32 r_gnd_par_route1_mohms,
  533. u32 r_load_eff_mohms, u32 r_gnd_res_tot_mohms,
  534. u32 r_aud_res_tot_mohms)
  535. {
  536. /* Proof 4: The numerator does not overflow.
  537. * r_gnd_int_fet_mohms and r_gnd_par_route1_mohms <= MAX_USBCSS_HS_IMPEDANCE_MOHMS
  538. * -->
  539. * FLOAT_TO_FIXED_XTALK * (r_gnd_int_fet_mohms + r_gnd_par_route1_mohms) <=
  540. * FLOAT_TO_FIXED_XTALK * 2 * MAX_USBCSS_HS_IMPEDANCE_MOHMS =
  541. * (1 << 16) * 2 * 20,000 = 65,536 * 40,000 = 2,621,440,000 <= 2^32 - 1 =
  542. * 4,294,967,295 = U32_MAX
  543. *
  544. * The denominator is greater than 0: See Proof 2
  545. * The deonominator does not overflow: See Proof 3
  546. */
  547. return FLOAT_TO_FIXED_XTALK * (r_gnd_int_fet_mohms + r_gnd_par_route1_mohms) /
  548. (r_load_eff_mohms + r_gnd_res_tot_mohms + r_aud_res_tot_mohms);
  549. }
  550. static u32 get_v_feedback_tap_factor_analog(u32 r_gnd_par_route2_mohms, u32 r_load_eff_mohms,
  551. u32 r_gnd_res_tot_mohms, u32 r_aud_res_tot_mohms)
  552. {
  553. /* Proof 5: The numerator does not overflow.
  554. * r_gnd_res_tot_mohms = r_gnd_int_fet_mohms + r_gnd_ext_fet_mohms + r_gnd_par_tot_mohms =
  555. * r_gnd_int_fet_mohms + r_gnd_ext_fet_mohms + r_gnd_par_route1_mohms +
  556. * r_gnd_par_route2_mohms
  557. *
  558. * r_gnd_res_tot_mohms - r_gnd_par_route2_mohms =
  559. * r_gnd_int_fet_mohms + r_gnd_ext_fet_mohms + r_gnd_par_route1_mohms
  560. *
  561. * r_gnd_int_fet_mohms, r_gnd_ext_fet_mohms, r_gnd_par_route1_mohms
  562. * <= MAX_USBCSS_HS_IMPEDANCE_MOHMS = 20,000
  563. * -->
  564. * FLOAT_TO_FIXED_XTALK * (r_gnd_int_fet_mohms + r_gnd_ext_fet_mohms +
  565. * r_gnd_par_route1_mohms)
  566. * <= FLOAT_TO_FIXED_XTALK * 3 * MAX_USBCSS_HS_IMPEDANCE_MOHMS =
  567. * (1 << 16) * 3 * 20,000 = 65,536 * 60,000 = 3,932,160,000 <= 2^32 - 1 =
  568. * 4,294,967,295 = U32_MAX
  569. *
  570. * The denominator is greater than 0: See Proof 2
  571. * The deonominator does not overflow: See Proof 3
  572. */
  573. return FLOAT_TO_FIXED_XTALK * (r_gnd_res_tot_mohms - r_gnd_par_route2_mohms) /
  574. (r_load_eff_mohms + r_gnd_res_tot_mohms + r_aud_res_tot_mohms);
  575. }
  576. static u32 get_xtalk_gain(u32 v_common_gnd_factor, u32 v_feedback_tap_factor)
  577. {
  578. return v_common_gnd_factor - v_feedback_tap_factor;
  579. }
  580. static void update_xtalk_scale_and_alpha(struct wcd939x_pdata *pdata, struct regmap *regmap)
  581. {
  582. u32 r_gnd_res_tot_mohms = 0, r_gnd_int_fet_mohms = 0, v_common_gnd_factor = 0;
  583. u32 v_feedback_tap_factor = 0, xtalk_gain = 0;
  584. if (!pdata || pdata->usbcss_hs.xtalk_config == XTALK_NONE)
  585. return;
  586. /* Orientation-dependent ground impedance parameters */
  587. #if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
  588. if (wcd_usbss_get_sbu_switch_orientation() == GND_SBU2_ORIENTATION_A) {
  589. r_gnd_res_tot_mohms = pdata->usbcss_hs.r_gnd_sbu2_res_tot_mohms;
  590. r_gnd_int_fet_mohms = pdata->usbcss_hs.r_gnd_sbu2_int_fet_mohms;
  591. } else if (wcd_usbss_get_sbu_switch_orientation() == GND_SBU1_ORIENTATION_B) {
  592. r_gnd_res_tot_mohms = pdata->usbcss_hs.r_gnd_sbu1_res_tot_mohms;
  593. r_gnd_int_fet_mohms = pdata->usbcss_hs.r_gnd_sbu1_int_fet_mohms;
  594. } else {
  595. pdata->usbcss_hs.scale_l = MAX_XTALK_SCALE;
  596. pdata->usbcss_hs.alpha_l = MIN_XTALK_ALPHA;
  597. pdata->usbcss_hs.scale_r = MAX_XTALK_SCALE;
  598. pdata->usbcss_hs.alpha_r = MIN_XTALK_ALPHA;
  599. return;
  600. }
  601. #endif
  602. /* Recall assumptions about L and R channel impedance parameters being equivalent */
  603. /* Xtalk gain calculation */
  604. v_common_gnd_factor = get_v_common_gnd_factor(r_gnd_res_tot_mohms,
  605. pdata->usbcss_hs.r_load_eff_l_mohms,
  606. pdata->usbcss_hs.r_aud_res_tot_l_mohms);
  607. if (pdata->usbcss_hs.xtalk_config == XTALK_ANALOG) {
  608. v_feedback_tap_factor = get_v_feedback_tap_factor_analog(
  609. pdata->usbcss_hs.r_gnd_par_route2_mohms,
  610. pdata->usbcss_hs.r_load_eff_l_mohms,
  611. r_gnd_res_tot_mohms,
  612. pdata->usbcss_hs.r_aud_res_tot_l_mohms);
  613. /* Update HD2 codes for analog xtalk */
  614. update_hd2_codes(regmap, r_gnd_res_tot_mohms, pdata->usbcss_hs.r_load_eff_l_mohms);
  615. } else {
  616. v_feedback_tap_factor = get_v_feedback_tap_factor_digital(
  617. r_gnd_int_fet_mohms,
  618. pdata->usbcss_hs.r_gnd_par_route1_mohms,
  619. pdata->usbcss_hs.r_load_eff_l_mohms,
  620. r_gnd_res_tot_mohms,
  621. pdata->usbcss_hs.r_aud_res_tot_l_mohms);
  622. }
  623. xtalk_gain = get_xtalk_gain(v_common_gnd_factor, v_feedback_tap_factor);
  624. /* Store scale and alpha values */
  625. pdata->usbcss_hs.scale_l = get_xtalk_scale(xtalk_gain);
  626. pdata->usbcss_hs.alpha_l = get_xtalk_alpha(xtalk_gain, pdata->usbcss_hs.scale_l);
  627. pdata->usbcss_hs.scale_r = pdata->usbcss_hs.scale_l;
  628. pdata->usbcss_hs.alpha_r = pdata->usbcss_hs.alpha_l;
  629. }
  630. static void update_ext_fet_res(struct wcd939x_pdata *pdata, u32 r_gnd_ext_fet_mohms)
  631. {
  632. if (!pdata)
  633. return;
  634. pdata->usbcss_hs.r_gnd_ext_fet_mohms = (r_gnd_ext_fet_mohms > MAX_USBCSS_HS_IMPEDANCE_MOHMS)
  635. ? MAX_USBCSS_HS_IMPEDANCE_MOHMS
  636. : r_gnd_ext_fet_mohms;
  637. pdata->usbcss_hs.r_aud_ext_fet_l_mohms = pdata->usbcss_hs.r_gnd_ext_fet_mohms;
  638. pdata->usbcss_hs.r_aud_ext_fet_r_mohms = pdata->usbcss_hs.r_gnd_ext_fet_mohms;
  639. pdata->usbcss_hs.r_gnd_sbu1_res_tot_mohms = get_r_gnd_res_tot_mohms(
  640. pdata->usbcss_hs.r_gnd_sbu1_int_fet_mohms,
  641. pdata->usbcss_hs.r_gnd_ext_fet_mohms,
  642. pdata->usbcss_hs.r_gnd_par_tot_mohms);
  643. pdata->usbcss_hs.r_gnd_sbu2_res_tot_mohms = get_r_gnd_res_tot_mohms(
  644. pdata->usbcss_hs.r_gnd_sbu2_int_fet_mohms,
  645. pdata->usbcss_hs.r_gnd_ext_fet_mohms,
  646. pdata->usbcss_hs.r_gnd_par_tot_mohms);
  647. pdata->usbcss_hs.r_aud_res_tot_l_mohms = get_r_aud_res_tot_mohms(
  648. pdata->usbcss_hs.r_aud_int_fet_l_mohms,
  649. pdata->usbcss_hs.r_aud_ext_fet_l_mohms);
  650. pdata->usbcss_hs.r_aud_res_tot_r_mohms = get_r_aud_res_tot_mohms(
  651. pdata->usbcss_hs.r_aud_int_fet_r_mohms,
  652. pdata->usbcss_hs.r_aud_ext_fet_r_mohms);
  653. }
  654. static void wcd939x_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr)
  655. {
  656. struct snd_soc_component *component = mbhc->component;
  657. struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev);
  658. struct wcd939x_pdata *pdata = dev_get_platdata(wcd939x->dev);
  659. s16 reg0, reg1, reg2, reg3, reg4;
  660. uint32_t zdiff_val = 0, r_gnd_int_fet_mohms = 0, rl_eff_mohms = 0, r_gnd_ext_fet_mohms = 0;
  661. uint32_t *zdiff = &zdiff_val;
  662. int32_t z1L, z1R, z1Ls, z1Diff;
  663. int zMono, z_diff1, z_diff2;
  664. bool is_fsm_disable = false;
  665. struct wcd939x_mbhc_zdet_param zdet_param = {4, 0, 6, 0x18, 0x60, 0x78};
  666. struct wcd939x_mbhc_zdet_param *zdet_param_ptr = &zdet_param;
  667. s16 d1[] = {0, 30, 30, 6};
  668. WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
  669. /* Turn on RX supplies */
  670. if (wcd939x->version == WCD939X_VERSION_2_0) {
  671. /* Start up Buck/Flyback, Enable RX bias, Use MBHC RCO for MBHC Zdet, Enable Vneg */
  672. regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x4C, 0x4C);
  673. /* Wait 100us for settling */
  674. usleep_range(100, 110);
  675. /* Enable VNEGDAC_LDO */
  676. regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x10, 0x10);
  677. /* Wait 100us for settling */
  678. usleep_range(100, 110);
  679. /* Keep PA left/right channels disabled */
  680. regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x01, 0x01);
  681. /* Enable VPOS */
  682. regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x20, 0x20);
  683. /* Wait 500us for settling */
  684. usleep_range(500, 510);
  685. }
  686. /* Store register values */
  687. reg0 = snd_soc_component_read(component, WCD939X_MBHC_BTN5);
  688. reg1 = snd_soc_component_read(component, WCD939X_MBHC_BTN6);
  689. reg2 = snd_soc_component_read(component, WCD939X_MBHC_BTN7);
  690. reg3 = snd_soc_component_read(component, WCD939X_CTL_CLK);
  691. reg4 = snd_soc_component_read(component, WCD939X_ZDET_ANA_CTL);
  692. /* Disable the detection FSM */
  693. if (snd_soc_component_read(component, WCD939X_MBHC_ELECT) & 0x80) {
  694. is_fsm_disable = true;
  695. regmap_update_bits(wcd939x->regmap,
  696. WCD939X_MBHC_ELECT, 0x80, 0x00);
  697. }
  698. /* For NO-jack, disable L_DET_EN before Z-det measurements */
  699. if (mbhc->hphl_swh)
  700. regmap_update_bits(wcd939x->regmap,
  701. WCD939X_MBHC_MECH, 0x80, 0x00);
  702. /* Turn off 100k pull down on HPHL */
  703. regmap_update_bits(wcd939x->regmap,
  704. WCD939X_MBHC_MECH, 0x01, 0x00);
  705. /* Disable surge protection before impedance detection.
  706. * This is done to give correct value for high impedance.
  707. */
  708. regmap_update_bits(wcd939x->regmap,
  709. WCD939X_HPHLR_SURGE_EN, 0xC0, 0x00);
  710. /* 1ms delay needed after disable surge protection */
  711. usleep_range(1000, 1010);
  712. #if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
  713. /* Disable sense switch and MIC for USB-C analog platforms */
  714. if (mbhc->mbhc_cfg->enable_usbc_analog) {
  715. wcd_usbss_set_switch_settings_enable(SENSE_SWITCHES, USBSS_SWITCH_DISABLE);
  716. wcd_usbss_set_switch_settings_enable(MIC_SWITCHES, USBSS_SWITCH_DISABLE);
  717. }
  718. #endif
  719. /* L-channel impedance */
  720. wcd939x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1);
  721. if ((z1L == WCD939X_ZDET_FLOATING_IMPEDANCE) || (z1L > WCD939X_ZDET_VAL_100K)) {
  722. *zl = WCD939X_ZDET_FLOATING_IMPEDANCE;
  723. } else {
  724. *zl = z1L;
  725. wcd939x_wcd_mbhc_qfuse_cal(component, zl, 0);
  726. }
  727. /* Differential measurement for USB-C analog platforms */
  728. if (mbhc->mbhc_cfg->enable_usbc_analog) {
  729. dev_dbg(component->dev, "%s: effective impedance on HPH_L = %d(mohms)\n",
  730. __func__, *zl);
  731. goto diff_impedance;
  732. }
  733. dev_dbg(component->dev, "%s: impedance on HPH_L = %d(mohms)\n",
  734. __func__, *zl);
  735. /* R-channel impedance */
  736. wcd939x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1);
  737. if ((z1R == WCD939X_ZDET_FLOATING_IMPEDANCE) || (z1R > WCD939X_ZDET_VAL_100K)) {
  738. *zr = WCD939X_ZDET_FLOATING_IMPEDANCE;
  739. } else {
  740. *zr = z1R;
  741. wcd939x_wcd_mbhc_qfuse_cal(component, zr, 1);
  742. }
  743. dev_dbg(component->dev, "%s: impedance on HPH_R = %d(mohms)\n",
  744. __func__, *zr);
  745. /* Convert from mohms to ohms (rounded) */
  746. *zl = (*zl + OHMS_TO_MILLIOHMS / 2) / OHMS_TO_MILLIOHMS;
  747. *zr = (*zr + OHMS_TO_MILLIOHMS / 2) / OHMS_TO_MILLIOHMS;
  748. goto mono_stereo_detection;
  749. diff_impedance:
  750. #if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
  751. /* Disable AGND switch */
  752. wcd_usbss_set_switch_settings_enable(AGND_SWITCHES, USBSS_SWITCH_DISABLE);
  753. #endif
  754. /* Enable HPHR NCLAMP */
  755. regmap_update_bits(wcd939x->regmap, WCD939X_HPHLR_SURGE_MISC1, 0x08, 0x08);
  756. /* Diffrential impedance */
  757. wcd939x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1Diff, NULL, d1);
  758. if ((z1Diff == WCD939X_ZDET_FLOATING_IMPEDANCE) || (z1Diff > WCD939X_ZDET_VAL_100K)) {
  759. *zdiff = WCD939X_ZDET_FLOATING_IMPEDANCE;
  760. } else {
  761. *zdiff = z1Diff;
  762. wcd939x_wcd_mbhc_qfuse_cal(component, zdiff, 0);
  763. }
  764. dev_dbg(component->dev, "%s: effective impedance on HPH_diff after calib = %d(mohms)\n",
  765. __func__, *zdiff);
  766. /* Disable HPHR NCLAMP */
  767. regmap_update_bits(wcd939x->regmap, WCD939X_HPHLR_SURGE_MISC1, 0x08, 0x00);
  768. #if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
  769. /* Enable AGND switch */
  770. wcd_usbss_set_switch_settings_enable(AGND_SWITCHES, USBSS_SWITCH_ENABLE);
  771. /* Get ground internal resistance based on orientation */
  772. if (wcd_usbss_get_sbu_switch_orientation() == GND_SBU2_ORIENTATION_A) {
  773. r_gnd_int_fet_mohms = pdata->usbcss_hs.r_gnd_sbu2_int_fet_mohms;
  774. } else if (wcd_usbss_get_sbu_switch_orientation() == GND_SBU1_ORIENTATION_B) {
  775. r_gnd_int_fet_mohms = pdata->usbcss_hs.r_gnd_sbu1_int_fet_mohms;
  776. } else {
  777. *zl = 0;
  778. *zr = 0;
  779. dev_dbg(component->dev, "%s: Invalid SBU switch orientation\n", __func__);
  780. goto zdet_complete;
  781. }
  782. #endif
  783. /* Compute external fet and effective load impedance */
  784. r_gnd_ext_fet_mohms = *zl - *zdiff / 2 + pdata->usbcss_hs.r_surge_mohms / 2 -
  785. pdata->usbcss_hs.r_gnd_par_tot_mohms - r_gnd_int_fet_mohms;
  786. rl_eff_mohms = *zdiff / 2 - pdata->usbcss_hs.r_aud_int_fet_r_mohms -
  787. pdata->usbcss_hs.r_gnd_ext_fet_mohms - pdata->usbcss_hs.r_surge_mohms / 2 -
  788. pdata->usbcss_hs.r_gnd_par_tot_mohms;
  789. /* Store values */
  790. *zl = (rl_eff_mohms - pdata->usbcss_hs.r_conn_par_load_pos_mohms - pdata->usbcss_hs.r3 +
  791. OHMS_TO_MILLIOHMS / 2) / OHMS_TO_MILLIOHMS;
  792. *zr = *zl;
  793. /* Update USBC-SS HS params */
  794. if (rl_eff_mohms > MAX_RL_EFF_MOHMS)
  795. rl_eff_mohms = MAX_RL_EFF_MOHMS;
  796. else if (rl_eff_mohms == 0)
  797. rl_eff_mohms = MIN_RL_EFF_MOHMS;
  798. pdata->usbcss_hs.r_load_eff_l_mohms = rl_eff_mohms;
  799. pdata->usbcss_hs.r_load_eff_r_mohms = rl_eff_mohms;
  800. update_ext_fet_res(pdata, r_gnd_ext_fet_mohms);
  801. update_xtalk_scale_and_alpha(pdata, wcd939x->regmap);
  802. dev_dbg(component->dev, "%s: Xtalk scale is 0x%x and alpha is 0x%x\n",
  803. __func__, pdata->usbcss_hs.scale_l, pdata->usbcss_hs.alpha_l);
  804. mono_stereo_detection:
  805. /* Mono/stereo detection */
  806. if ((*zl == WCD939X_ZDET_FLOATING_IMPEDANCE) && (*zr == WCD939X_ZDET_FLOATING_IMPEDANCE)) {
  807. dev_dbg(component->dev,
  808. "%s: plug type is invalid or extension cable\n",
  809. __func__);
  810. goto zdet_complete;
  811. }
  812. if ((*zl == WCD939X_ZDET_FLOATING_IMPEDANCE) ||
  813. (*zr == WCD939X_ZDET_FLOATING_IMPEDANCE) ||
  814. ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) ||
  815. ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) {
  816. dev_dbg(component->dev,
  817. "%s: Mono plug type with one ch floating or shorted to GND\n",
  818. __func__);
  819. mbhc->hph_type = WCD_MBHC_HPH_MONO;
  820. goto zdet_complete;
  821. }
  822. snd_soc_component_update_bits(component, WCD939X_R_ATEST, 0x02, 0x02);
  823. snd_soc_component_update_bits(component, WCD939X_PA_CTL2, 0x40, 0x01);
  824. wcd939x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1Ls, NULL, d1);
  825. snd_soc_component_update_bits(component, WCD939X_PA_CTL2, 0x40, 0x00);
  826. snd_soc_component_update_bits(component, WCD939X_R_ATEST, 0x02, 0x00);
  827. z1Ls /= 1000;
  828. wcd939x_wcd_mbhc_qfuse_cal(component, &z1Ls, 0);
  829. /* Parallel of left Z and 9 ohm pull down resistor */
  830. zMono = ((*zl) * 9) / ((*zl) + 9);
  831. z_diff1 = (z1Ls > zMono) ? (z1Ls - zMono) : (zMono - z1Ls);
  832. z_diff2 = ((*zl) > z1Ls) ? ((*zl) - z1Ls) : (z1Ls - (*zl));
  833. if ((z_diff1 * (*zl + z1Ls)) > (z_diff2 * (z1Ls + zMono))) {
  834. dev_dbg(component->dev, "%s: stereo plug type detected\n",
  835. __func__);
  836. mbhc->hph_type = WCD_MBHC_HPH_STEREO;
  837. } else {
  838. dev_dbg(component->dev, "%s: MONO plug type detected\n",
  839. __func__);
  840. mbhc->hph_type = WCD_MBHC_HPH_MONO;
  841. }
  842. zdet_complete:
  843. #if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
  844. /* Enable sense switch and MIC for USB-C analog platforms */
  845. if (mbhc->mbhc_cfg->enable_usbc_analog) {
  846. wcd_usbss_set_switch_settings_enable(SENSE_SWITCHES, USBSS_SWITCH_ENABLE);
  847. wcd_usbss_set_switch_settings_enable(MIC_SWITCHES, USBSS_SWITCH_ENABLE);
  848. }
  849. #endif
  850. /* Enable surge protection again after impedance detection */
  851. regmap_update_bits(wcd939x->regmap,
  852. WCD939X_HPHLR_SURGE_EN, 0xC0, 0xC0);
  853. snd_soc_component_write(component, WCD939X_MBHC_BTN5, reg0);
  854. snd_soc_component_write(component, WCD939X_MBHC_BTN6, reg1);
  855. snd_soc_component_write(component, WCD939X_MBHC_BTN7, reg2);
  856. /* Turn on 100k pull down on HPHL */
  857. regmap_update_bits(wcd939x->regmap,
  858. WCD939X_MBHC_MECH, 0x01, 0x01);
  859. /* For NO-jack, re-enable L_DET_EN after Z-det measurements */
  860. if (mbhc->hphl_swh)
  861. regmap_update_bits(wcd939x->regmap,
  862. WCD939X_MBHC_MECH, 0x80, 0x80);
  863. snd_soc_component_write(component, WCD939X_ZDET_ANA_CTL, reg4);
  864. snd_soc_component_write(component, WCD939X_CTL_CLK, reg3);
  865. if (is_fsm_disable)
  866. regmap_update_bits(wcd939x->regmap,
  867. WCD939X_MBHC_ELECT, 0x80, 0x80);
  868. /* Turn off RX supplies */
  869. if (wcd939x->version == WCD939X_VERSION_2_0) {
  870. /* Set VPOS to be controlled by RX */
  871. regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x20, 0x00);
  872. /* Wait 500us for settling */
  873. usleep_range(500, 510);
  874. /* Set PA Left/Right channels and VNEGDAC_LDO to be controlled by RX */
  875. regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x11, 0x00);
  876. /* Wait 100us for settling */
  877. usleep_range(100, 110);
  878. /* Set Vneg mode and enable to be controlled by RX */
  879. regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x06, 0x00);
  880. /* Wait 100us for settling */
  881. usleep_range(100, 110);
  882. /* Set RX bias to be controlled by RX and set Buck/Flyback back to SWR Rx clock */
  883. regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x48, 0x00);
  884. }
  885. }
  886. static void wcd939x_mbhc_gnd_det_ctrl(struct snd_soc_component *component,
  887. bool enable)
  888. {
  889. if (enable) {
  890. snd_soc_component_update_bits(component, WCD939X_MBHC_MECH,
  891. 0x02, 0x02);
  892. snd_soc_component_update_bits(component, WCD939X_MBHC_MECH,
  893. 0x40, 0x40);
  894. } else {
  895. snd_soc_component_update_bits(component, WCD939X_MBHC_MECH,
  896. 0x40, 0x00);
  897. snd_soc_component_update_bits(component, WCD939X_MBHC_MECH,
  898. 0x02, 0x00);
  899. }
  900. }
  901. static void wcd939x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component,
  902. bool enable)
  903. {
  904. if (enable) {
  905. snd_soc_component_update_bits(component, WCD939X_PA_CTL2,
  906. 0x40, 0x40);
  907. snd_soc_component_update_bits(component, WCD939X_PA_CTL2,
  908. 0x10, 0x10);
  909. } else {
  910. snd_soc_component_update_bits(component, WCD939X_PA_CTL2,
  911. 0x40, 0x00);
  912. snd_soc_component_update_bits(component, WCD939X_PA_CTL2,
  913. 0x10, 0x00);
  914. }
  915. }
  916. static void wcd939x_mbhc_moisture_config(struct wcd_mbhc *mbhc)
  917. {
  918. struct snd_soc_component *component = mbhc->component;
  919. if ((mbhc->moist_rref == R_OFF) ||
  920. (mbhc->mbhc_cfg->enable_usbc_analog)) {
  921. snd_soc_component_update_bits(component, WCD939X_CTL_2,
  922. 0x0C, R_OFF << 2);
  923. return;
  924. }
  925. /* Do not enable moisture detection if jack type is NC */
  926. if (!mbhc->hphl_swh) {
  927. dev_dbg(component->dev, "%s: disable moisture detection for NC\n",
  928. __func__);
  929. snd_soc_component_update_bits(component, WCD939X_CTL_2,
  930. 0x0C, R_OFF << 2);
  931. return;
  932. }
  933. snd_soc_component_update_bits(component, WCD939X_CTL_2,
  934. 0x0C, mbhc->moist_rref << 2);
  935. }
  936. static void wcd939x_mbhc_moisture_detect_en(struct wcd_mbhc *mbhc, bool enable)
  937. {
  938. struct snd_soc_component *component = mbhc->component;
  939. if (enable)
  940. snd_soc_component_update_bits(component, WCD939X_CTL_2,
  941. 0x0C, mbhc->moist_rref << 2);
  942. else
  943. snd_soc_component_update_bits(component, WCD939X_CTL_2,
  944. 0x0C, R_OFF << 2);
  945. }
  946. static bool wcd939x_mbhc_get_moisture_status(struct wcd_mbhc *mbhc)
  947. {
  948. struct snd_soc_component *component = mbhc->component;
  949. bool ret = false;
  950. if ((mbhc->moist_rref == R_OFF) ||
  951. (mbhc->mbhc_cfg->enable_usbc_analog)) {
  952. snd_soc_component_update_bits(component, WCD939X_CTL_2,
  953. 0x0C, R_OFF << 2);
  954. goto done;
  955. }
  956. /* Do not enable moisture detection if jack type is NC */
  957. if (!mbhc->hphl_swh) {
  958. dev_dbg(component->dev, "%s: disable moisture detection for NC\n",
  959. __func__);
  960. snd_soc_component_update_bits(component, WCD939X_CTL_2,
  961. 0x0C, R_OFF << 2);
  962. goto done;
  963. }
  964. /*
  965. * If moisture_en is already enabled, then skip to plug type
  966. * detection.
  967. */
  968. if ((snd_soc_component_read(component, WCD939X_CTL_2) & 0x0C))
  969. goto done;
  970. wcd939x_mbhc_moisture_detect_en(mbhc, true);
  971. /* Read moisture comparator status */
  972. ret = ((snd_soc_component_read(component, WCD939X_FSM_STATUS)
  973. & 0x20) ? 0 : 1);
  974. done:
  975. return ret;
  976. }
  977. static void wcd939x_mbhc_moisture_polling_ctrl(struct wcd_mbhc *mbhc,
  978. bool enable)
  979. {
  980. struct snd_soc_component *component = mbhc->component;
  981. snd_soc_component_update_bits(component,
  982. WCD939X_MOISTURE_DET_POLLING_CTRL,
  983. 0x04, (enable << 2));
  984. }
  985. static void wcd939x_mbhc_bcs_enable(struct wcd_mbhc *mbhc,
  986. bool bcs_enable)
  987. {
  988. if (bcs_enable)
  989. wcd939x_disable_bcs_before_slow_insert(mbhc->component, false);
  990. else
  991. wcd939x_disable_bcs_before_slow_insert(mbhc->component, true);
  992. }
  993. static const struct wcd_mbhc_cb mbhc_cb = {
  994. .request_irq = wcd939x_mbhc_request_irq,
  995. .irq_control = wcd939x_mbhc_irq_control,
  996. .free_irq = wcd939x_mbhc_free_irq,
  997. .clk_setup = wcd939x_mbhc_clk_setup,
  998. .map_btn_code_to_num = wcd939x_mbhc_btn_to_num,
  999. .mbhc_bias = wcd939x_mbhc_mbhc_bias_control,
  1000. .set_btn_thr = wcd939x_mbhc_program_btn_thr,
  1001. .lock_sleep = wcd939x_mbhc_lock_sleep,
  1002. .register_notifier = wcd939x_mbhc_register_notifier,
  1003. .micbias_enable_status = wcd939x_mbhc_micb_en_status,
  1004. .hph_pa_on_status = wcd939x_mbhc_hph_pa_on_status,
  1005. .hph_pull_up_control_v2 = wcd939x_mbhc_hph_l_pull_up_control,
  1006. .mbhc_micbias_control = wcd939x_mbhc_request_micbias,
  1007. .mbhc_micb_ramp_control = wcd939x_mbhc_micb_ramp_control,
  1008. .get_hwdep_fw_cal = wcd939x_get_hwdep_fw_cal,
  1009. .mbhc_micb_ctrl_thr_mic = wcd939x_mbhc_micb_ctrl_threshold_mic,
  1010. .compute_impedance = wcd939x_wcd_mbhc_calc_impedance,
  1011. .mbhc_gnd_det_ctrl = wcd939x_mbhc_gnd_det_ctrl,
  1012. .hph_pull_down_ctrl = wcd939x_mbhc_hph_pull_down_ctrl,
  1013. .mbhc_moisture_config = wcd939x_mbhc_moisture_config,
  1014. .mbhc_get_moisture_status = wcd939x_mbhc_get_moisture_status,
  1015. .mbhc_moisture_polling_ctrl = wcd939x_mbhc_moisture_polling_ctrl,
  1016. .mbhc_moisture_detect_en = wcd939x_mbhc_moisture_detect_en,
  1017. .bcs_enable = wcd939x_mbhc_bcs_enable,
  1018. };
  1019. static int wcd939x_get_hph_type(struct snd_kcontrol *kcontrol,
  1020. struct snd_ctl_elem_value *ucontrol)
  1021. {
  1022. struct snd_soc_component *component =
  1023. snd_soc_kcontrol_component(kcontrol);
  1024. struct wcd939x_mbhc *wcd939x_mbhc = wcd939x_soc_get_mbhc(component);
  1025. struct wcd_mbhc *mbhc;
  1026. if (!wcd939x_mbhc) {
  1027. dev_err_ratelimited(component->dev, "%s: mbhc not initialized!\n", __func__);
  1028. return -EINVAL;
  1029. }
  1030. mbhc = &wcd939x_mbhc->wcd_mbhc;
  1031. ucontrol->value.integer.value[0] = (u32) mbhc->hph_type;
  1032. dev_dbg(component->dev, "%s: hph_type = %u\n", __func__, mbhc->hph_type);
  1033. return 0;
  1034. }
  1035. static int wcd939x_hph_impedance_get(struct snd_kcontrol *kcontrol,
  1036. struct snd_ctl_elem_value *ucontrol)
  1037. {
  1038. uint32_t zl, zr;
  1039. bool hphr;
  1040. struct soc_multi_mixer_control *mc;
  1041. struct snd_soc_component *component =
  1042. snd_soc_kcontrol_component(kcontrol);
  1043. struct wcd939x_mbhc *wcd939x_mbhc = wcd939x_soc_get_mbhc(component);
  1044. if (!wcd939x_mbhc) {
  1045. dev_err_ratelimited(component->dev, "%s: mbhc not initialized!\n", __func__);
  1046. return -EINVAL;
  1047. }
  1048. mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
  1049. hphr = mc->shift;
  1050. wcd_mbhc_get_impedance(&wcd939x_mbhc->wcd_mbhc, &zl, &zr);
  1051. dev_dbg(component->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n", __func__, zl, zr);
  1052. ucontrol->value.integer.value[0] = hphr ? zr : zl;
  1053. return 0;
  1054. }
  1055. static const struct snd_kcontrol_new hph_type_detect_controls[] = {
  1056. SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
  1057. wcd939x_get_hph_type, NULL),
  1058. };
  1059. static const struct snd_kcontrol_new impedance_detect_controls[] = {
  1060. SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
  1061. wcd939x_hph_impedance_get, NULL),
  1062. SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
  1063. wcd939x_hph_impedance_get, NULL),
  1064. };
  1065. /*
  1066. * wcd939x_mbhc_get_impedance: get impedance of headphone
  1067. * left and right channels
  1068. * @wcd939x_mbhc: handle to struct wcd939x_mbhc *
  1069. * @zl: handle to left-ch impedance
  1070. * @zr: handle to right-ch impedance
  1071. * return 0 for success or error code in case of failure
  1072. */
  1073. int wcd939x_mbhc_get_impedance(struct wcd939x_mbhc *wcd939x_mbhc,
  1074. uint32_t *zl, uint32_t *zr)
  1075. {
  1076. if (!wcd939x_mbhc) {
  1077. pr_err_ratelimited("%s: mbhc not initialized!\n", __func__);
  1078. return -EINVAL;
  1079. }
  1080. if (!zl || !zr) {
  1081. pr_err_ratelimited("%s: zl or zr null!\n", __func__);
  1082. return -EINVAL;
  1083. }
  1084. return wcd_mbhc_get_impedance(&wcd939x_mbhc->wcd_mbhc, zl, zr);
  1085. }
  1086. EXPORT_SYMBOL(wcd939x_mbhc_get_impedance);
  1087. /*
  1088. * wcd939x_mbhc_hs_detect: starts mbhc insertion/removal functionality
  1089. * @codec: handle to snd_soc_component *
  1090. * @mbhc_cfg: handle to mbhc configuration structure
  1091. * return 0 if mbhc_start is success or error code in case of failure
  1092. */
  1093. int wcd939x_mbhc_hs_detect(struct snd_soc_component *component,
  1094. struct wcd_mbhc_config *mbhc_cfg)
  1095. {
  1096. struct wcd939x_priv *wcd939x = NULL;
  1097. struct wcd939x_mbhc *wcd939x_mbhc = NULL;
  1098. if (!component) {
  1099. pr_err_ratelimited("%s: component is NULL\n", __func__);
  1100. return -EINVAL;
  1101. }
  1102. wcd939x = snd_soc_component_get_drvdata(component);
  1103. if (!wcd939x) {
  1104. pr_err_ratelimited("%s: wcd939x is NULL\n", __func__);
  1105. return -EINVAL;
  1106. }
  1107. wcd939x_mbhc = wcd939x->mbhc;
  1108. if (!wcd939x_mbhc) {
  1109. dev_err_ratelimited(component->dev, "%s: mbhc not initialized!\n", __func__);
  1110. return -EINVAL;
  1111. }
  1112. return wcd_mbhc_start(&wcd939x_mbhc->wcd_mbhc, mbhc_cfg);
  1113. }
  1114. EXPORT_SYMBOL(wcd939x_mbhc_hs_detect);
  1115. /*
  1116. * wcd939x_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality
  1117. * @component: handle to snd_soc_component *
  1118. */
  1119. void wcd939x_mbhc_hs_detect_exit(struct snd_soc_component *component)
  1120. {
  1121. struct wcd939x_priv *wcd939x = NULL;
  1122. struct wcd939x_mbhc *wcd939x_mbhc = NULL;
  1123. if (!component) {
  1124. pr_err_ratelimited("%s: component is NULL\n", __func__);
  1125. return;
  1126. }
  1127. wcd939x = snd_soc_component_get_drvdata(component);
  1128. if (!wcd939x) {
  1129. pr_err_ratelimited("%s: wcd939x is NULL\n", __func__);
  1130. return;
  1131. }
  1132. wcd939x_mbhc = wcd939x->mbhc;
  1133. if (!wcd939x_mbhc) {
  1134. dev_err_ratelimited(component->dev, "%s: mbhc not initialized!\n", __func__);
  1135. return;
  1136. }
  1137. wcd_mbhc_stop(&wcd939x_mbhc->wcd_mbhc);
  1138. }
  1139. EXPORT_SYMBOL(wcd939x_mbhc_hs_detect_exit);
  1140. /*
  1141. * wcd939x_mbhc_ssr_down: stop mbhc during
  1142. * wcd939x subsystem restart
  1143. * mbhc: pointer to wcd937x_mbhc structure
  1144. * component: handle to snd_soc_component *
  1145. */
  1146. void wcd939x_mbhc_ssr_down(struct wcd939x_mbhc *mbhc,
  1147. struct snd_soc_component *component)
  1148. {
  1149. struct wcd_mbhc *wcd_mbhc = NULL;
  1150. if (!mbhc || !component)
  1151. return;
  1152. wcd_mbhc = &mbhc->wcd_mbhc;
  1153. if (!wcd_mbhc) {
  1154. dev_err_ratelimited(component->dev, "%s: wcd_mbhc is NULL\n", __func__);
  1155. return;
  1156. }
  1157. wcd939x_mbhc_hs_detect_exit(component);
  1158. wcd_mbhc_deinit(wcd_mbhc);
  1159. }
  1160. EXPORT_SYMBOL(wcd939x_mbhc_ssr_down);
  1161. /*
  1162. * wcd939x_mbhc_post_ssr_init: initialize mbhc for
  1163. * wcd939x post subsystem restart
  1164. * @mbhc: poniter to wcd939x_mbhc structure
  1165. * @component: handle to snd_soc_component *
  1166. *
  1167. * return 0 if mbhc_init is success or error code in case of failure
  1168. */
  1169. int wcd939x_mbhc_post_ssr_init(struct wcd939x_mbhc *mbhc,
  1170. struct snd_soc_component *component)
  1171. {
  1172. int ret = 0;
  1173. struct wcd_mbhc *wcd_mbhc = NULL;
  1174. if (!mbhc || !component)
  1175. return -EINVAL;
  1176. wcd_mbhc = &mbhc->wcd_mbhc;
  1177. if (wcd_mbhc == NULL) {
  1178. pr_err("%s: wcd_mbhc is NULL\n", __func__);
  1179. return -EINVAL;
  1180. }
  1181. /* Reset detection type to insertion after SSR recovery */
  1182. snd_soc_component_update_bits(component, WCD939X_MBHC_MECH,
  1183. 0x20, 0x20);
  1184. ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, &intr_ids,
  1185. wcd_mbhc_registers, WCD939X_ZDET_SUPPORTED);
  1186. if (ret) {
  1187. dev_err(component->dev, "%s: mbhc initialization failed\n",
  1188. __func__);
  1189. goto done;
  1190. }
  1191. done:
  1192. return ret;
  1193. }
  1194. EXPORT_SYMBOL(wcd939x_mbhc_post_ssr_init);
  1195. /*
  1196. * wcd939x_mbhc_init: initialize mbhc for wcd939x
  1197. * @mbhc: poniter to wcd939x_mbhc struct pointer to store the configs
  1198. * @codec: handle to snd_soc_component *
  1199. * @fw_data: handle to firmware data
  1200. *
  1201. * return 0 if mbhc_init is success or error code in case of failure
  1202. */
  1203. int wcd939x_mbhc_init(struct wcd939x_mbhc **mbhc,
  1204. struct snd_soc_component *component,
  1205. struct fw_info *fw_data)
  1206. {
  1207. struct wcd939x_mbhc *wcd939x_mbhc = NULL;
  1208. struct wcd_mbhc *wcd_mbhc = NULL;
  1209. int ret = 0;
  1210. struct wcd939x_pdata *pdata;
  1211. if (!component) {
  1212. pr_err("%s: component is NULL\n", __func__);
  1213. return -EINVAL;
  1214. }
  1215. wcd939x_mbhc = devm_kzalloc(component->dev, sizeof(struct wcd939x_mbhc),
  1216. GFP_KERNEL);
  1217. if (!wcd939x_mbhc)
  1218. return -ENOMEM;
  1219. wcd939x_mbhc->fw_data = fw_data;
  1220. BLOCKING_INIT_NOTIFIER_HEAD(&wcd939x_mbhc->notifier);
  1221. wcd_mbhc = &wcd939x_mbhc->wcd_mbhc;
  1222. if (wcd_mbhc == NULL) {
  1223. pr_err("%s: wcd_mbhc is NULL\n", __func__);
  1224. ret = -EINVAL;
  1225. goto err;
  1226. }
  1227. /* Setting default mbhc detection logic to ADC */
  1228. wcd_mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
  1229. pdata = dev_get_platdata(component->dev);
  1230. if (!pdata) {
  1231. dev_err(component->dev, "%s: pdata pointer is NULL\n",
  1232. __func__);
  1233. ret = -EINVAL;
  1234. goto err;
  1235. }
  1236. wcd_mbhc->micb_mv = pdata->micbias.micb2_mv;
  1237. ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb,
  1238. &intr_ids, wcd_mbhc_registers,
  1239. WCD939X_ZDET_SUPPORTED);
  1240. if (ret) {
  1241. dev_err(component->dev, "%s: mbhc initialization failed\n",
  1242. __func__);
  1243. goto err;
  1244. }
  1245. (*mbhc) = wcd939x_mbhc;
  1246. snd_soc_add_component_controls(component, impedance_detect_controls,
  1247. ARRAY_SIZE(impedance_detect_controls));
  1248. snd_soc_add_component_controls(component, hph_type_detect_controls,
  1249. ARRAY_SIZE(hph_type_detect_controls));
  1250. return 0;
  1251. err:
  1252. devm_kfree(component->dev, wcd939x_mbhc);
  1253. return ret;
  1254. }
  1255. EXPORT_SYMBOL(wcd939x_mbhc_init);
  1256. /*
  1257. * wcd939x_mbhc_deinit: deinitialize mbhc for wcd939x
  1258. * @codec: handle to snd_soc_component *
  1259. */
  1260. void wcd939x_mbhc_deinit(struct snd_soc_component *component)
  1261. {
  1262. struct wcd939x_priv *wcd939x;
  1263. struct wcd939x_mbhc *wcd939x_mbhc;
  1264. if (!component) {
  1265. pr_err("%s: component is NULL\n", __func__);
  1266. return;
  1267. }
  1268. wcd939x = snd_soc_component_get_drvdata(component);
  1269. if (!wcd939x) {
  1270. pr_err("%s: wcd939x is NULL\n", __func__);
  1271. return;
  1272. }
  1273. wcd939x_mbhc = wcd939x->mbhc;
  1274. if (wcd939x_mbhc) {
  1275. wcd_mbhc_deinit(&wcd939x_mbhc->wcd_mbhc);
  1276. devm_kfree(component->dev, wcd939x_mbhc);
  1277. }
  1278. }
  1279. EXPORT_SYMBOL(wcd939x_mbhc_deinit);