extcon-arizona.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052
  1. /*
  2. * extcon-arizona.c - Extcon driver Wolfson Arizona devices
  3. *
  4. * Copyright (C) 2012 Wolfson Microelectronics plc
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include <linux/kernel.h>
  17. #include <linux/module.h>
  18. #include <linux/i2c.h>
  19. #include <linux/slab.h>
  20. #include <linux/interrupt.h>
  21. #include <linux/err.h>
  22. #include <linux/gpio.h>
  23. #include <linux/input.h>
  24. #include <linux/platform_device.h>
  25. #include <linux/pm_runtime.h>
  26. #include <linux/regulator/consumer.h>
  27. #include <linux/extcon.h>
  28. #include <linux/mfd/arizona/core.h>
  29. #include <linux/mfd/arizona/pdata.h>
  30. #include <linux/mfd/arizona/registers.h>
  31. #define ARIZONA_DEFAULT_HP 32
  32. #define ARIZONA_NUM_BUTTONS 6
  33. #define ARIZONA_ACCDET_MODE_MIC 0
  34. #define ARIZONA_ACCDET_MODE_HPL 1
  35. #define ARIZONA_ACCDET_MODE_HPR 2
  36. struct arizona_extcon_info {
  37. struct device *dev;
  38. struct arizona *arizona;
  39. struct mutex lock;
  40. struct regulator *micvdd;
  41. struct input_dev *input;
  42. int micd_mode;
  43. const struct arizona_micd_config *micd_modes;
  44. int micd_num_modes;
  45. bool micd_reva;
  46. bool micd_clamp;
  47. bool hpdet_active;
  48. int num_hpdet_res;
  49. unsigned int hpdet_res[2];
  50. bool mic;
  51. bool detecting;
  52. int jack_flips;
  53. int hpdet_ip;
  54. struct extcon_dev edev;
  55. };
  56. static const struct arizona_micd_config micd_default_modes[] = {
  57. { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
  58. { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
  59. };
  60. static struct {
  61. u16 status;
  62. int report;
  63. } arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = {
  64. { 0x1, BTN_0 },
  65. { 0x2, BTN_1 },
  66. { 0x4, BTN_2 },
  67. { 0x8, BTN_3 },
  68. { 0x10, BTN_4 },
  69. { 0x20, BTN_5 },
  70. };
  71. #define ARIZONA_CABLE_MECHANICAL 0
  72. #define ARIZONA_CABLE_MICROPHONE 1
  73. #define ARIZONA_CABLE_HEADPHONE 2
  74. #define ARIZONA_CABLE_LINEOUT 3
  75. static const char *arizona_cable[] = {
  76. "Mechanical",
  77. "Microphone",
  78. "Headphone",
  79. "Line-out",
  80. NULL,
  81. };
  82. static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
  83. {
  84. struct arizona *arizona = info->arizona;
  85. if (arizona->pdata.micd_pol_gpio > 0)
  86. gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
  87. info->micd_modes[mode].gpio);
  88. regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
  89. ARIZONA_MICD_BIAS_SRC_MASK,
  90. info->micd_modes[mode].bias);
  91. regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
  92. ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
  93. info->micd_mode = mode;
  94. dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
  95. }
  96. static void arizona_start_mic(struct arizona_extcon_info *info)
  97. {
  98. struct arizona *arizona = info->arizona;
  99. bool change;
  100. int ret;
  101. /* Microphone detection can't use idle mode */
  102. pm_runtime_get(info->dev);
  103. ret = regulator_enable(info->micvdd);
  104. if (ret != 0) {
  105. dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
  106. ret);
  107. }
  108. if (info->micd_reva) {
  109. regmap_write(arizona->regmap, 0x80, 0x3);
  110. regmap_write(arizona->regmap, 0x294, 0);
  111. regmap_write(arizona->regmap, 0x80, 0x0);
  112. }
  113. regmap_update_bits(arizona->regmap,
  114. ARIZONA_ACCESSORY_DETECT_MODE_1,
  115. ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
  116. regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
  117. ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
  118. &change);
  119. if (!change) {
  120. regulator_disable(info->micvdd);
  121. pm_runtime_put_autosuspend(info->dev);
  122. }
  123. }
  124. static void arizona_stop_mic(struct arizona_extcon_info *info)
  125. {
  126. struct arizona *arizona = info->arizona;
  127. bool change;
  128. regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
  129. ARIZONA_MICD_ENA, 0,
  130. &change);
  131. if (info->micd_reva) {
  132. regmap_write(arizona->regmap, 0x80, 0x3);
  133. regmap_write(arizona->regmap, 0x294, 2);
  134. regmap_write(arizona->regmap, 0x80, 0x0);
  135. }
  136. if (change) {
  137. regulator_disable(info->micvdd);
  138. pm_runtime_mark_last_busy(info->dev);
  139. pm_runtime_put_autosuspend(info->dev);
  140. }
  141. }
  142. static struct {
  143. unsigned int factor_a;
  144. unsigned int factor_b;
  145. } arizona_hpdet_b_ranges[] = {
  146. { 5528, 362464 },
  147. { 11084, 6186851 },
  148. { 11065, 65460395 },
  149. };
  150. static struct {
  151. int min;
  152. int max;
  153. } arizona_hpdet_c_ranges[] = {
  154. { 0, 30 },
  155. { 8, 100 },
  156. { 100, 1000 },
  157. { 1000, 10000 },
  158. };
  159. static int arizona_hpdet_read(struct arizona_extcon_info *info)
  160. {
  161. struct arizona *arizona = info->arizona;
  162. unsigned int val, range;
  163. int ret;
  164. ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
  165. if (ret != 0) {
  166. dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
  167. ret);
  168. return ret;
  169. }
  170. switch (info->hpdet_ip) {
  171. case 0:
  172. if (!(val & ARIZONA_HP_DONE)) {
  173. dev_err(arizona->dev, "HPDET did not complete: %x\n",
  174. val);
  175. val = ARIZONA_DEFAULT_HP;
  176. }
  177. val &= ARIZONA_HP_LVL_MASK;
  178. break;
  179. case 1:
  180. if (!(val & ARIZONA_HP_DONE_B)) {
  181. dev_err(arizona->dev, "HPDET did not complete: %x\n",
  182. val);
  183. return ARIZONA_DEFAULT_HP;
  184. }
  185. ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
  186. if (ret != 0) {
  187. dev_err(arizona->dev, "Failed to read HP value: %d\n",
  188. ret);
  189. return ARIZONA_DEFAULT_HP;
  190. }
  191. regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
  192. &range);
  193. range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
  194. >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
  195. if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
  196. (val < 100 || val > 0x3fb)) {
  197. range++;
  198. dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
  199. range);
  200. regmap_update_bits(arizona->regmap,
  201. ARIZONA_HEADPHONE_DETECT_1,
  202. ARIZONA_HP_IMPEDANCE_RANGE_MASK,
  203. range <<
  204. ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
  205. return -EAGAIN;
  206. }
  207. /* If we go out of range report top of range */
  208. if (val < 100 || val > 0x3fb) {
  209. dev_dbg(arizona->dev, "Measurement out of range\n");
  210. return 10000;
  211. }
  212. dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
  213. val, range);
  214. val = arizona_hpdet_b_ranges[range].factor_b
  215. / ((val * 100) -
  216. arizona_hpdet_b_ranges[range].factor_a);
  217. break;
  218. default:
  219. dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
  220. info->hpdet_ip);
  221. case 2:
  222. if (!(val & ARIZONA_HP_DONE_B)) {
  223. dev_err(arizona->dev, "HPDET did not complete: %x\n",
  224. val);
  225. return ARIZONA_DEFAULT_HP;
  226. }
  227. val &= ARIZONA_HP_LVL_B_MASK;
  228. regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
  229. &range);
  230. range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
  231. >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
  232. /* Skip up or down a range? */
  233. if (range && (val < arizona_hpdet_c_ranges[range].min)) {
  234. range--;
  235. dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
  236. arizona_hpdet_c_ranges[range].min,
  237. arizona_hpdet_c_ranges[range].max);
  238. regmap_update_bits(arizona->regmap,
  239. ARIZONA_HEADPHONE_DETECT_1,
  240. ARIZONA_HP_IMPEDANCE_RANGE_MASK,
  241. range <<
  242. ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
  243. return -EAGAIN;
  244. }
  245. if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
  246. (val >= arizona_hpdet_c_ranges[range].max)) {
  247. range++;
  248. dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
  249. arizona_hpdet_c_ranges[range].min,
  250. arizona_hpdet_c_ranges[range].max);
  251. regmap_update_bits(arizona->regmap,
  252. ARIZONA_HEADPHONE_DETECT_1,
  253. ARIZONA_HP_IMPEDANCE_RANGE_MASK,
  254. range <<
  255. ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
  256. return -EAGAIN;
  257. }
  258. }
  259. dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
  260. return val;
  261. }
  262. static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
  263. {
  264. struct arizona *arizona = info->arizona;
  265. int ret;
  266. /*
  267. * If we're using HPDET for accessory identification we need
  268. * to take multiple measurements, step through them in sequence.
  269. */
  270. if (arizona->pdata.hpdet_acc_id) {
  271. info->hpdet_res[info->num_hpdet_res++] = *reading;
  272. /*
  273. * If the impedence is too high don't measure the
  274. * second ground.
  275. */
  276. if (info->num_hpdet_res == 1 && *reading >= 45) {
  277. dev_dbg(arizona->dev, "Skipping ground flip\n");
  278. info->hpdet_res[info->num_hpdet_res++] = *reading;
  279. }
  280. if (info->num_hpdet_res == 1) {
  281. dev_dbg(arizona->dev, "Flipping ground\n");
  282. regmap_update_bits(arizona->regmap,
  283. ARIZONA_ACCESSORY_DETECT_MODE_1,
  284. ARIZONA_ACCDET_SRC,
  285. ~info->micd_modes[0].src);
  286. regmap_update_bits(arizona->regmap,
  287. ARIZONA_HEADPHONE_DETECT_1,
  288. ARIZONA_HP_POLL, 0);
  289. regmap_update_bits(arizona->regmap,
  290. ARIZONA_HEADPHONE_DETECT_1,
  291. ARIZONA_HP_POLL, ARIZONA_HP_POLL);
  292. return -EAGAIN;
  293. }
  294. /* OK, got both. Now, compare... */
  295. dev_dbg(arizona->dev, "HPDET measured %d %d\n",
  296. info->hpdet_res[0], info->hpdet_res[1]);
  297. if (info->hpdet_res[0] > info->hpdet_res[1] * 2) {
  298. dev_dbg(arizona->dev, "Detected mic\n");
  299. info->mic = true;
  300. ret = extcon_set_cable_state_(&info->edev,
  301. ARIZONA_CABLE_MICROPHONE,
  302. true);
  303. if (ret != 0) {
  304. dev_err(arizona->dev,
  305. "Failed to report mic: %d\n", ret);
  306. }
  307. /* Take the headphone impedance for the main report */
  308. *reading = info->hpdet_res[1];
  309. } else {
  310. dev_dbg(arizona->dev, "Detected headphone\n");
  311. }
  312. /* Make sure everything is reset back to the real polarity */
  313. regmap_update_bits(arizona->regmap,
  314. ARIZONA_ACCESSORY_DETECT_MODE_1,
  315. ARIZONA_ACCDET_SRC,
  316. info->micd_modes[0].src);
  317. }
  318. return 0;
  319. }
  320. static irqreturn_t arizona_hpdet_irq(int irq, void *data)
  321. {
  322. struct arizona_extcon_info *info = data;
  323. struct arizona *arizona = info->arizona;
  324. int report = ARIZONA_CABLE_HEADPHONE;
  325. int ret, reading;
  326. mutex_lock(&info->lock);
  327. /* If we got a spurious IRQ for some reason then ignore it */
  328. if (!info->hpdet_active) {
  329. dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
  330. mutex_unlock(&info->lock);
  331. return IRQ_NONE;
  332. }
  333. /* If the cable was removed while measuring ignore the result */
  334. ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
  335. if (ret < 0) {
  336. dev_err(arizona->dev, "Failed to check cable state: %d\n",
  337. ret);
  338. goto out;
  339. } else if (!ret) {
  340. dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
  341. goto done;
  342. }
  343. ret = arizona_hpdet_read(info);
  344. if (ret == -EAGAIN) {
  345. goto out;
  346. } else if (ret < 0) {
  347. goto done;
  348. }
  349. reading = ret;
  350. /* Reset back to starting range */
  351. regmap_update_bits(arizona->regmap,
  352. ARIZONA_HEADPHONE_DETECT_1,
  353. ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
  354. 0);
  355. ret = arizona_hpdet_do_id(info, &reading);
  356. if (ret == -EAGAIN) {
  357. goto out;
  358. } else if (ret < 0) {
  359. goto done;
  360. }
  361. /* Report high impedence cables as line outputs */
  362. if (reading >= 5000)
  363. report = ARIZONA_CABLE_LINEOUT;
  364. else
  365. report = ARIZONA_CABLE_HEADPHONE;
  366. ret = extcon_set_cable_state_(&info->edev, report, true);
  367. if (ret != 0)
  368. dev_err(arizona->dev, "Failed to report HP/line: %d\n",
  369. ret);
  370. ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0);
  371. if (ret != 0)
  372. dev_warn(arizona->dev, "Failed to undo magic: %d\n", ret);
  373. ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0);
  374. if (ret != 0)
  375. dev_warn(arizona->dev, "Failed to undo magic: %d\n", ret);
  376. done:
  377. /* Revert back to MICDET mode */
  378. regmap_update_bits(arizona->regmap,
  379. ARIZONA_ACCESSORY_DETECT_MODE_1,
  380. ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
  381. /* If we have a mic then reenable MICDET */
  382. if (info->mic)
  383. arizona_start_mic(info);
  384. if (info->hpdet_active) {
  385. pm_runtime_put_autosuspend(info->dev);
  386. info->hpdet_active = false;
  387. }
  388. out:
  389. mutex_unlock(&info->lock);
  390. return IRQ_HANDLED;
  391. }
  392. static void arizona_identify_headphone(struct arizona_extcon_info *info)
  393. {
  394. struct arizona *arizona = info->arizona;
  395. int ret;
  396. dev_dbg(arizona->dev, "Starting HPDET\n");
  397. /* Make sure we keep the device enabled during the measurement */
  398. pm_runtime_get(info->dev);
  399. info->hpdet_active = true;
  400. if (info->mic)
  401. arizona_stop_mic(info);
  402. ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000);
  403. if (ret != 0)
  404. dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
  405. ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000);
  406. if (ret != 0)
  407. dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
  408. ret = regmap_update_bits(arizona->regmap,
  409. ARIZONA_ACCESSORY_DETECT_MODE_1,
  410. ARIZONA_ACCDET_MODE_MASK,
  411. ARIZONA_ACCDET_MODE_HPL);
  412. if (ret != 0) {
  413. dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
  414. goto err;
  415. }
  416. ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
  417. ARIZONA_HP_POLL, ARIZONA_HP_POLL);
  418. if (ret != 0) {
  419. dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
  420. ret);
  421. goto err;
  422. }
  423. return;
  424. err:
  425. regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
  426. ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
  427. /* Just report headphone */
  428. ret = extcon_update_state(&info->edev,
  429. 1 << ARIZONA_CABLE_HEADPHONE,
  430. 1 << ARIZONA_CABLE_HEADPHONE);
  431. if (ret != 0)
  432. dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
  433. if (info->mic)
  434. arizona_start_mic(info);
  435. info->hpdet_active = false;
  436. }
  437. static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
  438. {
  439. struct arizona *arizona = info->arizona;
  440. int ret;
  441. dev_dbg(arizona->dev, "Starting identification via HPDET\n");
  442. /* Make sure we keep the device enabled during the measurement */
  443. pm_runtime_get(info->dev);
  444. info->hpdet_active = true;
  445. ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000);
  446. if (ret != 0)
  447. dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
  448. ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000);
  449. if (ret != 0)
  450. dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
  451. ret = regmap_update_bits(arizona->regmap,
  452. ARIZONA_ACCESSORY_DETECT_MODE_1,
  453. ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
  454. info->micd_modes[0].src |
  455. ARIZONA_ACCDET_MODE_HPL);
  456. if (ret != 0) {
  457. dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
  458. goto err;
  459. }
  460. ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
  461. ARIZONA_HP_POLL, ARIZONA_HP_POLL);
  462. if (ret != 0) {
  463. dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
  464. ret);
  465. goto err;
  466. }
  467. return;
  468. err:
  469. regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
  470. ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
  471. /* Just report headphone */
  472. ret = extcon_update_state(&info->edev,
  473. 1 << ARIZONA_CABLE_HEADPHONE,
  474. 1 << ARIZONA_CABLE_HEADPHONE);
  475. if (ret != 0)
  476. dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
  477. info->hpdet_active = false;
  478. }
  479. static irqreturn_t arizona_micdet(int irq, void *data)
  480. {
  481. struct arizona_extcon_info *info = data;
  482. struct arizona *arizona = info->arizona;
  483. unsigned int val, lvl;
  484. int ret, i;
  485. mutex_lock(&info->lock);
  486. ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
  487. if (ret != 0) {
  488. dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
  489. mutex_unlock(&info->lock);
  490. return IRQ_NONE;
  491. }
  492. dev_dbg(arizona->dev, "MICDET: %x\n", val);
  493. if (!(val & ARIZONA_MICD_VALID)) {
  494. dev_warn(arizona->dev, "Microphone detection state invalid\n");
  495. mutex_unlock(&info->lock);
  496. return IRQ_NONE;
  497. }
  498. /* Due to jack detect this should never happen */
  499. if (!(val & ARIZONA_MICD_STS)) {
  500. dev_warn(arizona->dev, "Detected open circuit\n");
  501. info->detecting = false;
  502. goto handled;
  503. }
  504. /* If we got a high impedence we should have a headset, report it. */
  505. if (info->detecting && (val & 0x400)) {
  506. arizona_identify_headphone(info);
  507. ret = extcon_update_state(&info->edev,
  508. 1 << ARIZONA_CABLE_MICROPHONE,
  509. 1 << ARIZONA_CABLE_MICROPHONE);
  510. if (ret != 0)
  511. dev_err(arizona->dev, "Headset report failed: %d\n",
  512. ret);
  513. info->mic = true;
  514. info->detecting = false;
  515. goto handled;
  516. }
  517. /* If we detected a lower impedence during initial startup
  518. * then we probably have the wrong polarity, flip it. Don't
  519. * do this for the lowest impedences to speed up detection of
  520. * plain headphones. If both polarities report a low
  521. * impedence then give up and report headphones.
  522. */
  523. if (info->detecting && (val & 0x3f8)) {
  524. info->jack_flips++;
  525. if (info->jack_flips >= info->micd_num_modes) {
  526. dev_dbg(arizona->dev, "Detected HP/line\n");
  527. arizona_identify_headphone(info);
  528. info->detecting = false;
  529. arizona_stop_mic(info);
  530. } else {
  531. info->micd_mode++;
  532. if (info->micd_mode == info->micd_num_modes)
  533. info->micd_mode = 0;
  534. arizona_extcon_set_mode(info, info->micd_mode);
  535. info->jack_flips++;
  536. }
  537. goto handled;
  538. }
  539. /*
  540. * If we're still detecting and we detect a short then we've
  541. * got a headphone. Otherwise it's a button press.
  542. */
  543. if (val & 0x3fc) {
  544. if (info->mic) {
  545. dev_dbg(arizona->dev, "Mic button detected\n");
  546. lvl = val & ARIZONA_MICD_LVL_MASK;
  547. lvl >>= ARIZONA_MICD_LVL_SHIFT;
  548. for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
  549. if (lvl & arizona_lvl_to_key[i].status)
  550. input_report_key(info->input,
  551. arizona_lvl_to_key[i].report,
  552. 1);
  553. input_sync(info->input);
  554. } else if (info->detecting) {
  555. dev_dbg(arizona->dev, "Headphone detected\n");
  556. info->detecting = false;
  557. arizona_stop_mic(info);
  558. arizona_identify_headphone(info);
  559. } else {
  560. dev_warn(arizona->dev, "Button with no mic: %x\n",
  561. val);
  562. }
  563. } else {
  564. dev_dbg(arizona->dev, "Mic button released\n");
  565. for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
  566. input_report_key(info->input,
  567. arizona_lvl_to_key[i].report, 0);
  568. input_sync(info->input);
  569. }
  570. handled:
  571. pm_runtime_mark_last_busy(info->dev);
  572. mutex_unlock(&info->lock);
  573. return IRQ_HANDLED;
  574. }
  575. static irqreturn_t arizona_jackdet(int irq, void *data)
  576. {
  577. struct arizona_extcon_info *info = data;
  578. struct arizona *arizona = info->arizona;
  579. unsigned int val, present, mask;
  580. int ret, i;
  581. pm_runtime_get_sync(info->dev);
  582. mutex_lock(&info->lock);
  583. if (arizona->pdata.jd_gpio5) {
  584. mask = ARIZONA_MICD_CLAMP_STS;
  585. present = 0;
  586. } else {
  587. mask = ARIZONA_JD1_STS;
  588. present = ARIZONA_JD1_STS;
  589. }
  590. ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
  591. if (ret != 0) {
  592. dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
  593. ret);
  594. mutex_unlock(&info->lock);
  595. pm_runtime_put_autosuspend(info->dev);
  596. return IRQ_NONE;
  597. }
  598. if ((val & mask) == present) {
  599. dev_dbg(arizona->dev, "Detected jack\n");
  600. ret = extcon_set_cable_state_(&info->edev,
  601. ARIZONA_CABLE_MECHANICAL, true);
  602. if (ret != 0)
  603. dev_err(arizona->dev, "Mechanical report failed: %d\n",
  604. ret);
  605. if (!arizona->pdata.hpdet_acc_id) {
  606. info->detecting = true;
  607. info->mic = false;
  608. info->jack_flips = 0;
  609. arizona_start_mic(info);
  610. } else {
  611. arizona_start_hpdet_acc_id(info);
  612. }
  613. } else {
  614. dev_dbg(arizona->dev, "Detected jack removal\n");
  615. arizona_stop_mic(info);
  616. info->num_hpdet_res = 0;
  617. for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
  618. info->hpdet_res[i] = 0;
  619. info->mic = false;
  620. for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
  621. input_report_key(info->input,
  622. arizona_lvl_to_key[i].report, 0);
  623. input_sync(info->input);
  624. ret = extcon_update_state(&info->edev, 0xffffffff, 0);
  625. if (ret != 0)
  626. dev_err(arizona->dev, "Removal report failed: %d\n",
  627. ret);
  628. }
  629. mutex_unlock(&info->lock);
  630. pm_runtime_mark_last_busy(info->dev);
  631. pm_runtime_put_autosuspend(info->dev);
  632. return IRQ_HANDLED;
  633. }
  634. static int arizona_extcon_probe(struct platform_device *pdev)
  635. {
  636. struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
  637. struct arizona_pdata *pdata;
  638. struct arizona_extcon_info *info;
  639. int jack_irq_fall, jack_irq_rise;
  640. int ret, mode, i;
  641. pdata = dev_get_platdata(arizona->dev);
  642. info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
  643. if (!info) {
  644. dev_err(&pdev->dev, "Failed to allocate memory\n");
  645. ret = -ENOMEM;
  646. goto err;
  647. }
  648. info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
  649. if (IS_ERR(info->micvdd)) {
  650. ret = PTR_ERR(info->micvdd);
  651. dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
  652. goto err;
  653. }
  654. mutex_init(&info->lock);
  655. info->arizona = arizona;
  656. info->dev = &pdev->dev;
  657. platform_set_drvdata(pdev, info);
  658. switch (arizona->type) {
  659. case WM5102:
  660. switch (arizona->rev) {
  661. case 0:
  662. info->micd_reva = true;
  663. break;
  664. default:
  665. info->micd_clamp = true;
  666. info->hpdet_ip = 1;
  667. break;
  668. }
  669. break;
  670. default:
  671. break;
  672. }
  673. info->edev.name = "Headset Jack";
  674. info->edev.supported_cable = arizona_cable;
  675. ret = extcon_dev_register(&info->edev, arizona->dev);
  676. if (ret < 0) {
  677. dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
  678. ret);
  679. goto err;
  680. }
  681. if (pdata->num_micd_configs) {
  682. info->micd_modes = pdata->micd_configs;
  683. info->micd_num_modes = pdata->num_micd_configs;
  684. } else {
  685. info->micd_modes = micd_default_modes;
  686. info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
  687. }
  688. if (arizona->pdata.micd_pol_gpio > 0) {
  689. if (info->micd_modes[0].gpio)
  690. mode = GPIOF_OUT_INIT_HIGH;
  691. else
  692. mode = GPIOF_OUT_INIT_LOW;
  693. ret = devm_gpio_request_one(&pdev->dev,
  694. arizona->pdata.micd_pol_gpio,
  695. mode,
  696. "MICD polarity");
  697. if (ret != 0) {
  698. dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
  699. arizona->pdata.micd_pol_gpio, ret);
  700. goto err_register;
  701. }
  702. }
  703. if (arizona->pdata.micd_bias_start_time)
  704. regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
  705. ARIZONA_MICD_BIAS_STARTTIME_MASK,
  706. arizona->pdata.micd_bias_start_time
  707. << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
  708. /*
  709. * If we have a clamp use it, activating in conjunction with
  710. * GPIO5 if that is connected for jack detect operation.
  711. */
  712. if (info->micd_clamp) {
  713. if (arizona->pdata.jd_gpio5) {
  714. /* Put the GPIO into input mode */
  715. regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
  716. 0xc101);
  717. regmap_update_bits(arizona->regmap,
  718. ARIZONA_MICD_CLAMP_CONTROL,
  719. ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
  720. } else {
  721. regmap_update_bits(arizona->regmap,
  722. ARIZONA_MICD_CLAMP_CONTROL,
  723. ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
  724. }
  725. regmap_update_bits(arizona->regmap,
  726. ARIZONA_JACK_DETECT_DEBOUNCE,
  727. ARIZONA_MICD_CLAMP_DB,
  728. ARIZONA_MICD_CLAMP_DB);
  729. }
  730. arizona_extcon_set_mode(info, 0);
  731. info->input = devm_input_allocate_device(&pdev->dev);
  732. if (!info->input) {
  733. dev_err(arizona->dev, "Can't allocate input dev\n");
  734. ret = -ENOMEM;
  735. goto err_register;
  736. }
  737. for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
  738. input_set_capability(info->input, EV_KEY,
  739. arizona_lvl_to_key[i].report);
  740. info->input->name = "Headset";
  741. info->input->phys = "arizona/extcon";
  742. info->input->dev.parent = &pdev->dev;
  743. pm_runtime_enable(&pdev->dev);
  744. pm_runtime_idle(&pdev->dev);
  745. pm_runtime_get_sync(&pdev->dev);
  746. if (arizona->pdata.jd_gpio5) {
  747. jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
  748. jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
  749. } else {
  750. jack_irq_rise = ARIZONA_IRQ_JD_RISE;
  751. jack_irq_fall = ARIZONA_IRQ_JD_FALL;
  752. }
  753. ret = arizona_request_irq(arizona, jack_irq_rise,
  754. "JACKDET rise", arizona_jackdet, info);
  755. if (ret != 0) {
  756. dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
  757. ret);
  758. goto err_input;
  759. }
  760. ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
  761. if (ret != 0) {
  762. dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
  763. ret);
  764. goto err_rise;
  765. }
  766. ret = arizona_request_irq(arizona, jack_irq_fall,
  767. "JACKDET fall", arizona_jackdet, info);
  768. if (ret != 0) {
  769. dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
  770. goto err_rise_wake;
  771. }
  772. ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
  773. if (ret != 0) {
  774. dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
  775. ret);
  776. goto err_fall;
  777. }
  778. ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
  779. "MICDET", arizona_micdet, info);
  780. if (ret != 0) {
  781. dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
  782. goto err_fall_wake;
  783. }
  784. ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
  785. "HPDET", arizona_hpdet_irq, info);
  786. if (ret != 0) {
  787. dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
  788. goto err_micdet;
  789. }
  790. regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
  791. ARIZONA_MICD_RATE_MASK,
  792. 8 << ARIZONA_MICD_RATE_SHIFT);
  793. arizona_clk32k_enable(arizona);
  794. regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
  795. ARIZONA_JD1_DB, ARIZONA_JD1_DB);
  796. regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
  797. ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
  798. ret = regulator_allow_bypass(info->micvdd, true);
  799. if (ret != 0)
  800. dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
  801. ret);
  802. pm_runtime_put(&pdev->dev);
  803. ret = input_register_device(info->input);
  804. if (ret) {
  805. dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
  806. goto err_hpdet;
  807. }
  808. return 0;
  809. err_hpdet:
  810. arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
  811. err_micdet:
  812. arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
  813. err_fall_wake:
  814. arizona_set_irq_wake(arizona, jack_irq_fall, 0);
  815. err_fall:
  816. arizona_free_irq(arizona, jack_irq_fall, info);
  817. err_rise_wake:
  818. arizona_set_irq_wake(arizona, jack_irq_rise, 0);
  819. err_rise:
  820. arizona_free_irq(arizona, jack_irq_rise, info);
  821. err_input:
  822. err_register:
  823. pm_runtime_disable(&pdev->dev);
  824. extcon_dev_unregister(&info->edev);
  825. err:
  826. return ret;
  827. }
  828. static int arizona_extcon_remove(struct platform_device *pdev)
  829. {
  830. struct arizona_extcon_info *info = platform_get_drvdata(pdev);
  831. struct arizona *arizona = info->arizona;
  832. int jack_irq_rise, jack_irq_fall;
  833. pm_runtime_disable(&pdev->dev);
  834. regmap_update_bits(arizona->regmap,
  835. ARIZONA_MICD_CLAMP_CONTROL,
  836. ARIZONA_MICD_CLAMP_MODE_MASK, 0);
  837. if (arizona->pdata.jd_gpio5) {
  838. jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
  839. jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
  840. } else {
  841. jack_irq_rise = ARIZONA_IRQ_JD_RISE;
  842. jack_irq_fall = ARIZONA_IRQ_JD_FALL;
  843. }
  844. arizona_set_irq_wake(arizona, jack_irq_rise, 0);
  845. arizona_set_irq_wake(arizona, jack_irq_fall, 0);
  846. arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
  847. arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
  848. arizona_free_irq(arizona, jack_irq_rise, info);
  849. arizona_free_irq(arizona, jack_irq_fall, info);
  850. regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
  851. ARIZONA_JD1_ENA, 0);
  852. arizona_clk32k_disable(arizona);
  853. extcon_dev_unregister(&info->edev);
  854. return 0;
  855. }
  856. static struct platform_driver arizona_extcon_driver = {
  857. .driver = {
  858. .name = "arizona-extcon",
  859. .owner = THIS_MODULE,
  860. },
  861. .probe = arizona_extcon_probe,
  862. .remove = arizona_extcon_remove,
  863. };
  864. module_platform_driver(arizona_extcon_driver);
  865. MODULE_DESCRIPTION("Arizona Extcon driver");
  866. MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
  867. MODULE_LICENSE("GPL");
  868. MODULE_ALIAS("platform:extcon-arizona");