blob: a287cece0593c327c53e8961b70a0dde8b1af2ce [file] [log] [blame]
Mark Brownf2c32a82012-06-24 12:09:45 +01001/*
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
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/i2c.h>
20#include <linux/slab.h>
21#include <linux/interrupt.h>
22#include <linux/err.h>
23#include <linux/gpio.h>
Mark Brown34efe4d2012-07-20 17:07:29 +010024#include <linux/input.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010025#include <linux/platform_device.h>
26#include <linux/pm_runtime.h>
27#include <linux/regulator/consumer.h>
28#include <linux/extcon.h>
29
Mark Brownbbbd46e2013-01-10 19:38:43 +000030#include <sound/soc.h>
31
Mark Brownf2c32a82012-06-24 12:09:45 +010032#include <linux/mfd/arizona/core.h>
33#include <linux/mfd/arizona/pdata.h>
34#include <linux/mfd/arizona/registers.h>
35
Mark Brown6fed4d82013-04-01 22:03:06 +010036#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010037
Mark Brown4f340332013-01-11 08:55:43 +090038#define ARIZONA_ACCDET_MODE_MIC 0
39#define ARIZONA_ACCDET_MODE_HPL 1
40#define ARIZONA_ACCDET_MODE_HPR 2
41
Mark Brown9dd5e532013-04-01 19:09:45 +010042#define ARIZONA_HPDET_MAX 10000
43
Mark Brown2643fd62013-04-01 19:07:28 +010044#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010045#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010046
Mark Brownf2c32a82012-06-24 12:09:45 +010047struct arizona_extcon_info {
48 struct device *dev;
49 struct arizona *arizona;
50 struct mutex lock;
51 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010052 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010053
Mark Browna3e20782013-04-01 19:05:27 +010054 u16 last_jackdet;
55
Mark Brownf2c32a82012-06-24 12:09:45 +010056 int micd_mode;
57 const struct arizona_micd_config *micd_modes;
58 int micd_num_modes;
59
Mark Brown6fed4d82013-04-01 22:03:06 +010060 const struct arizona_micd_range *micd_ranges;
61 int num_micd_ranges;
62
Mark Brown7abd4e22013-04-01 19:25:55 +010063 int micd_timeout;
64
Mark Brownf2c32a82012-06-24 12:09:45 +010065 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090066 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010067
Mark Brown0e27bd32013-02-05 21:00:15 +000068 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010069 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010070 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000071
Mark Brown4f340332013-01-11 08:55:43 +090072 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000073 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010074 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090075
Mark Browndd235ee2013-01-11 08:55:51 +090076 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090077 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090078
Mark Brownf2c32a82012-06-24 12:09:45 +010079 bool mic;
80 bool detecting;
81 int jack_flips;
82
Mark Brown4f340332013-01-11 08:55:43 +090083 int hpdet_ip;
84
Mark Brownf2c32a82012-06-24 12:09:45 +010085 struct extcon_dev edev;
86};
87
88static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +010089 { ARIZONA_ACCDET_SRC, 1, 0 },
90 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +010091};
92
Mark Brown6fed4d82013-04-01 22:03:06 +010093static const struct arizona_micd_range micd_default_ranges[] = {
94 { .max = 11, .key = BTN_0 },
95 { .max = 28, .key = BTN_1 },
96 { .max = 54, .key = BTN_2 },
97 { .max = 100, .key = BTN_3 },
98 { .max = 186, .key = BTN_4 },
99 { .max = 430, .key = BTN_5 },
100};
101
102static const int arizona_micd_levels[] = {
103 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
104 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
105 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
106 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
107 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100108};
109
Mark Brown325c6422012-06-28 13:08:30 +0100110#define ARIZONA_CABLE_MECHANICAL 0
111#define ARIZONA_CABLE_MICROPHONE 1
112#define ARIZONA_CABLE_HEADPHONE 2
Mark Brown4f340332013-01-11 08:55:43 +0900113#define ARIZONA_CABLE_LINEOUT 3
Mark Brownf2c32a82012-06-24 12:09:45 +0100114
115static const char *arizona_cable[] = {
Mark Brown325c6422012-06-28 13:08:30 +0100116 "Mechanical",
117 "Microphone",
118 "Headphone",
Mark Brown4f340332013-01-11 08:55:43 +0900119 "Line-out",
Mark Brownf2c32a82012-06-24 12:09:45 +0100120 NULL,
121};
122
Mark Brown9dd5e532013-04-01 19:09:45 +0100123static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
124
Mark Brown03409072013-02-12 13:00:31 +0000125static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
126 unsigned int magic)
127{
128 struct arizona *arizona = info->arizona;
Mark Brown03409072013-02-12 13:00:31 +0000129 int ret;
130
131 mutex_lock(&arizona->dapm->card->dapm_mutex);
132
Mark Browndf8c3db2013-02-22 18:38:03 +0000133 arizona->hpdet_magic = magic;
134
135 /* Keep the HP output stages disabled while doing the magic */
136 if (magic) {
137 ret = regmap_update_bits(arizona->regmap,
138 ARIZONA_OUTPUT_ENABLES_1,
139 ARIZONA_OUT1L_ENA |
140 ARIZONA_OUT1R_ENA, 0);
141 if (ret != 0)
142 dev_warn(arizona->dev,
143 "Failed to disable headphone outputs: %d\n",
144 ret);
Mark Brown03409072013-02-12 13:00:31 +0000145 }
146
Mark Browndf8c3db2013-02-22 18:38:03 +0000147 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
148 magic);
149 if (ret != 0)
150 dev_warn(arizona->dev, "Failed to do magic: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000151 ret);
152
Mark Browndf8c3db2013-02-22 18:38:03 +0000153 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
154 magic);
155 if (ret != 0)
156 dev_warn(arizona->dev, "Failed to do magic: %d\n",
157 ret);
158
159 /* Restore the desired state while not doing the magic */
160 if (!magic) {
161 ret = regmap_update_bits(arizona->regmap,
162 ARIZONA_OUTPUT_ENABLES_1,
163 ARIZONA_OUT1L_ENA |
164 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000165 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000166 dev_warn(arizona->dev,
167 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000168 ret);
169 }
170
171 mutex_unlock(&arizona->dapm->card->dapm_mutex);
172}
173
Mark Brownf2c32a82012-06-24 12:09:45 +0100174static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
175{
176 struct arizona *arizona = info->arizona;
177
Mark Brown6fed4d82013-04-01 22:03:06 +0100178 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800179
Mark Browncd74f7b2012-11-27 16:14:26 +0900180 if (arizona->pdata.micd_pol_gpio > 0)
181 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
182 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100183 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
184 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100185 info->micd_modes[mode].bias <<
186 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100187 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
188 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
189
190 info->micd_mode = mode;
191
192 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
193}
194
Mark Brownbbbd46e2013-01-10 19:38:43 +0000195static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
196{
Charles Keepax41024242013-09-23 14:33:59 +0100197 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000198 case 1:
199 return "MICBIAS1";
200 case 2:
201 return "MICBIAS2";
202 case 3:
203 return "MICBIAS3";
204 default:
205 return "MICVDD";
206 }
207}
208
209static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
210{
211 struct arizona *arizona = info->arizona;
212 const char *widget = arizona_extcon_get_micbias(info);
213 struct snd_soc_dapm_context *dapm = arizona->dapm;
214 int ret;
215
216 mutex_lock(&dapm->card->dapm_mutex);
217
218 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
219 if (ret != 0)
220 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
221 widget, ret);
222
223 mutex_unlock(&dapm->card->dapm_mutex);
224
225 snd_soc_dapm_sync(dapm);
226
227 if (!arizona->pdata.micd_force_micbias) {
228 mutex_lock(&dapm->card->dapm_mutex);
229
230 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
231 if (ret != 0)
232 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
233 widget, ret);
234
235 mutex_unlock(&dapm->card->dapm_mutex);
236
237 snd_soc_dapm_sync(dapm);
238 }
239}
240
Mark Brown9b1270c2013-01-11 08:55:46 +0900241static void arizona_start_mic(struct arizona_extcon_info *info)
242{
243 struct arizona *arizona = info->arizona;
244 bool change;
245 int ret;
246
Mark Brown9b1270c2013-01-11 08:55:46 +0900247 /* Microphone detection can't use idle mode */
248 pm_runtime_get(info->dev);
249
Mark Brownbbbd46e2013-01-10 19:38:43 +0000250 if (info->detecting) {
251 ret = regulator_allow_bypass(info->micvdd, false);
252 if (ret != 0) {
253 dev_err(arizona->dev,
254 "Failed to regulate MICVDD: %d\n",
255 ret);
256 }
257 }
258
Mark Brown9b1270c2013-01-11 08:55:46 +0900259 ret = regulator_enable(info->micvdd);
260 if (ret != 0) {
261 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
262 ret);
263 }
264
265 if (info->micd_reva) {
266 regmap_write(arizona->regmap, 0x80, 0x3);
267 regmap_write(arizona->regmap, 0x294, 0);
268 regmap_write(arizona->regmap, 0x80, 0x0);
269 }
270
271 regmap_update_bits(arizona->regmap,
272 ARIZONA_ACCESSORY_DETECT_MODE_1,
273 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
274
Mark Brownbbbd46e2013-01-10 19:38:43 +0000275 arizona_extcon_pulse_micbias(info);
276
Mark Brown9b1270c2013-01-11 08:55:46 +0900277 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
278 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
279 &change);
280 if (!change) {
281 regulator_disable(info->micvdd);
282 pm_runtime_put_autosuspend(info->dev);
283 }
284}
285
286static void arizona_stop_mic(struct arizona_extcon_info *info)
287{
288 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000289 const char *widget = arizona_extcon_get_micbias(info);
290 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900291 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000292 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900293
294 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
295 ARIZONA_MICD_ENA, 0,
296 &change);
297
Mark Brownbbbd46e2013-01-10 19:38:43 +0000298 mutex_lock(&dapm->card->dapm_mutex);
299
300 ret = snd_soc_dapm_disable_pin(dapm, widget);
301 if (ret != 0)
302 dev_warn(arizona->dev,
303 "Failed to disable %s: %d\n",
304 widget, ret);
305
306 mutex_unlock(&dapm->card->dapm_mutex);
307
308 snd_soc_dapm_sync(dapm);
309
Mark Brown9b1270c2013-01-11 08:55:46 +0900310 if (info->micd_reva) {
311 regmap_write(arizona->regmap, 0x80, 0x3);
312 regmap_write(arizona->regmap, 0x294, 2);
313 regmap_write(arizona->regmap, 0x80, 0x0);
314 }
315
Mark Brownbbbd46e2013-01-10 19:38:43 +0000316 ret = regulator_allow_bypass(info->micvdd, true);
317 if (ret != 0) {
318 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
319 ret);
320 }
321
Mark Brown9b1270c2013-01-11 08:55:46 +0900322 if (change) {
323 regulator_disable(info->micvdd);
324 pm_runtime_mark_last_busy(info->dev);
325 pm_runtime_put_autosuspend(info->dev);
326 }
327}
328
Mark Brown4f340332013-01-11 08:55:43 +0900329static struct {
330 unsigned int factor_a;
331 unsigned int factor_b;
332} arizona_hpdet_b_ranges[] = {
333 { 5528, 362464 },
334 { 11084, 6186851 },
335 { 11065, 65460395 },
336};
337
338static struct {
339 int min;
340 int max;
341} arizona_hpdet_c_ranges[] = {
342 { 0, 30 },
343 { 8, 100 },
344 { 100, 1000 },
345 { 1000, 10000 },
346};
347
348static int arizona_hpdet_read(struct arizona_extcon_info *info)
349{
350 struct arizona *arizona = info->arizona;
351 unsigned int val, range;
352 int ret;
353
354 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
355 if (ret != 0) {
356 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
357 ret);
358 return ret;
359 }
360
361 switch (info->hpdet_ip) {
362 case 0:
363 if (!(val & ARIZONA_HP_DONE)) {
364 dev_err(arizona->dev, "HPDET did not complete: %x\n",
365 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900366 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900367 }
368
369 val &= ARIZONA_HP_LVL_MASK;
370 break;
371
372 case 1:
373 if (!(val & ARIZONA_HP_DONE_B)) {
374 dev_err(arizona->dev, "HPDET did not complete: %x\n",
375 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900376 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900377 }
378
379 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
380 if (ret != 0) {
381 dev_err(arizona->dev, "Failed to read HP value: %d\n",
382 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900383 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900384 }
385
386 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
387 &range);
388 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
389 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
390
391 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100392 (val < 100 || val >= 0x3fb)) {
Mark Brown4f340332013-01-11 08:55:43 +0900393 range++;
394 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
395 range);
396 regmap_update_bits(arizona->regmap,
397 ARIZONA_HEADPHONE_DETECT_1,
398 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
399 range <<
400 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
401 return -EAGAIN;
402 }
403
404 /* If we go out of range report top of range */
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100405 if (val < 100 || val >= 0x3fb) {
Mark Brown4f340332013-01-11 08:55:43 +0900406 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100407 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900408 }
409
410 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
411 val, range);
412
413 val = arizona_hpdet_b_ranges[range].factor_b
414 / ((val * 100) -
415 arizona_hpdet_b_ranges[range].factor_a);
416 break;
417
418 default:
419 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
420 info->hpdet_ip);
421 case 2:
422 if (!(val & ARIZONA_HP_DONE_B)) {
423 dev_err(arizona->dev, "HPDET did not complete: %x\n",
424 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900425 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900426 }
427
428 val &= ARIZONA_HP_LVL_B_MASK;
429
430 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
431 &range);
432 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
433 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
434
435 /* Skip up or down a range? */
436 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
437 range--;
438 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
439 arizona_hpdet_c_ranges[range].min,
440 arizona_hpdet_c_ranges[range].max);
441 regmap_update_bits(arizona->regmap,
442 ARIZONA_HEADPHONE_DETECT_1,
443 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
444 range <<
445 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
446 return -EAGAIN;
447 }
448
449 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
450 (val >= arizona_hpdet_c_ranges[range].max)) {
451 range++;
452 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
453 arizona_hpdet_c_ranges[range].min,
454 arizona_hpdet_c_ranges[range].max);
455 regmap_update_bits(arizona->regmap,
456 ARIZONA_HEADPHONE_DETECT_1,
457 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
458 range <<
459 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
460 return -EAGAIN;
461 }
462 }
463
464 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
465 return val;
466}
467
Mark Brown9c2ba272013-02-25 23:42:31 +0000468static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
469 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900470{
471 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900472 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900473
474 /*
475 * If we're using HPDET for accessory identification we need
476 * to take multiple measurements, step through them in sequence.
477 */
478 if (arizona->pdata.hpdet_acc_id) {
479 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900480
481 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000482 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900483 dev_dbg(arizona->dev, "Measuring mic\n");
484
485 regmap_update_bits(arizona->regmap,
486 ARIZONA_ACCESSORY_DETECT_MODE_1,
487 ARIZONA_ACCDET_MODE_MASK |
488 ARIZONA_ACCDET_SRC,
489 ARIZONA_ACCDET_MODE_HPR |
490 info->micd_modes[0].src);
491
492 gpio_set_value_cansleep(id_gpio, 1);
493
Mark Browndd235ee2013-01-11 08:55:51 +0900494 regmap_update_bits(arizona->regmap,
495 ARIZONA_HEADPHONE_DETECT_1,
496 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
497 return -EAGAIN;
498 }
499
500 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000501 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
502 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000503
504 /* Take the headphone impedance for the main report */
505 *reading = info->hpdet_res[0];
506
Mark Brown9dd5e532013-04-01 19:09:45 +0100507 /* Sometimes we get false readings due to slow insert */
508 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
509 dev_dbg(arizona->dev, "Retrying high impedance\n");
510 info->num_hpdet_res = 0;
511 info->hpdet_retried = true;
512 arizona_start_hpdet_acc_id(info);
513 pm_runtime_put(info->dev);
514 return -EAGAIN;
515 }
516
Mark Brown1eda6aa2013-01-11 08:55:54 +0900517 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530518 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900519 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000520 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900521 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000522 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000523 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900524 } else {
525 dev_dbg(arizona->dev, "Detected headphone\n");
526 }
527
528 /* Make sure everything is reset back to the real polarity */
529 regmap_update_bits(arizona->regmap,
530 ARIZONA_ACCESSORY_DETECT_MODE_1,
531 ARIZONA_ACCDET_SRC,
532 info->micd_modes[0].src);
533 }
534
535 return 0;
536}
537
Mark Brown4f340332013-01-11 08:55:43 +0900538static irqreturn_t arizona_hpdet_irq(int irq, void *data)
539{
540 struct arizona_extcon_info *info = data;
541 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900542 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900543 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900544 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000545 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900546
547 mutex_lock(&info->lock);
548
549 /* If we got a spurious IRQ for some reason then ignore it */
550 if (!info->hpdet_active) {
551 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
552 mutex_unlock(&info->lock);
553 return IRQ_NONE;
554 }
555
556 /* If the cable was removed while measuring ignore the result */
557 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
558 if (ret < 0) {
559 dev_err(arizona->dev, "Failed to check cable state: %d\n",
560 ret);
561 goto out;
562 } else if (!ret) {
563 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
564 goto done;
565 }
566
567 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900568 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900569 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900570 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900571 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900572 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900573
574 /* Reset back to starting range */
575 regmap_update_bits(arizona->regmap,
576 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900577 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
578 0);
579
Mark Brown9c2ba272013-02-25 23:42:31 +0000580 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900581 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900582 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900583 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900584 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900585
586 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900587 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900588 report = ARIZONA_CABLE_LINEOUT;
589 else
590 report = ARIZONA_CABLE_HEADPHONE;
591
592 ret = extcon_set_cable_state_(&info->edev, report, true);
593 if (ret != 0)
594 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
595 ret);
596
Mark Brown03409072013-02-12 13:00:31 +0000597 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900598
599done:
Mark Brown1eda6aa2013-01-11 08:55:54 +0900600 if (id_gpio)
601 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900602
603 /* Revert back to MICDET mode */
604 regmap_update_bits(arizona->regmap,
605 ARIZONA_ACCESSORY_DETECT_MODE_1,
606 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
607
608 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000609 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900610 arizona_start_mic(info);
611
612 if (info->hpdet_active) {
613 pm_runtime_put_autosuspend(info->dev);
614 info->hpdet_active = false;
615 }
616
Mark Brownbf14ee52013-02-05 20:20:17 +0000617 info->hpdet_done = true;
618
Mark Brown4f340332013-01-11 08:55:43 +0900619out:
620 mutex_unlock(&info->lock);
621
622 return IRQ_HANDLED;
623}
624
625static void arizona_identify_headphone(struct arizona_extcon_info *info)
626{
627 struct arizona *arizona = info->arizona;
628 int ret;
629
Mark Brownbf14ee52013-02-05 20:20:17 +0000630 if (info->hpdet_done)
631 return;
632
Mark Brown4f340332013-01-11 08:55:43 +0900633 dev_dbg(arizona->dev, "Starting HPDET\n");
634
635 /* Make sure we keep the device enabled during the measurement */
636 pm_runtime_get(info->dev);
637
638 info->hpdet_active = true;
639
640 if (info->mic)
641 arizona_stop_mic(info);
642
Mark Brown03409072013-02-12 13:00:31 +0000643 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900644
645 ret = regmap_update_bits(arizona->regmap,
646 ARIZONA_ACCESSORY_DETECT_MODE_1,
647 ARIZONA_ACCDET_MODE_MASK,
648 ARIZONA_ACCDET_MODE_HPL);
649 if (ret != 0) {
650 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
651 goto err;
652 }
653
654 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
655 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
656 if (ret != 0) {
657 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
658 ret);
659 goto err;
660 }
661
662 return;
663
664err:
665 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
666 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
667
668 /* Just report headphone */
669 ret = extcon_update_state(&info->edev,
670 1 << ARIZONA_CABLE_HEADPHONE,
671 1 << ARIZONA_CABLE_HEADPHONE);
672 if (ret != 0)
673 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
674
675 if (info->mic)
676 arizona_start_mic(info);
677
678 info->hpdet_active = false;
679}
Mark Browndd235ee2013-01-11 08:55:51 +0900680
681static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
682{
683 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000684 int hp_reading = 32;
685 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900686 int ret;
687
688 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
689
690 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000691 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900692
693 info->hpdet_active = true;
694
Mark Brown03409072013-02-12 13:00:31 +0000695 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900696
697 ret = regmap_update_bits(arizona->regmap,
698 ARIZONA_ACCESSORY_DETECT_MODE_1,
699 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
700 info->micd_modes[0].src |
701 ARIZONA_ACCDET_MODE_HPL);
702 if (ret != 0) {
703 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
704 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900705 }
706
Mark Brown9c2ba272013-02-25 23:42:31 +0000707 if (arizona->pdata.hpdet_acc_id_line) {
708 ret = regmap_update_bits(arizona->regmap,
709 ARIZONA_HEADPHONE_DETECT_1,
710 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
711 if (ret != 0) {
712 dev_err(arizona->dev,
713 "Can't start HPDETL measurement: %d\n",
714 ret);
715 goto err;
716 }
717 } else {
718 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900719 }
720
721 return;
722
723err:
724 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
725 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
726
727 /* Just report headphone */
728 ret = extcon_update_state(&info->edev,
729 1 << ARIZONA_CABLE_HEADPHONE,
730 1 << ARIZONA_CABLE_HEADPHONE);
731 if (ret != 0)
732 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
733
Mark Brown4f340332013-01-11 08:55:43 +0900734 info->hpdet_active = false;
735}
736
Mark Brown939c5672013-04-01 19:17:34 +0100737static void arizona_micd_timeout_work(struct work_struct *work)
738{
739 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900740 struct arizona_extcon_info,
741 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100742
743 mutex_lock(&info->lock);
744
745 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
746 arizona_identify_headphone(info);
747
748 info->detecting = false;
749
750 arizona_stop_mic(info);
751
752 mutex_unlock(&info->lock);
753}
754
Mark Browncd59e792013-04-01 19:21:48 +0100755static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100756{
Mark Browncd59e792013-04-01 19:21:48 +0100757 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900758 struct arizona_extcon_info,
759 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100760 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100761 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100762 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100763
Mark Brown939c5672013-04-01 19:17:34 +0100764 cancel_delayed_work_sync(&info->micd_timeout_work);
765
Mark Brownf2c32a82012-06-24 12:09:45 +0100766 mutex_lock(&info->lock);
767
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100768 for (i = 0; i < 10 && !(val & 0x7fc); i++) {
769 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
770 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900771 dev_err(arizona->dev,
772 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100773 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100774 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100775 }
776
777 dev_dbg(arizona->dev, "MICDET: %x\n", val);
778
779 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900780 dev_warn(arizona->dev,
781 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100782 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100783 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100784 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100785 }
786
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100787 if (i == 10 && !(val & 0x7fc)) {
788 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100789 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100790 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100791 }
792
793 /* Due to jack detect this should never happen */
794 if (!(val & ARIZONA_MICD_STS)) {
795 dev_warn(arizona->dev, "Detected open circuit\n");
796 info->detecting = false;
797 goto handled;
798 }
799
800 /* If we got a high impedence we should have a headset, report it. */
801 if (info->detecting && (val & 0x400)) {
Mark Brown4f340332013-01-11 08:55:43 +0900802 arizona_identify_headphone(info);
803
Mark Brown325c6422012-06-28 13:08:30 +0100804 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900805 1 << ARIZONA_CABLE_MICROPHONE,
806 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100807
808 if (ret != 0)
809 dev_err(arizona->dev, "Headset report failed: %d\n",
810 ret);
811
Mark Brownbbbd46e2013-01-10 19:38:43 +0000812 /* Don't need to regulate for button detection */
813 ret = regulator_allow_bypass(info->micvdd, false);
814 if (ret != 0) {
815 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
816 ret);
817 }
818
Mark Brownf2c32a82012-06-24 12:09:45 +0100819 info->mic = true;
820 info->detecting = false;
821 goto handled;
822 }
823
824 /* If we detected a lower impedence during initial startup
825 * then we probably have the wrong polarity, flip it. Don't
826 * do this for the lowest impedences to speed up detection of
827 * plain headphones. If both polarities report a low
828 * impedence then give up and report headphones.
829 */
830 if (info->detecting && (val & 0x3f8)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800831 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900832 dev_dbg(arizona->dev, "Detected HP/line\n");
833 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100834
Mark Brown4f340332013-01-11 08:55:43 +0900835 info->detecting = false;
836
837 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100838 } else {
839 info->micd_mode++;
840 if (info->micd_mode == info->micd_num_modes)
841 info->micd_mode = 0;
842 arizona_extcon_set_mode(info, info->micd_mode);
843
844 info->jack_flips++;
845 }
846
847 goto handled;
848 }
849
850 /*
851 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100852 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100853 */
854 if (val & 0x3fc) {
855 if (info->mic) {
856 dev_dbg(arizona->dev, "Mic button detected\n");
857
Mark Brown34efe4d2012-07-20 17:07:29 +0100858 lvl = val & ARIZONA_MICD_LVL_MASK;
859 lvl >>= ARIZONA_MICD_LVL_SHIFT;
860
Mark Brown41a57852013-04-01 19:18:18 +0100861 for (i = 0; i < info->num_micd_ranges; i++)
862 input_report_key(info->input,
863 info->micd_ranges[i].key, 0);
864
Mark Brown6fed4d82013-04-01 22:03:06 +0100865 WARN_ON(!lvl);
866 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
867 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
868 key = info->micd_ranges[ffs(lvl) - 1].key;
869 input_report_key(info->input, key, 1);
870 input_sync(info->input);
871 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100872
Mark Brownf2c32a82012-06-24 12:09:45 +0100873 } else if (info->detecting) {
874 dev_dbg(arizona->dev, "Headphone detected\n");
875 info->detecting = false;
876 arizona_stop_mic(info);
877
Mark Brown4f340332013-01-11 08:55:43 +0900878 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100879 } else {
880 dev_warn(arizona->dev, "Button with no mic: %x\n",
881 val);
882 }
883 } else {
884 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100885 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100886 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100887 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100888 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000889 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100890 }
891
892handled:
Mark Brown939c5672013-04-01 19:17:34 +0100893 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100894 queue_delayed_work(system_power_efficient_wq,
895 &info->micd_timeout_work,
896 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100897
Mark Brownf2c32a82012-06-24 12:09:45 +0100898 pm_runtime_mark_last_busy(info->dev);
899 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100900}
901
902static irqreturn_t arizona_micdet(int irq, void *data)
903{
904 struct arizona_extcon_info *info = data;
905 struct arizona *arizona = info->arizona;
906 int debounce = arizona->pdata.micd_detect_debounce;
907
908 cancel_delayed_work_sync(&info->micd_detect_work);
909 cancel_delayed_work_sync(&info->micd_timeout_work);
910
911 mutex_lock(&info->lock);
912 if (!info->detecting)
913 debounce = 0;
914 mutex_unlock(&info->lock);
915
916 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100917 queue_delayed_work(system_power_efficient_wq,
918 &info->micd_detect_work,
919 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100920 else
921 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100922
923 return IRQ_HANDLED;
924}
925
Mark Brown0e27bd32013-02-05 21:00:15 +0000926static void arizona_hpdet_work(struct work_struct *work)
927{
928 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900929 struct arizona_extcon_info,
930 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000931
932 mutex_lock(&info->lock);
933 arizona_start_hpdet_acc_id(info);
934 mutex_unlock(&info->lock);
935}
936
Mark Brownf2c32a82012-06-24 12:09:45 +0100937static irqreturn_t arizona_jackdet(int irq, void *data)
938{
939 struct arizona_extcon_info *info = data;
940 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900941 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100942 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100943 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100944
Mark Brown939c5672013-04-01 19:17:34 +0100945 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
946 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100947
Mark Browna3e20782013-04-01 19:05:27 +0100948 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000949
Mark Brownf2c32a82012-06-24 12:09:45 +0100950 mutex_lock(&info->lock);
951
Mark Brown92a49872013-01-11 08:55:39 +0900952 if (arizona->pdata.jd_gpio5) {
953 mask = ARIZONA_MICD_CLAMP_STS;
954 present = 0;
955 } else {
956 mask = ARIZONA_JD1_STS;
957 present = ARIZONA_JD1_STS;
958 }
959
Mark Brownf2c32a82012-06-24 12:09:45 +0100960 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
961 if (ret != 0) {
962 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
963 ret);
964 mutex_unlock(&info->lock);
965 pm_runtime_put_autosuspend(info->dev);
966 return IRQ_NONE;
967 }
968
Mark Browna3e20782013-04-01 19:05:27 +0100969 val &= mask;
970 if (val == info->last_jackdet) {
971 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +0100972 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100973 queue_delayed_work(system_power_efficient_wq,
974 &info->hpdet_work,
975 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +0100976
Chanwoo Choic2275d22013-08-23 10:21:37 +0900977 if (cancelled_mic) {
978 int micd_timeout = info->micd_timeout;
979
Mark Browndf9a5ab2013-07-18 22:42:22 +0100980 queue_delayed_work(system_power_efficient_wq,
981 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900982 msecs_to_jiffies(micd_timeout));
983 }
Mark Brown939c5672013-04-01 19:17:34 +0100984
Mark Browna3e20782013-04-01 19:05:27 +0100985 goto out;
986 }
987 info->last_jackdet = val;
988
989 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100990 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +0100991 ret = extcon_set_cable_state_(&info->edev,
992 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100993
994 if (ret != 0)
995 dev_err(arizona->dev, "Mechanical report failed: %d\n",
996 ret);
997
Mark Browndd235ee2013-01-11 08:55:51 +0900998 if (!arizona->pdata.hpdet_acc_id) {
999 info->detecting = true;
1000 info->mic = false;
1001 info->jack_flips = 0;
1002
1003 arizona_start_mic(info);
1004 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001005 queue_delayed_work(system_power_efficient_wq,
1006 &info->hpdet_work,
1007 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001008 }
Mark Brown4e616872013-01-15 22:09:20 +09001009
1010 regmap_update_bits(arizona->regmap,
1011 ARIZONA_JACK_DETECT_DEBOUNCE,
1012 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001013 } else {
1014 dev_dbg(arizona->dev, "Detected jack removal\n");
1015
1016 arizona_stop_mic(info);
1017
Mark Browndd235ee2013-01-11 08:55:51 +09001018 info->num_hpdet_res = 0;
1019 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1020 info->hpdet_res[i] = 0;
1021 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001022 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001023 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001024
Mark Brown6fed4d82013-04-01 22:03:06 +01001025 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001026 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001027 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001028 input_sync(info->input);
1029
Mark Brownf2c32a82012-06-24 12:09:45 +01001030 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
1031 if (ret != 0)
1032 dev_err(arizona->dev, "Removal report failed: %d\n",
1033 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001034
1035 regmap_update_bits(arizona->regmap,
1036 ARIZONA_JACK_DETECT_DEBOUNCE,
1037 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1038 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001039 }
1040
Mark Brown7abd4e22013-04-01 19:25:55 +01001041 if (arizona->pdata.micd_timeout)
1042 info->micd_timeout = arizona->pdata.micd_timeout;
1043 else
1044 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1045
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001046out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001047 /* Clear trig_sts to make sure DCVDD is not forced up */
1048 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1049 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1050 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1051 ARIZONA_JD1_FALL_TRIG_STS |
1052 ARIZONA_JD1_RISE_TRIG_STS);
1053
Mark Brownf2c32a82012-06-24 12:09:45 +01001054 mutex_unlock(&info->lock);
1055
1056 pm_runtime_mark_last_busy(info->dev);
1057 pm_runtime_put_autosuspend(info->dev);
1058
1059 return IRQ_HANDLED;
1060}
1061
Mark Brown6fed4d82013-04-01 22:03:06 +01001062/* Map a level onto a slot in the register bank */
1063static void arizona_micd_set_level(struct arizona *arizona, int index,
1064 unsigned int level)
1065{
1066 int reg;
1067 unsigned int mask;
1068
1069 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1070
1071 if (!(index % 2)) {
1072 mask = 0x3f00;
1073 level <<= 8;
1074 } else {
1075 mask = 0x3f;
1076 }
1077
1078 /* Program the level itself */
1079 regmap_update_bits(arizona->regmap, reg, mask, level);
1080}
1081
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001082static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001083{
1084 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001085 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001086 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001087 unsigned int val;
Mark Brown92a49872013-01-11 08:55:39 +09001088 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001089 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001090
Mark Brownbbbd46e2013-01-10 19:38:43 +00001091 if (!arizona->dapm || !arizona->dapm->card)
1092 return -EPROBE_DEFER;
1093
Mark Brownf2c32a82012-06-24 12:09:45 +01001094 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1095 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001096 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +01001097 ret = -ENOMEM;
1098 goto err;
1099 }
1100
1101 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1102 if (IS_ERR(info->micvdd)) {
1103 ret = PTR_ERR(info->micvdd);
1104 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
1105 goto err;
1106 }
1107
1108 mutex_init(&info->lock);
1109 info->arizona = arizona;
1110 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001111 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001112 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001113 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001114 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001115 platform_set_drvdata(pdev, info);
1116
1117 switch (arizona->type) {
1118 case WM5102:
1119 switch (arizona->rev) {
1120 case 0:
1121 info->micd_reva = true;
1122 break;
1123 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001124 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001125 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001126 break;
1127 }
1128 break;
1129 default:
1130 break;
1131 }
1132
1133 info->edev.name = "Headset Jack";
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001134 info->edev.dev.parent = arizona->dev;
Mark Brownf2c32a82012-06-24 12:09:45 +01001135 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001136
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001137 ret = extcon_dev_register(&info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001138 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001139 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001140 ret);
1141 goto err;
1142 }
1143
Mark Brown6fed4d82013-04-01 22:03:06 +01001144 info->input = devm_input_allocate_device(&pdev->dev);
1145 if (!info->input) {
1146 dev_err(arizona->dev, "Can't allocate input dev\n");
1147 ret = -ENOMEM;
1148 goto err_register;
1149 }
1150
1151 info->input->name = "Headset";
1152 info->input->phys = "arizona/extcon";
1153 info->input->dev.parent = &pdev->dev;
1154
Mark Brownf2c32a82012-06-24 12:09:45 +01001155 if (pdata->num_micd_configs) {
1156 info->micd_modes = pdata->micd_configs;
1157 info->micd_num_modes = pdata->num_micd_configs;
1158 } else {
1159 info->micd_modes = micd_default_modes;
1160 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1161 }
1162
1163 if (arizona->pdata.micd_pol_gpio > 0) {
1164 if (info->micd_modes[0].gpio)
1165 mode = GPIOF_OUT_INIT_HIGH;
1166 else
1167 mode = GPIOF_OUT_INIT_LOW;
1168
1169 ret = devm_gpio_request_one(&pdev->dev,
1170 arizona->pdata.micd_pol_gpio,
1171 mode,
1172 "MICD polarity");
1173 if (ret != 0) {
1174 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1175 arizona->pdata.micd_pol_gpio, ret);
1176 goto err_register;
1177 }
1178 }
1179
Mark Brown1eda6aa2013-01-11 08:55:54 +09001180 if (arizona->pdata.hpdet_id_gpio > 0) {
1181 ret = devm_gpio_request_one(&pdev->dev,
1182 arizona->pdata.hpdet_id_gpio,
1183 GPIOF_OUT_INIT_LOW,
1184 "HPDET");
1185 if (ret != 0) {
1186 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1187 arizona->pdata.hpdet_id_gpio, ret);
1188 goto err_register;
1189 }
1190 }
1191
Mark Brownb17e5462013-01-11 08:55:24 +09001192 if (arizona->pdata.micd_bias_start_time)
1193 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1194 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1195 arizona->pdata.micd_bias_start_time
1196 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1197
Mark Brown2e033db2013-01-21 17:36:33 +09001198 if (arizona->pdata.micd_rate)
1199 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1200 ARIZONA_MICD_RATE_MASK,
1201 arizona->pdata.micd_rate
1202 << ARIZONA_MICD_RATE_SHIFT);
1203
1204 if (arizona->pdata.micd_dbtime)
1205 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1206 ARIZONA_MICD_DBTIME_MASK,
1207 arizona->pdata.micd_dbtime
1208 << ARIZONA_MICD_DBTIME_SHIFT);
1209
Mark Brown6fed4d82013-04-01 22:03:06 +01001210 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1211
1212 if (arizona->pdata.num_micd_ranges) {
1213 info->micd_ranges = pdata->micd_ranges;
1214 info->num_micd_ranges = pdata->num_micd_ranges;
1215 } else {
1216 info->micd_ranges = micd_default_ranges;
1217 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1218 }
1219
1220 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1221 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1222 arizona->pdata.num_micd_ranges);
1223 }
1224
1225 if (info->num_micd_ranges > 1) {
1226 for (i = 1; i < info->num_micd_ranges; i++) {
1227 if (info->micd_ranges[i - 1].max >
1228 info->micd_ranges[i].max) {
1229 dev_err(arizona->dev,
1230 "MICD ranges must be sorted\n");
1231 ret = -EINVAL;
1232 goto err_input;
1233 }
1234 }
1235 }
1236
1237 /* Disable all buttons by default */
1238 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1239 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1240
1241 /* Set up all the buttons the user specified */
1242 for (i = 0; i < info->num_micd_ranges; i++) {
1243 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1244 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1245 break;
1246
1247 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1248 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1249 info->micd_ranges[i].max);
1250 ret = -EINVAL;
1251 goto err_input;
1252 }
1253
1254 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1255 arizona_micd_levels[j], i);
1256
1257 arizona_micd_set_level(arizona, i, j);
1258 input_set_capability(info->input, EV_KEY,
1259 info->micd_ranges[i].key);
1260
1261 /* Enable reporting of that range */
1262 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1263 1 << i, 1 << i);
1264 }
1265
1266 /* Set all the remaining keys to a maximum */
1267 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1268 arizona_micd_set_level(arizona, i, 0x3f);
1269
Mark Browndab63eb2013-01-11 08:55:36 +09001270 /*
Mark Brown92a49872013-01-11 08:55:39 +09001271 * If we have a clamp use it, activating in conjunction with
1272 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001273 */
1274 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001275 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001276 /* Put the GPIO into input mode with optional pull */
1277 val = 0xc101;
1278 if (arizona->pdata.jd_gpio5_nopull)
1279 val &= ~ARIZONA_GPN_PU;
1280
Mark Brown92a49872013-01-11 08:55:39 +09001281 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001282 val);
Mark Brown92a49872013-01-11 08:55:39 +09001283
1284 regmap_update_bits(arizona->regmap,
1285 ARIZONA_MICD_CLAMP_CONTROL,
1286 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1287 } else {
1288 regmap_update_bits(arizona->regmap,
1289 ARIZONA_MICD_CLAMP_CONTROL,
1290 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1291 }
1292
Mark Browndab63eb2013-01-11 08:55:36 +09001293 regmap_update_bits(arizona->regmap,
1294 ARIZONA_JACK_DETECT_DEBOUNCE,
1295 ARIZONA_MICD_CLAMP_DB,
1296 ARIZONA_MICD_CLAMP_DB);
1297 }
1298
Mark Brownf2c32a82012-06-24 12:09:45 +01001299 arizona_extcon_set_mode(info, 0);
1300
1301 pm_runtime_enable(&pdev->dev);
1302 pm_runtime_idle(&pdev->dev);
1303 pm_runtime_get_sync(&pdev->dev);
1304
Mark Brown92a49872013-01-11 08:55:39 +09001305 if (arizona->pdata.jd_gpio5) {
1306 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1307 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1308 } else {
1309 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1310 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1311 }
1312
1313 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001314 "JACKDET rise", arizona_jackdet, info);
1315 if (ret != 0) {
1316 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1317 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001318 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001319 }
1320
Mark Brown92a49872013-01-11 08:55:39 +09001321 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001322 if (ret != 0) {
1323 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1324 ret);
1325 goto err_rise;
1326 }
1327
Mark Brown92a49872013-01-11 08:55:39 +09001328 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001329 "JACKDET fall", arizona_jackdet, info);
1330 if (ret != 0) {
1331 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1332 goto err_rise_wake;
1333 }
1334
Mark Brown92a49872013-01-11 08:55:39 +09001335 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001336 if (ret != 0) {
1337 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1338 ret);
1339 goto err_fall;
1340 }
1341
1342 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1343 "MICDET", arizona_micdet, info);
1344 if (ret != 0) {
1345 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1346 goto err_fall_wake;
1347 }
1348
Mark Brown4f340332013-01-11 08:55:43 +09001349 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1350 "HPDET", arizona_hpdet_irq, info);
1351 if (ret != 0) {
1352 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1353 goto err_micdet;
1354 }
1355
Mark Brownf2c32a82012-06-24 12:09:45 +01001356 arizona_clk32k_enable(arizona);
1357 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1358 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1359 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1360 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1361
Mark Brownb8575a12012-09-07 17:01:15 +08001362 ret = regulator_allow_bypass(info->micvdd, true);
1363 if (ret != 0)
1364 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1365 ret);
1366
Mark Brownf2c32a82012-06-24 12:09:45 +01001367 pm_runtime_put(&pdev->dev);
1368
Mark Brown34efe4d2012-07-20 17:07:29 +01001369 ret = input_register_device(info->input);
1370 if (ret) {
1371 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001372 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001373 }
1374
Mark Brownf2c32a82012-06-24 12:09:45 +01001375 return 0;
1376
Mark Brown4f340332013-01-11 08:55:43 +09001377err_hpdet:
1378 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001379err_micdet:
1380 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001381err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001382 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001383err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001384 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001385err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001386 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001387err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001388 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001389err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001390err_register:
1391 pm_runtime_disable(&pdev->dev);
1392 extcon_dev_unregister(&info->edev);
1393err:
1394 return ret;
1395}
1396
Bill Pemberton93ed0322012-11-19 13:25:49 -05001397static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001398{
1399 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1400 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001401 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001402
1403 pm_runtime_disable(&pdev->dev);
1404
Mark Browndab63eb2013-01-11 08:55:36 +09001405 regmap_update_bits(arizona->regmap,
1406 ARIZONA_MICD_CLAMP_CONTROL,
1407 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1408
Mark Brown92a49872013-01-11 08:55:39 +09001409 if (arizona->pdata.jd_gpio5) {
1410 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1411 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1412 } else {
1413 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1414 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1415 }
1416
1417 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1418 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1419 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001420 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001421 arizona_free_irq(arizona, jack_irq_rise, info);
1422 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001423 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001424 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1425 ARIZONA_JD1_ENA, 0);
1426 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001427 extcon_dev_unregister(&info->edev);
1428
1429 return 0;
1430}
1431
1432static struct platform_driver arizona_extcon_driver = {
1433 .driver = {
1434 .name = "arizona-extcon",
1435 .owner = THIS_MODULE,
1436 },
1437 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001438 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001439};
1440
1441module_platform_driver(arizona_extcon_driver);
1442
1443MODULE_DESCRIPTION("Arizona Extcon driver");
1444MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1445MODULE_LICENSE("GPL");
1446MODULE_ALIAS("platform:extcon-arizona");