da7219-aad.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * da7219-aad.c - Dialog DA7219 ALSA SoC AAD Driver
  4. *
  5. * Copyright (c) 2015 Dialog Semiconductor Ltd.
  6. *
  7. * Author: Adam Thomson <[email protected]>
  8. */
  9. #include <linux/module.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/clk.h>
  12. #include <linux/i2c.h>
  13. #include <linux/property.h>
  14. #include <linux/pm_wakeirq.h>
  15. #include <linux/slab.h>
  16. #include <linux/delay.h>
  17. #include <linux/workqueue.h>
  18. #include <sound/soc.h>
  19. #include <sound/jack.h>
  20. #include <sound/da7219.h>
  21. #include "da7219.h"
  22. #include "da7219-aad.h"
  23. /*
  24. * Detection control
  25. */
  26. void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jack *jack)
  27. {
  28. struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
  29. da7219->aad->jack = jack;
  30. da7219->aad->jack_inserted = false;
  31. /* Send an initial empty report */
  32. snd_soc_jack_report(jack, 0, DA7219_AAD_REPORT_ALL_MASK);
  33. /* Enable/Disable jack detection */
  34. snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
  35. DA7219_ACCDET_EN_MASK,
  36. (jack ? DA7219_ACCDET_EN_MASK : 0));
  37. }
  38. EXPORT_SYMBOL_GPL(da7219_aad_jack_det);
  39. /*
  40. * Button/HPTest work
  41. */
  42. static void da7219_aad_btn_det_work(struct work_struct *work)
  43. {
  44. struct da7219_aad_priv *da7219_aad =
  45. container_of(work, struct da7219_aad_priv, btn_det_work);
  46. struct snd_soc_component *component = da7219_aad->component;
  47. struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
  48. struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
  49. u8 statusa, micbias_ctrl;
  50. bool micbias_up = false;
  51. int retries = 0;
  52. /* Disable ground switch */
  53. snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
  54. /* Drive headphones/lineout */
  55. snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
  56. DA7219_HP_L_AMP_OE_MASK,
  57. DA7219_HP_L_AMP_OE_MASK);
  58. snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
  59. DA7219_HP_R_AMP_OE_MASK,
  60. DA7219_HP_R_AMP_OE_MASK);
  61. /* Make sure mic bias is up */
  62. snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
  63. snd_soc_dapm_sync(dapm);
  64. do {
  65. statusa = snd_soc_component_read(component, DA7219_ACCDET_STATUS_A);
  66. if (statusa & DA7219_MICBIAS_UP_STS_MASK)
  67. micbias_up = true;
  68. else if (retries++ < DA7219_AAD_MICBIAS_CHK_RETRIES)
  69. msleep(DA7219_AAD_MICBIAS_CHK_DELAY);
  70. } while ((!micbias_up) && (retries < DA7219_AAD_MICBIAS_CHK_RETRIES));
  71. if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES)
  72. dev_warn(component->dev, "Mic bias status check timed out");
  73. da7219->micbias_on_event = true;
  74. /*
  75. * Mic bias pulse required to enable mic, must be done before enabling
  76. * button detection to prevent erroneous button readings.
  77. */
  78. if (da7219_aad->micbias_pulse_lvl && da7219_aad->micbias_pulse_time) {
  79. /* Pulse higher level voltage */
  80. micbias_ctrl = snd_soc_component_read(component, DA7219_MICBIAS_CTRL);
  81. snd_soc_component_update_bits(component, DA7219_MICBIAS_CTRL,
  82. DA7219_MICBIAS1_LEVEL_MASK,
  83. da7219_aad->micbias_pulse_lvl);
  84. msleep(da7219_aad->micbias_pulse_time);
  85. snd_soc_component_write(component, DA7219_MICBIAS_CTRL, micbias_ctrl);
  86. }
  87. snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
  88. DA7219_BUTTON_CONFIG_MASK,
  89. da7219_aad->btn_cfg);
  90. }
  91. static void da7219_aad_hptest_work(struct work_struct *work)
  92. {
  93. struct da7219_aad_priv *da7219_aad =
  94. container_of(work, struct da7219_aad_priv, hptest_work);
  95. struct snd_soc_component *component = da7219_aad->component;
  96. struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
  97. struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
  98. __le16 tonegen_freq_hptest;
  99. u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8;
  100. int report = 0, ret;
  101. /* Lock DAPM, Kcontrols affected by this test and the PLL */
  102. snd_soc_dapm_mutex_lock(dapm);
  103. mutex_lock(&da7219->ctrl_lock);
  104. mutex_lock(&da7219->pll_lock);
  105. /* Ensure MCLK is available for HP test procedure */
  106. if (da7219->mclk) {
  107. ret = clk_prepare_enable(da7219->mclk);
  108. if (ret) {
  109. dev_err(component->dev, "Failed to enable mclk - %d\n", ret);
  110. mutex_unlock(&da7219->pll_lock);
  111. mutex_unlock(&da7219->ctrl_lock);
  112. snd_soc_dapm_mutex_unlock(dapm);
  113. return;
  114. }
  115. }
  116. /*
  117. * If MCLK not present, then we're using the internal oscillator and
  118. * require different frequency settings to achieve the same result.
  119. *
  120. * If MCLK is present, but PLL is not enabled then we enable it here to
  121. * ensure a consistent detection procedure.
  122. */
  123. pll_srm_sts = snd_soc_component_read(component, DA7219_PLL_SRM_STS);
  124. if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) {
  125. tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
  126. pll_ctrl = snd_soc_component_read(component, DA7219_PLL_CTRL);
  127. if ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS)
  128. da7219_set_pll(component, DA7219_SYSCLK_PLL,
  129. DA7219_PLL_FREQ_OUT_98304);
  130. } else {
  131. tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);
  132. }
  133. /* Disable ground switch */
  134. snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
  135. /* Ensure gain ramping at fastest rate */
  136. gain_ramp_ctrl = snd_soc_component_read(component, DA7219_GAIN_RAMP_CTRL);
  137. snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);
  138. /* Bypass cache so it saves current settings */
  139. regcache_cache_bypass(da7219->regmap, true);
  140. /* Make sure Tone Generator is disabled */
  141. snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0);
  142. /* Enable HPTest block, 1KOhms check */
  143. snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8,
  144. DA7219_HPTEST_EN_MASK | DA7219_HPTEST_RES_SEL_MASK,
  145. DA7219_HPTEST_EN_MASK |
  146. DA7219_HPTEST_RES_SEL_1KOHMS);
  147. /* Set gains to 0db */
  148. snd_soc_component_write(component, DA7219_DAC_L_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
  149. snd_soc_component_write(component, DA7219_DAC_R_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
  150. snd_soc_component_write(component, DA7219_HP_L_GAIN, DA7219_HP_AMP_GAIN_0DB);
  151. snd_soc_component_write(component, DA7219_HP_R_GAIN, DA7219_HP_AMP_GAIN_0DB);
  152. /* Disable DAC filters, EQs and soft mute */
  153. snd_soc_component_update_bits(component, DA7219_DAC_FILTERS1, DA7219_HPF_MODE_MASK,
  154. 0);
  155. snd_soc_component_update_bits(component, DA7219_DAC_FILTERS4, DA7219_DAC_EQ_EN_MASK,
  156. 0);
  157. snd_soc_component_update_bits(component, DA7219_DAC_FILTERS5,
  158. DA7219_DAC_SOFTMUTE_EN_MASK, 0);
  159. /* Enable HP left & right paths */
  160. snd_soc_component_update_bits(component, DA7219_CP_CTRL, DA7219_CP_EN_MASK,
  161. DA7219_CP_EN_MASK);
  162. snd_soc_component_update_bits(component, DA7219_DIG_ROUTING_DAC,
  163. DA7219_DAC_L_SRC_MASK | DA7219_DAC_R_SRC_MASK,
  164. DA7219_DAC_L_SRC_TONEGEN |
  165. DA7219_DAC_R_SRC_TONEGEN);
  166. snd_soc_component_update_bits(component, DA7219_DAC_L_CTRL,
  167. DA7219_DAC_L_EN_MASK | DA7219_DAC_L_MUTE_EN_MASK,
  168. DA7219_DAC_L_EN_MASK);
  169. snd_soc_component_update_bits(component, DA7219_DAC_R_CTRL,
  170. DA7219_DAC_R_EN_MASK | DA7219_DAC_R_MUTE_EN_MASK,
  171. DA7219_DAC_R_EN_MASK);
  172. snd_soc_component_update_bits(component, DA7219_MIXOUT_L_SELECT,
  173. DA7219_MIXOUT_L_MIX_SELECT_MASK,
  174. DA7219_MIXOUT_L_MIX_SELECT_MASK);
  175. snd_soc_component_update_bits(component, DA7219_MIXOUT_R_SELECT,
  176. DA7219_MIXOUT_R_MIX_SELECT_MASK,
  177. DA7219_MIXOUT_R_MIX_SELECT_MASK);
  178. snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1L,
  179. DA7219_OUTFILT_ST_1L_SRC_MASK,
  180. DA7219_DMIX_ST_SRC_OUTFILT1L);
  181. snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1R,
  182. DA7219_OUTFILT_ST_1R_SRC_MASK,
  183. DA7219_DMIX_ST_SRC_OUTFILT1R);
  184. snd_soc_component_update_bits(component, DA7219_MIXOUT_L_CTRL,
  185. DA7219_MIXOUT_L_AMP_EN_MASK,
  186. DA7219_MIXOUT_L_AMP_EN_MASK);
  187. snd_soc_component_update_bits(component, DA7219_MIXOUT_R_CTRL,
  188. DA7219_MIXOUT_R_AMP_EN_MASK,
  189. DA7219_MIXOUT_R_AMP_EN_MASK);
  190. snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
  191. DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK,
  192. DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);
  193. snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
  194. DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK,
  195. DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
  196. msleep(DA7219_SETTLING_DELAY);
  197. snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
  198. DA7219_HP_L_AMP_MUTE_EN_MASK |
  199. DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0);
  200. snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
  201. DA7219_HP_R_AMP_MUTE_EN_MASK |
  202. DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0);
  203. /*
  204. * If we're running from the internal oscillator then give audio paths
  205. * time to settle before running test.
  206. */
  207. if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
  208. msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
  209. /* Configure & start Tone Generator */
  210. snd_soc_component_write(component, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK);
  211. regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
  212. &tonegen_freq_hptest, sizeof(tonegen_freq_hptest));
  213. snd_soc_component_update_bits(component, DA7219_TONE_GEN_CFG2,
  214. DA7219_SWG_SEL_MASK | DA7219_TONE_GEN_GAIN_MASK,
  215. DA7219_SWG_SEL_SRAMP |
  216. DA7219_TONE_GEN_GAIN_MINUS_15DB);
  217. snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, DA7219_START_STOPN_MASK);
  218. msleep(DA7219_AAD_HPTEST_PERIOD);
  219. /* Grab comparator reading */
  220. accdet_cfg8 = snd_soc_component_read(component, DA7219_ACCDET_CONFIG_8);
  221. if (accdet_cfg8 & DA7219_HPTEST_COMP_MASK)
  222. report |= SND_JACK_HEADPHONE;
  223. else
  224. report |= SND_JACK_LINEOUT;
  225. /* Stop tone generator */
  226. snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0);
  227. msleep(DA7219_AAD_HPTEST_PERIOD);
  228. /* Restore original settings from cache */
  229. regcache_mark_dirty(da7219->regmap);
  230. regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL,
  231. DA7219_HP_R_CTRL);
  232. msleep(DA7219_SETTLING_DELAY);
  233. regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL,
  234. DA7219_MIXOUT_R_CTRL);
  235. regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L,
  236. DA7219_DROUTING_ST_OUTFILT_1R);
  237. regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_SELECT,
  238. DA7219_MIXOUT_R_SELECT);
  239. regcache_sync_region(da7219->regmap, DA7219_DAC_L_CTRL,
  240. DA7219_DAC_R_CTRL);
  241. regcache_sync_region(da7219->regmap, DA7219_DIG_ROUTING_DAC,
  242. DA7219_DIG_ROUTING_DAC);
  243. regcache_sync_region(da7219->regmap, DA7219_CP_CTRL, DA7219_CP_CTRL);
  244. regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS5,
  245. DA7219_DAC_FILTERS5);
  246. regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS4,
  247. DA7219_DAC_FILTERS1);
  248. regcache_sync_region(da7219->regmap, DA7219_HP_L_GAIN,
  249. DA7219_HP_R_GAIN);
  250. regcache_sync_region(da7219->regmap, DA7219_DAC_L_GAIN,
  251. DA7219_DAC_R_GAIN);
  252. regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_ON_PER,
  253. DA7219_TONE_GEN_ON_PER);
  254. regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
  255. DA7219_TONE_GEN_FREQ1_U);
  256. regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_CFG1,
  257. DA7219_TONE_GEN_CFG2);
  258. regcache_cache_bypass(da7219->regmap, false);
  259. /* Disable HPTest block */
  260. snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8,
  261. DA7219_HPTEST_EN_MASK, 0);
  262. /*
  263. * If we're running from the internal oscillator then give audio paths
  264. * time to settle before allowing headphones to be driven as required.
  265. */
  266. if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
  267. msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
  268. /* Restore gain ramping rate */
  269. snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl);
  270. /* Drive Headphones/lineout */
  271. snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK,
  272. DA7219_HP_L_AMP_OE_MASK);
  273. snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,
  274. DA7219_HP_R_AMP_OE_MASK);
  275. /* Restore PLL to previous configuration, if re-configured */
  276. if ((pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) &&
  277. ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS))
  278. da7219_set_pll(component, DA7219_SYSCLK_MCLK, 0);
  279. /* Remove MCLK, if previously enabled */
  280. if (da7219->mclk)
  281. clk_disable_unprepare(da7219->mclk);
  282. mutex_unlock(&da7219->pll_lock);
  283. mutex_unlock(&da7219->ctrl_lock);
  284. snd_soc_dapm_mutex_unlock(dapm);
  285. /*
  286. * Only send report if jack hasn't been removed during process,
  287. * otherwise it's invalid and we drop it.
  288. */
  289. if (da7219_aad->jack_inserted)
  290. snd_soc_jack_report(da7219_aad->jack, report,
  291. SND_JACK_HEADSET | SND_JACK_LINEOUT);
  292. }
  293. /*
  294. * IRQ
  295. */
  296. static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
  297. {
  298. struct da7219_aad_priv *da7219_aad = data;
  299. struct snd_soc_component *component = da7219_aad->component;
  300. struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
  301. struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
  302. u8 events[DA7219_AAD_IRQ_REG_MAX];
  303. u8 statusa;
  304. int i, ret, report = 0, mask = 0;
  305. /* Read current IRQ events */
  306. ret = regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
  307. events, DA7219_AAD_IRQ_REG_MAX);
  308. if (ret) {
  309. dev_warn_ratelimited(component->dev, "Failed to read IRQ events: %d\n", ret);
  310. return IRQ_NONE;
  311. }
  312. if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B])
  313. return IRQ_NONE;
  314. /* Read status register for jack insertion & type status */
  315. statusa = snd_soc_component_read(component, DA7219_ACCDET_STATUS_A);
  316. /* Clear events */
  317. regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
  318. events, DA7219_AAD_IRQ_REG_MAX);
  319. dev_dbg(component->dev, "IRQ events = 0x%x|0x%x, status = 0x%x\n",
  320. events[DA7219_AAD_IRQ_REG_A], events[DA7219_AAD_IRQ_REG_B],
  321. statusa);
  322. if (statusa & DA7219_JACK_INSERTION_STS_MASK) {
  323. /* Jack Insertion */
  324. if (events[DA7219_AAD_IRQ_REG_A] &
  325. DA7219_E_JACK_INSERTED_MASK) {
  326. report |= SND_JACK_MECHANICAL;
  327. mask |= SND_JACK_MECHANICAL;
  328. da7219_aad->jack_inserted = true;
  329. }
  330. /* Jack type detection */
  331. if (events[DA7219_AAD_IRQ_REG_A] &
  332. DA7219_E_JACK_DETECT_COMPLETE_MASK) {
  333. /*
  334. * If 4-pole, then enable button detection, else perform
  335. * HP impedance test to determine output type to report.
  336. *
  337. * We schedule work here as the tasks themselves can
  338. * take time to complete, and in particular for hptest
  339. * we want to be able to check if the jack was removed
  340. * during the procedure as this will invalidate the
  341. * result. By doing this as work, the IRQ thread can
  342. * handle a removal, and we can check at the end of
  343. * hptest if we have a valid result or not.
  344. */
  345. if (statusa & DA7219_JACK_TYPE_STS_MASK) {
  346. report |= SND_JACK_HEADSET;
  347. mask |= SND_JACK_HEADSET | SND_JACK_LINEOUT;
  348. schedule_work(&da7219_aad->btn_det_work);
  349. } else {
  350. schedule_work(&da7219_aad->hptest_work);
  351. }
  352. }
  353. /* Button support for 4-pole jack */
  354. if (statusa & DA7219_JACK_TYPE_STS_MASK) {
  355. for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
  356. /* Button Press */
  357. if (events[DA7219_AAD_IRQ_REG_B] &
  358. (DA7219_E_BUTTON_A_PRESSED_MASK << i)) {
  359. report |= SND_JACK_BTN_0 >> i;
  360. mask |= SND_JACK_BTN_0 >> i;
  361. }
  362. }
  363. snd_soc_jack_report(da7219_aad->jack, report, mask);
  364. for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
  365. /* Button Release */
  366. if (events[DA7219_AAD_IRQ_REG_B] &
  367. (DA7219_E_BUTTON_A_RELEASED_MASK >> i)) {
  368. report &= ~(SND_JACK_BTN_0 >> i);
  369. mask |= SND_JACK_BTN_0 >> i;
  370. }
  371. }
  372. }
  373. } else {
  374. /* Jack removal */
  375. if (events[DA7219_AAD_IRQ_REG_A] & DA7219_E_JACK_REMOVED_MASK) {
  376. report = 0;
  377. mask |= DA7219_AAD_REPORT_ALL_MASK;
  378. da7219_aad->jack_inserted = false;
  379. /* Cancel any pending work */
  380. cancel_work_sync(&da7219_aad->btn_det_work);
  381. cancel_work_sync(&da7219_aad->hptest_work);
  382. /* Un-drive headphones/lineout */
  383. snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
  384. DA7219_HP_R_AMP_OE_MASK, 0);
  385. snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
  386. DA7219_HP_L_AMP_OE_MASK, 0);
  387. /* Ensure button detection disabled */
  388. snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
  389. DA7219_BUTTON_CONFIG_MASK, 0);
  390. da7219->micbias_on_event = false;
  391. /* Disable mic bias */
  392. snd_soc_dapm_disable_pin(dapm, "Mic Bias");
  393. snd_soc_dapm_sync(dapm);
  394. /* Enable ground switch */
  395. snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01);
  396. }
  397. }
  398. snd_soc_jack_report(da7219_aad->jack, report, mask);
  399. return IRQ_HANDLED;
  400. }
  401. /*
  402. * DT/ACPI to pdata conversion
  403. */
  404. static enum da7219_aad_micbias_pulse_lvl
  405. da7219_aad_fw_micbias_pulse_lvl(struct device *dev, u32 val)
  406. {
  407. switch (val) {
  408. case 2800:
  409. return DA7219_AAD_MICBIAS_PULSE_LVL_2_8V;
  410. case 2900:
  411. return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V;
  412. default:
  413. dev_warn(dev, "Invalid micbias pulse level");
  414. return DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
  415. }
  416. }
  417. static enum da7219_aad_btn_cfg
  418. da7219_aad_fw_btn_cfg(struct device *dev, u32 val)
  419. {
  420. switch (val) {
  421. case 2:
  422. return DA7219_AAD_BTN_CFG_2MS;
  423. case 5:
  424. return DA7219_AAD_BTN_CFG_5MS;
  425. case 10:
  426. return DA7219_AAD_BTN_CFG_10MS;
  427. case 50:
  428. return DA7219_AAD_BTN_CFG_50MS;
  429. case 100:
  430. return DA7219_AAD_BTN_CFG_100MS;
  431. case 200:
  432. return DA7219_AAD_BTN_CFG_200MS;
  433. case 500:
  434. return DA7219_AAD_BTN_CFG_500MS;
  435. default:
  436. dev_warn(dev, "Invalid button config");
  437. return DA7219_AAD_BTN_CFG_10MS;
  438. }
  439. }
  440. static enum da7219_aad_mic_det_thr
  441. da7219_aad_fw_mic_det_thr(struct device *dev, u32 val)
  442. {
  443. switch (val) {
  444. case 200:
  445. return DA7219_AAD_MIC_DET_THR_200_OHMS;
  446. case 500:
  447. return DA7219_AAD_MIC_DET_THR_500_OHMS;
  448. case 750:
  449. return DA7219_AAD_MIC_DET_THR_750_OHMS;
  450. case 1000:
  451. return DA7219_AAD_MIC_DET_THR_1000_OHMS;
  452. default:
  453. dev_warn(dev, "Invalid mic detect threshold");
  454. return DA7219_AAD_MIC_DET_THR_500_OHMS;
  455. }
  456. }
  457. static enum da7219_aad_jack_ins_deb
  458. da7219_aad_fw_jack_ins_deb(struct device *dev, u32 val)
  459. {
  460. switch (val) {
  461. case 5:
  462. return DA7219_AAD_JACK_INS_DEB_5MS;
  463. case 10:
  464. return DA7219_AAD_JACK_INS_DEB_10MS;
  465. case 20:
  466. return DA7219_AAD_JACK_INS_DEB_20MS;
  467. case 50:
  468. return DA7219_AAD_JACK_INS_DEB_50MS;
  469. case 100:
  470. return DA7219_AAD_JACK_INS_DEB_100MS;
  471. case 200:
  472. return DA7219_AAD_JACK_INS_DEB_200MS;
  473. case 500:
  474. return DA7219_AAD_JACK_INS_DEB_500MS;
  475. case 1000:
  476. return DA7219_AAD_JACK_INS_DEB_1S;
  477. default:
  478. dev_warn(dev, "Invalid jack insert debounce");
  479. return DA7219_AAD_JACK_INS_DEB_20MS;
  480. }
  481. }
  482. static enum da7219_aad_jack_det_rate
  483. da7219_aad_fw_jack_det_rate(struct device *dev, const char *str)
  484. {
  485. if (!strcmp(str, "32ms_64ms")) {
  486. return DA7219_AAD_JACK_DET_RATE_32_64MS;
  487. } else if (!strcmp(str, "64ms_128ms")) {
  488. return DA7219_AAD_JACK_DET_RATE_64_128MS;
  489. } else if (!strcmp(str, "128ms_256ms")) {
  490. return DA7219_AAD_JACK_DET_RATE_128_256MS;
  491. } else if (!strcmp(str, "256ms_512ms")) {
  492. return DA7219_AAD_JACK_DET_RATE_256_512MS;
  493. } else {
  494. dev_warn(dev, "Invalid jack detect rate");
  495. return DA7219_AAD_JACK_DET_RATE_256_512MS;
  496. }
  497. }
  498. static enum da7219_aad_jack_rem_deb
  499. da7219_aad_fw_jack_rem_deb(struct device *dev, u32 val)
  500. {
  501. switch (val) {
  502. case 1:
  503. return DA7219_AAD_JACK_REM_DEB_1MS;
  504. case 5:
  505. return DA7219_AAD_JACK_REM_DEB_5MS;
  506. case 10:
  507. return DA7219_AAD_JACK_REM_DEB_10MS;
  508. case 20:
  509. return DA7219_AAD_JACK_REM_DEB_20MS;
  510. default:
  511. dev_warn(dev, "Invalid jack removal debounce");
  512. return DA7219_AAD_JACK_REM_DEB_1MS;
  513. }
  514. }
  515. static enum da7219_aad_btn_avg
  516. da7219_aad_fw_btn_avg(struct device *dev, u32 val)
  517. {
  518. switch (val) {
  519. case 1:
  520. return DA7219_AAD_BTN_AVG_1;
  521. case 2:
  522. return DA7219_AAD_BTN_AVG_2;
  523. case 4:
  524. return DA7219_AAD_BTN_AVG_4;
  525. case 8:
  526. return DA7219_AAD_BTN_AVG_8;
  527. default:
  528. dev_warn(dev, "Invalid button average value");
  529. return DA7219_AAD_BTN_AVG_2;
  530. }
  531. }
  532. static enum da7219_aad_adc_1bit_rpt
  533. da7219_aad_fw_adc_1bit_rpt(struct device *dev, u32 val)
  534. {
  535. switch (val) {
  536. case 1:
  537. return DA7219_AAD_ADC_1BIT_RPT_1;
  538. case 2:
  539. return DA7219_AAD_ADC_1BIT_RPT_2;
  540. case 4:
  541. return DA7219_AAD_ADC_1BIT_RPT_4;
  542. case 8:
  543. return DA7219_AAD_ADC_1BIT_RPT_8;
  544. default:
  545. dev_warn(dev, "Invalid ADC 1-bit repeat value");
  546. return DA7219_AAD_ADC_1BIT_RPT_1;
  547. }
  548. }
  549. static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev)
  550. {
  551. struct i2c_client *i2c = to_i2c_client(dev);
  552. struct fwnode_handle *aad_np;
  553. struct da7219_aad_pdata *aad_pdata;
  554. const char *fw_str;
  555. u32 fw_val32;
  556. aad_np = device_get_named_child_node(dev, "da7219_aad");
  557. if (!aad_np)
  558. return NULL;
  559. aad_pdata = devm_kzalloc(dev, sizeof(*aad_pdata), GFP_KERNEL);
  560. if (!aad_pdata)
  561. return NULL;
  562. aad_pdata->irq = i2c->irq;
  563. if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-lvl",
  564. &fw_val32) >= 0)
  565. aad_pdata->micbias_pulse_lvl =
  566. da7219_aad_fw_micbias_pulse_lvl(dev, fw_val32);
  567. else
  568. aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
  569. if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-time",
  570. &fw_val32) >= 0)
  571. aad_pdata->micbias_pulse_time = fw_val32;
  572. if (fwnode_property_read_u32(aad_np, "dlg,btn-cfg", &fw_val32) >= 0)
  573. aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(dev, fw_val32);
  574. else
  575. aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS;
  576. if (fwnode_property_read_u32(aad_np, "dlg,mic-det-thr", &fw_val32) >= 0)
  577. aad_pdata->mic_det_thr =
  578. da7219_aad_fw_mic_det_thr(dev, fw_val32);
  579. else
  580. aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS;
  581. if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0)
  582. aad_pdata->jack_ins_deb =
  583. da7219_aad_fw_jack_ins_deb(dev, fw_val32);
  584. else
  585. aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS;
  586. if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str))
  587. aad_pdata->jack_det_rate =
  588. da7219_aad_fw_jack_det_rate(dev, fw_str);
  589. else
  590. aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS;
  591. if (fwnode_property_read_u32(aad_np, "dlg,jack-rem-deb", &fw_val32) >= 0)
  592. aad_pdata->jack_rem_deb =
  593. da7219_aad_fw_jack_rem_deb(dev, fw_val32);
  594. else
  595. aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS;
  596. if (fwnode_property_read_u32(aad_np, "dlg,a-d-btn-thr", &fw_val32) >= 0)
  597. aad_pdata->a_d_btn_thr = (u8) fw_val32;
  598. else
  599. aad_pdata->a_d_btn_thr = 0xA;
  600. if (fwnode_property_read_u32(aad_np, "dlg,d-b-btn-thr", &fw_val32) >= 0)
  601. aad_pdata->d_b_btn_thr = (u8) fw_val32;
  602. else
  603. aad_pdata->d_b_btn_thr = 0x16;
  604. if (fwnode_property_read_u32(aad_np, "dlg,b-c-btn-thr", &fw_val32) >= 0)
  605. aad_pdata->b_c_btn_thr = (u8) fw_val32;
  606. else
  607. aad_pdata->b_c_btn_thr = 0x21;
  608. if (fwnode_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &fw_val32) >= 0)
  609. aad_pdata->c_mic_btn_thr = (u8) fw_val32;
  610. else
  611. aad_pdata->c_mic_btn_thr = 0x3E;
  612. if (fwnode_property_read_u32(aad_np, "dlg,btn-avg", &fw_val32) >= 0)
  613. aad_pdata->btn_avg = da7219_aad_fw_btn_avg(dev, fw_val32);
  614. else
  615. aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2;
  616. if (fwnode_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &fw_val32) >= 0)
  617. aad_pdata->adc_1bit_rpt =
  618. da7219_aad_fw_adc_1bit_rpt(dev, fw_val32);
  619. else
  620. aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1;
  621. return aad_pdata;
  622. }
  623. static void da7219_aad_handle_pdata(struct snd_soc_component *component)
  624. {
  625. struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
  626. struct da7219_aad_priv *da7219_aad = da7219->aad;
  627. struct da7219_pdata *pdata = da7219->pdata;
  628. if ((pdata) && (pdata->aad_pdata)) {
  629. struct da7219_aad_pdata *aad_pdata = pdata->aad_pdata;
  630. u8 cfg, mask;
  631. da7219_aad->irq = aad_pdata->irq;
  632. switch (aad_pdata->micbias_pulse_lvl) {
  633. case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V:
  634. case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V:
  635. da7219_aad->micbias_pulse_lvl =
  636. (aad_pdata->micbias_pulse_lvl <<
  637. DA7219_MICBIAS1_LEVEL_SHIFT);
  638. break;
  639. default:
  640. break;
  641. }
  642. da7219_aad->micbias_pulse_time = aad_pdata->micbias_pulse_time;
  643. switch (aad_pdata->btn_cfg) {
  644. case DA7219_AAD_BTN_CFG_2MS:
  645. case DA7219_AAD_BTN_CFG_5MS:
  646. case DA7219_AAD_BTN_CFG_10MS:
  647. case DA7219_AAD_BTN_CFG_50MS:
  648. case DA7219_AAD_BTN_CFG_100MS:
  649. case DA7219_AAD_BTN_CFG_200MS:
  650. case DA7219_AAD_BTN_CFG_500MS:
  651. da7219_aad->btn_cfg = (aad_pdata->btn_cfg <<
  652. DA7219_BUTTON_CONFIG_SHIFT);
  653. }
  654. cfg = 0;
  655. mask = 0;
  656. switch (aad_pdata->mic_det_thr) {
  657. case DA7219_AAD_MIC_DET_THR_200_OHMS:
  658. case DA7219_AAD_MIC_DET_THR_500_OHMS:
  659. case DA7219_AAD_MIC_DET_THR_750_OHMS:
  660. case DA7219_AAD_MIC_DET_THR_1000_OHMS:
  661. cfg |= (aad_pdata->mic_det_thr <<
  662. DA7219_MIC_DET_THRESH_SHIFT);
  663. mask |= DA7219_MIC_DET_THRESH_MASK;
  664. }
  665. snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, mask, cfg);
  666. cfg = 0;
  667. mask = 0;
  668. switch (aad_pdata->jack_ins_deb) {
  669. case DA7219_AAD_JACK_INS_DEB_5MS:
  670. case DA7219_AAD_JACK_INS_DEB_10MS:
  671. case DA7219_AAD_JACK_INS_DEB_20MS:
  672. case DA7219_AAD_JACK_INS_DEB_50MS:
  673. case DA7219_AAD_JACK_INS_DEB_100MS:
  674. case DA7219_AAD_JACK_INS_DEB_200MS:
  675. case DA7219_AAD_JACK_INS_DEB_500MS:
  676. case DA7219_AAD_JACK_INS_DEB_1S:
  677. cfg |= (aad_pdata->jack_ins_deb <<
  678. DA7219_JACKDET_DEBOUNCE_SHIFT);
  679. mask |= DA7219_JACKDET_DEBOUNCE_MASK;
  680. }
  681. switch (aad_pdata->jack_det_rate) {
  682. case DA7219_AAD_JACK_DET_RATE_32_64MS:
  683. case DA7219_AAD_JACK_DET_RATE_64_128MS:
  684. case DA7219_AAD_JACK_DET_RATE_128_256MS:
  685. case DA7219_AAD_JACK_DET_RATE_256_512MS:
  686. cfg |= (aad_pdata->jack_det_rate <<
  687. DA7219_JACK_DETECT_RATE_SHIFT);
  688. mask |= DA7219_JACK_DETECT_RATE_MASK;
  689. }
  690. switch (aad_pdata->jack_rem_deb) {
  691. case DA7219_AAD_JACK_REM_DEB_1MS:
  692. case DA7219_AAD_JACK_REM_DEB_5MS:
  693. case DA7219_AAD_JACK_REM_DEB_10MS:
  694. case DA7219_AAD_JACK_REM_DEB_20MS:
  695. cfg |= (aad_pdata->jack_rem_deb <<
  696. DA7219_JACKDET_REM_DEB_SHIFT);
  697. mask |= DA7219_JACKDET_REM_DEB_MASK;
  698. }
  699. snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_2, mask, cfg);
  700. snd_soc_component_write(component, DA7219_ACCDET_CONFIG_3,
  701. aad_pdata->a_d_btn_thr);
  702. snd_soc_component_write(component, DA7219_ACCDET_CONFIG_4,
  703. aad_pdata->d_b_btn_thr);
  704. snd_soc_component_write(component, DA7219_ACCDET_CONFIG_5,
  705. aad_pdata->b_c_btn_thr);
  706. snd_soc_component_write(component, DA7219_ACCDET_CONFIG_6,
  707. aad_pdata->c_mic_btn_thr);
  708. cfg = 0;
  709. mask = 0;
  710. switch (aad_pdata->btn_avg) {
  711. case DA7219_AAD_BTN_AVG_1:
  712. case DA7219_AAD_BTN_AVG_2:
  713. case DA7219_AAD_BTN_AVG_4:
  714. case DA7219_AAD_BTN_AVG_8:
  715. cfg |= (aad_pdata->btn_avg <<
  716. DA7219_BUTTON_AVERAGE_SHIFT);
  717. mask |= DA7219_BUTTON_AVERAGE_MASK;
  718. }
  719. switch (aad_pdata->adc_1bit_rpt) {
  720. case DA7219_AAD_ADC_1BIT_RPT_1:
  721. case DA7219_AAD_ADC_1BIT_RPT_2:
  722. case DA7219_AAD_ADC_1BIT_RPT_4:
  723. case DA7219_AAD_ADC_1BIT_RPT_8:
  724. cfg |= (aad_pdata->adc_1bit_rpt <<
  725. DA7219_ADC_1_BIT_REPEAT_SHIFT);
  726. mask |= DA7219_ADC_1_BIT_REPEAT_MASK;
  727. }
  728. snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_7, mask, cfg);
  729. }
  730. }
  731. /*
  732. * Suspend/Resume
  733. */
  734. void da7219_aad_suspend(struct snd_soc_component *component)
  735. {
  736. struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
  737. struct da7219_aad_priv *da7219_aad = da7219->aad;
  738. struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
  739. u8 micbias_ctrl;
  740. if (da7219_aad->jack) {
  741. /* Disable jack detection during suspend */
  742. snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
  743. DA7219_ACCDET_EN_MASK, 0);
  744. /*
  745. * If we have a 4-pole jack inserted, then micbias will be
  746. * enabled. We can disable micbias here, and keep a note to
  747. * re-enable it on resume. If jack removal occurred during
  748. * suspend then this will be dealt with through the IRQ handler.
  749. */
  750. if (da7219_aad->jack_inserted) {
  751. micbias_ctrl = snd_soc_component_read(component, DA7219_MICBIAS_CTRL);
  752. if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) {
  753. snd_soc_dapm_disable_pin(dapm, "Mic Bias");
  754. snd_soc_dapm_sync(dapm);
  755. da7219_aad->micbias_resume_enable = true;
  756. }
  757. }
  758. }
  759. synchronize_irq(da7219_aad->irq);
  760. }
  761. void da7219_aad_resume(struct snd_soc_component *component)
  762. {
  763. struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
  764. struct da7219_aad_priv *da7219_aad = da7219->aad;
  765. struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
  766. if (da7219_aad->jack) {
  767. /* Re-enable micbias if previously enabled for 4-pole jack */
  768. if (da7219_aad->jack_inserted &&
  769. da7219_aad->micbias_resume_enable) {
  770. snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
  771. snd_soc_dapm_sync(dapm);
  772. da7219_aad->micbias_resume_enable = false;
  773. }
  774. /* Re-enable jack detection */
  775. snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
  776. DA7219_ACCDET_EN_MASK,
  777. DA7219_ACCDET_EN_MASK);
  778. }
  779. }
  780. /*
  781. * Init/Exit
  782. */
  783. int da7219_aad_init(struct snd_soc_component *component)
  784. {
  785. struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
  786. struct da7219_aad_priv *da7219_aad = da7219->aad;
  787. u8 mask[DA7219_AAD_IRQ_REG_MAX];
  788. int ret;
  789. da7219_aad->component = component;
  790. /* Handle any DT/ACPI/platform data */
  791. da7219_aad_handle_pdata(component);
  792. /* Disable button detection */
  793. snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
  794. DA7219_BUTTON_CONFIG_MASK, 0);
  795. /* Enable ground switch */
  796. snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01);
  797. INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work);
  798. INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work);
  799. ret = request_threaded_irq(da7219_aad->irq, NULL,
  800. da7219_aad_irq_thread,
  801. IRQF_TRIGGER_LOW | IRQF_ONESHOT,
  802. "da7219-aad", da7219_aad);
  803. if (ret) {
  804. dev_err(component->dev, "Failed to request IRQ: %d\n", ret);
  805. return ret;
  806. }
  807. /* Unmask AAD IRQs */
  808. memset(mask, 0, DA7219_AAD_IRQ_REG_MAX);
  809. regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
  810. &mask, DA7219_AAD_IRQ_REG_MAX);
  811. return 0;
  812. }
  813. EXPORT_SYMBOL_GPL(da7219_aad_init);
  814. void da7219_aad_exit(struct snd_soc_component *component)
  815. {
  816. struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
  817. struct da7219_aad_priv *da7219_aad = da7219->aad;
  818. u8 mask[DA7219_AAD_IRQ_REG_MAX];
  819. /* Mask off AAD IRQs */
  820. memset(mask, DA7219_BYTE_MASK, DA7219_AAD_IRQ_REG_MAX);
  821. regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
  822. mask, DA7219_AAD_IRQ_REG_MAX);
  823. free_irq(da7219_aad->irq, da7219_aad);
  824. cancel_work_sync(&da7219_aad->btn_det_work);
  825. cancel_work_sync(&da7219_aad->hptest_work);
  826. }
  827. EXPORT_SYMBOL_GPL(da7219_aad_exit);
  828. /*
  829. * AAD related I2C probe handling
  830. */
  831. int da7219_aad_probe(struct i2c_client *i2c)
  832. {
  833. struct da7219_priv *da7219 = i2c_get_clientdata(i2c);
  834. struct device *dev = &i2c->dev;
  835. struct da7219_aad_priv *da7219_aad;
  836. da7219_aad = devm_kzalloc(dev, sizeof(*da7219_aad), GFP_KERNEL);
  837. if (!da7219_aad)
  838. return -ENOMEM;
  839. da7219->aad = da7219_aad;
  840. /* Retrieve any DT/ACPI/platform data */
  841. if (da7219->pdata && !da7219->pdata->aad_pdata)
  842. da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(dev);
  843. return 0;
  844. }
  845. EXPORT_SYMBOL_GPL(da7219_aad_probe);
  846. MODULE_DESCRIPTION("ASoC DA7219 AAD Driver");
  847. MODULE_AUTHOR("Adam Thomson <[email protected]>");
  848. MODULE_LICENSE("GPL");