blob: f36debffe6e8c8b2c21dd825626b9be08c7fc5d0 [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
Charles Keepaxffae24f2013-11-14 16:18:21 +000047#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
48 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
49 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
50 ARIZONA_MICD_LVL_7)
51
52#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
53
54#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
55
Mark Brownf2c32a82012-06-24 12:09:45 +010056struct arizona_extcon_info {
57 struct device *dev;
58 struct arizona *arizona;
59 struct mutex lock;
60 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010061 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010062
Mark Browna3e20782013-04-01 19:05:27 +010063 u16 last_jackdet;
64
Mark Brownf2c32a82012-06-24 12:09:45 +010065 int micd_mode;
66 const struct arizona_micd_config *micd_modes;
67 int micd_num_modes;
68
Mark Brown6fed4d82013-04-01 22:03:06 +010069 const struct arizona_micd_range *micd_ranges;
70 int num_micd_ranges;
71
Mark Brown7abd4e22013-04-01 19:25:55 +010072 int micd_timeout;
73
Mark Brownf2c32a82012-06-24 12:09:45 +010074 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090075 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010076
Mark Brown0e27bd32013-02-05 21:00:15 +000077 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010078 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010079 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000080
Mark Brown4f340332013-01-11 08:55:43 +090081 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000082 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010083 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090084
Mark Browndd235ee2013-01-11 08:55:51 +090085 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090086 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090087
Mark Brownf2c32a82012-06-24 12:09:45 +010088 bool mic;
89 bool detecting;
90 int jack_flips;
91
Mark Brown4f340332013-01-11 08:55:43 +090092 int hpdet_ip;
93
Mark Brownf2c32a82012-06-24 12:09:45 +010094 struct extcon_dev edev;
95};
96
97static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +010098 { ARIZONA_ACCDET_SRC, 1, 0 },
99 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100100};
101
Mark Brown6fed4d82013-04-01 22:03:06 +0100102static const struct arizona_micd_range micd_default_ranges[] = {
103 { .max = 11, .key = BTN_0 },
104 { .max = 28, .key = BTN_1 },
105 { .max = 54, .key = BTN_2 },
106 { .max = 100, .key = BTN_3 },
107 { .max = 186, .key = BTN_4 },
108 { .max = 430, .key = BTN_5 },
109};
110
111static const int arizona_micd_levels[] = {
112 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
113 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
114 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
115 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
116 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100117};
118
Mark Brown325c6422012-06-28 13:08:30 +0100119#define ARIZONA_CABLE_MECHANICAL 0
120#define ARIZONA_CABLE_MICROPHONE 1
121#define ARIZONA_CABLE_HEADPHONE 2
Mark Brown4f340332013-01-11 08:55:43 +0900122#define ARIZONA_CABLE_LINEOUT 3
Mark Brownf2c32a82012-06-24 12:09:45 +0100123
124static const char *arizona_cable[] = {
Mark Brown325c6422012-06-28 13:08:30 +0100125 "Mechanical",
126 "Microphone",
127 "Headphone",
Mark Brown4f340332013-01-11 08:55:43 +0900128 "Line-out",
Mark Brownf2c32a82012-06-24 12:09:45 +0100129 NULL,
130};
131
Mark Brown9dd5e532013-04-01 19:09:45 +0100132static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
133
Mark Brown03409072013-02-12 13:00:31 +0000134static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
135 unsigned int magic)
136{
137 struct arizona *arizona = info->arizona;
Mark Brown03409072013-02-12 13:00:31 +0000138 int ret;
139
140 mutex_lock(&arizona->dapm->card->dapm_mutex);
141
Mark Browndf8c3db2013-02-22 18:38:03 +0000142 arizona->hpdet_magic = magic;
143
144 /* Keep the HP output stages disabled while doing the magic */
145 if (magic) {
146 ret = regmap_update_bits(arizona->regmap,
147 ARIZONA_OUTPUT_ENABLES_1,
148 ARIZONA_OUT1L_ENA |
149 ARIZONA_OUT1R_ENA, 0);
150 if (ret != 0)
151 dev_warn(arizona->dev,
152 "Failed to disable headphone outputs: %d\n",
153 ret);
Mark Brown03409072013-02-12 13:00:31 +0000154 }
155
Mark Browndf8c3db2013-02-22 18:38:03 +0000156 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
157 magic);
158 if (ret != 0)
159 dev_warn(arizona->dev, "Failed to do magic: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000160 ret);
161
Mark Browndf8c3db2013-02-22 18:38:03 +0000162 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
163 magic);
164 if (ret != 0)
165 dev_warn(arizona->dev, "Failed to do magic: %d\n",
166 ret);
167
168 /* Restore the desired state while not doing the magic */
169 if (!magic) {
170 ret = regmap_update_bits(arizona->regmap,
171 ARIZONA_OUTPUT_ENABLES_1,
172 ARIZONA_OUT1L_ENA |
173 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000174 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000175 dev_warn(arizona->dev,
176 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000177 ret);
178 }
179
180 mutex_unlock(&arizona->dapm->card->dapm_mutex);
181}
182
Mark Brownf2c32a82012-06-24 12:09:45 +0100183static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
184{
185 struct arizona *arizona = info->arizona;
186
Mark Brown6fed4d82013-04-01 22:03:06 +0100187 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800188
Mark Browncd74f7b2012-11-27 16:14:26 +0900189 if (arizona->pdata.micd_pol_gpio > 0)
190 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
191 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100192 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
193 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100194 info->micd_modes[mode].bias <<
195 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100196 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
197 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
198
199 info->micd_mode = mode;
200
201 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
202}
203
Mark Brownbbbd46e2013-01-10 19:38:43 +0000204static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
205{
Charles Keepax41024242013-09-23 14:33:59 +0100206 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000207 case 1:
208 return "MICBIAS1";
209 case 2:
210 return "MICBIAS2";
211 case 3:
212 return "MICBIAS3";
213 default:
214 return "MICVDD";
215 }
216}
217
218static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
219{
220 struct arizona *arizona = info->arizona;
221 const char *widget = arizona_extcon_get_micbias(info);
222 struct snd_soc_dapm_context *dapm = arizona->dapm;
223 int ret;
224
225 mutex_lock(&dapm->card->dapm_mutex);
226
227 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
228 if (ret != 0)
229 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
230 widget, ret);
231
232 mutex_unlock(&dapm->card->dapm_mutex);
233
234 snd_soc_dapm_sync(dapm);
235
236 if (!arizona->pdata.micd_force_micbias) {
237 mutex_lock(&dapm->card->dapm_mutex);
238
239 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
240 if (ret != 0)
241 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
242 widget, ret);
243
244 mutex_unlock(&dapm->card->dapm_mutex);
245
246 snd_soc_dapm_sync(dapm);
247 }
248}
249
Mark Brown9b1270c2013-01-11 08:55:46 +0900250static void arizona_start_mic(struct arizona_extcon_info *info)
251{
252 struct arizona *arizona = info->arizona;
253 bool change;
254 int ret;
255
Mark Brown9b1270c2013-01-11 08:55:46 +0900256 /* Microphone detection can't use idle mode */
257 pm_runtime_get(info->dev);
258
Mark Brownbbbd46e2013-01-10 19:38:43 +0000259 if (info->detecting) {
260 ret = regulator_allow_bypass(info->micvdd, false);
261 if (ret != 0) {
262 dev_err(arizona->dev,
263 "Failed to regulate MICVDD: %d\n",
264 ret);
265 }
266 }
267
Mark Brown9b1270c2013-01-11 08:55:46 +0900268 ret = regulator_enable(info->micvdd);
269 if (ret != 0) {
270 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
271 ret);
272 }
273
274 if (info->micd_reva) {
275 regmap_write(arizona->regmap, 0x80, 0x3);
276 regmap_write(arizona->regmap, 0x294, 0);
277 regmap_write(arizona->regmap, 0x80, 0x0);
278 }
279
280 regmap_update_bits(arizona->regmap,
281 ARIZONA_ACCESSORY_DETECT_MODE_1,
282 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
283
Mark Brownbbbd46e2013-01-10 19:38:43 +0000284 arizona_extcon_pulse_micbias(info);
285
Mark Brown9b1270c2013-01-11 08:55:46 +0900286 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
287 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
288 &change);
289 if (!change) {
290 regulator_disable(info->micvdd);
291 pm_runtime_put_autosuspend(info->dev);
292 }
293}
294
295static void arizona_stop_mic(struct arizona_extcon_info *info)
296{
297 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000298 const char *widget = arizona_extcon_get_micbias(info);
299 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900300 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000301 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900302
303 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
304 ARIZONA_MICD_ENA, 0,
305 &change);
306
Mark Brownbbbd46e2013-01-10 19:38:43 +0000307 mutex_lock(&dapm->card->dapm_mutex);
308
309 ret = snd_soc_dapm_disable_pin(dapm, widget);
310 if (ret != 0)
311 dev_warn(arizona->dev,
312 "Failed to disable %s: %d\n",
313 widget, ret);
314
315 mutex_unlock(&dapm->card->dapm_mutex);
316
317 snd_soc_dapm_sync(dapm);
318
Mark Brown9b1270c2013-01-11 08:55:46 +0900319 if (info->micd_reva) {
320 regmap_write(arizona->regmap, 0x80, 0x3);
321 regmap_write(arizona->regmap, 0x294, 2);
322 regmap_write(arizona->regmap, 0x80, 0x0);
323 }
324
Mark Brownbbbd46e2013-01-10 19:38:43 +0000325 ret = regulator_allow_bypass(info->micvdd, true);
326 if (ret != 0) {
327 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
328 ret);
329 }
330
Mark Brown9b1270c2013-01-11 08:55:46 +0900331 if (change) {
332 regulator_disable(info->micvdd);
333 pm_runtime_mark_last_busy(info->dev);
334 pm_runtime_put_autosuspend(info->dev);
335 }
336}
337
Mark Brown4f340332013-01-11 08:55:43 +0900338static struct {
339 unsigned int factor_a;
340 unsigned int factor_b;
341} arizona_hpdet_b_ranges[] = {
342 { 5528, 362464 },
343 { 11084, 6186851 },
344 { 11065, 65460395 },
345};
346
347static struct {
348 int min;
349 int max;
350} arizona_hpdet_c_ranges[] = {
351 { 0, 30 },
352 { 8, 100 },
353 { 100, 1000 },
354 { 1000, 10000 },
355};
356
357static int arizona_hpdet_read(struct arizona_extcon_info *info)
358{
359 struct arizona *arizona = info->arizona;
360 unsigned int val, range;
361 int ret;
362
363 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
364 if (ret != 0) {
365 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
366 ret);
367 return ret;
368 }
369
370 switch (info->hpdet_ip) {
371 case 0:
372 if (!(val & ARIZONA_HP_DONE)) {
373 dev_err(arizona->dev, "HPDET did not complete: %x\n",
374 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900375 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900376 }
377
378 val &= ARIZONA_HP_LVL_MASK;
379 break;
380
381 case 1:
382 if (!(val & ARIZONA_HP_DONE_B)) {
383 dev_err(arizona->dev, "HPDET did not complete: %x\n",
384 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900385 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900386 }
387
388 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
389 if (ret != 0) {
390 dev_err(arizona->dev, "Failed to read HP value: %d\n",
391 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900392 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900393 }
394
395 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
396 &range);
397 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
398 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
399
400 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100401 (val < 100 || val >= 0x3fb)) {
Mark Brown4f340332013-01-11 08:55:43 +0900402 range++;
403 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
404 range);
405 regmap_update_bits(arizona->regmap,
406 ARIZONA_HEADPHONE_DETECT_1,
407 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
408 range <<
409 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
410 return -EAGAIN;
411 }
412
413 /* If we go out of range report top of range */
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100414 if (val < 100 || val >= 0x3fb) {
Mark Brown4f340332013-01-11 08:55:43 +0900415 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100416 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900417 }
418
419 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
420 val, range);
421
422 val = arizona_hpdet_b_ranges[range].factor_b
423 / ((val * 100) -
424 arizona_hpdet_b_ranges[range].factor_a);
425 break;
426
427 default:
428 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
429 info->hpdet_ip);
430 case 2:
431 if (!(val & ARIZONA_HP_DONE_B)) {
432 dev_err(arizona->dev, "HPDET did not complete: %x\n",
433 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900434 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900435 }
436
437 val &= ARIZONA_HP_LVL_B_MASK;
438
439 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
440 &range);
441 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
442 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
443
444 /* Skip up or down a range? */
445 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
446 range--;
447 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
448 arizona_hpdet_c_ranges[range].min,
449 arizona_hpdet_c_ranges[range].max);
450 regmap_update_bits(arizona->regmap,
451 ARIZONA_HEADPHONE_DETECT_1,
452 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
453 range <<
454 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
455 return -EAGAIN;
456 }
457
458 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
459 (val >= arizona_hpdet_c_ranges[range].max)) {
460 range++;
461 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
462 arizona_hpdet_c_ranges[range].min,
463 arizona_hpdet_c_ranges[range].max);
464 regmap_update_bits(arizona->regmap,
465 ARIZONA_HEADPHONE_DETECT_1,
466 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
467 range <<
468 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
469 return -EAGAIN;
470 }
471 }
472
473 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
474 return val;
475}
476
Mark Brown9c2ba272013-02-25 23:42:31 +0000477static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
478 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900479{
480 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900481 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900482
483 /*
484 * If we're using HPDET for accessory identification we need
485 * to take multiple measurements, step through them in sequence.
486 */
487 if (arizona->pdata.hpdet_acc_id) {
488 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900489
490 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000491 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900492 dev_dbg(arizona->dev, "Measuring mic\n");
493
494 regmap_update_bits(arizona->regmap,
495 ARIZONA_ACCESSORY_DETECT_MODE_1,
496 ARIZONA_ACCDET_MODE_MASK |
497 ARIZONA_ACCDET_SRC,
498 ARIZONA_ACCDET_MODE_HPR |
499 info->micd_modes[0].src);
500
501 gpio_set_value_cansleep(id_gpio, 1);
502
Mark Browndd235ee2013-01-11 08:55:51 +0900503 regmap_update_bits(arizona->regmap,
504 ARIZONA_HEADPHONE_DETECT_1,
505 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
506 return -EAGAIN;
507 }
508
509 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000510 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
511 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000512
513 /* Take the headphone impedance for the main report */
514 *reading = info->hpdet_res[0];
515
Mark Brown9dd5e532013-04-01 19:09:45 +0100516 /* Sometimes we get false readings due to slow insert */
517 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
518 dev_dbg(arizona->dev, "Retrying high impedance\n");
519 info->num_hpdet_res = 0;
520 info->hpdet_retried = true;
521 arizona_start_hpdet_acc_id(info);
522 pm_runtime_put(info->dev);
523 return -EAGAIN;
524 }
525
Mark Brown1eda6aa2013-01-11 08:55:54 +0900526 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530527 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900528 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000529 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900530 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000531 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000532 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900533 } else {
534 dev_dbg(arizona->dev, "Detected headphone\n");
535 }
536
537 /* Make sure everything is reset back to the real polarity */
538 regmap_update_bits(arizona->regmap,
539 ARIZONA_ACCESSORY_DETECT_MODE_1,
540 ARIZONA_ACCDET_SRC,
541 info->micd_modes[0].src);
542 }
543
544 return 0;
545}
546
Mark Brown4f340332013-01-11 08:55:43 +0900547static irqreturn_t arizona_hpdet_irq(int irq, void *data)
548{
549 struct arizona_extcon_info *info = data;
550 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900551 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900552 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900553 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000554 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900555
556 mutex_lock(&info->lock);
557
558 /* If we got a spurious IRQ for some reason then ignore it */
559 if (!info->hpdet_active) {
560 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
561 mutex_unlock(&info->lock);
562 return IRQ_NONE;
563 }
564
565 /* If the cable was removed while measuring ignore the result */
566 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
567 if (ret < 0) {
568 dev_err(arizona->dev, "Failed to check cable state: %d\n",
569 ret);
570 goto out;
571 } else if (!ret) {
572 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
573 goto done;
574 }
575
576 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900577 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900578 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900579 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900580 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900581 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900582
583 /* Reset back to starting range */
584 regmap_update_bits(arizona->regmap,
585 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900586 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
587 0);
588
Mark Brown9c2ba272013-02-25 23:42:31 +0000589 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900590 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900591 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900592 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900593 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900594
595 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900596 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900597 report = ARIZONA_CABLE_LINEOUT;
598 else
599 report = ARIZONA_CABLE_HEADPHONE;
600
601 ret = extcon_set_cable_state_(&info->edev, report, true);
602 if (ret != 0)
603 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
604 ret);
605
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000606done:
607 /* Reset back to starting range */
608 regmap_update_bits(arizona->regmap,
609 ARIZONA_HEADPHONE_DETECT_1,
610 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
611 0);
612
Mark Brown03409072013-02-12 13:00:31 +0000613 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900614
Mark Brown1eda6aa2013-01-11 08:55:54 +0900615 if (id_gpio)
616 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900617
618 /* Revert back to MICDET mode */
619 regmap_update_bits(arizona->regmap,
620 ARIZONA_ACCESSORY_DETECT_MODE_1,
621 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
622
623 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000624 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900625 arizona_start_mic(info);
626
627 if (info->hpdet_active) {
628 pm_runtime_put_autosuspend(info->dev);
629 info->hpdet_active = false;
630 }
631
Mark Brownbf14ee52013-02-05 20:20:17 +0000632 info->hpdet_done = true;
633
Mark Brown4f340332013-01-11 08:55:43 +0900634out:
635 mutex_unlock(&info->lock);
636
637 return IRQ_HANDLED;
638}
639
640static void arizona_identify_headphone(struct arizona_extcon_info *info)
641{
642 struct arizona *arizona = info->arizona;
643 int ret;
644
Mark Brownbf14ee52013-02-05 20:20:17 +0000645 if (info->hpdet_done)
646 return;
647
Mark Brown4f340332013-01-11 08:55:43 +0900648 dev_dbg(arizona->dev, "Starting HPDET\n");
649
650 /* Make sure we keep the device enabled during the measurement */
651 pm_runtime_get(info->dev);
652
653 info->hpdet_active = true;
654
655 if (info->mic)
656 arizona_stop_mic(info);
657
Mark Brown03409072013-02-12 13:00:31 +0000658 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900659
660 ret = regmap_update_bits(arizona->regmap,
661 ARIZONA_ACCESSORY_DETECT_MODE_1,
662 ARIZONA_ACCDET_MODE_MASK,
663 ARIZONA_ACCDET_MODE_HPL);
664 if (ret != 0) {
665 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
666 goto err;
667 }
668
669 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
670 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
671 if (ret != 0) {
672 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
673 ret);
674 goto err;
675 }
676
677 return;
678
679err:
680 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
681 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
682
683 /* Just report headphone */
684 ret = extcon_update_state(&info->edev,
685 1 << ARIZONA_CABLE_HEADPHONE,
686 1 << ARIZONA_CABLE_HEADPHONE);
687 if (ret != 0)
688 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
689
690 if (info->mic)
691 arizona_start_mic(info);
692
693 info->hpdet_active = false;
694}
Mark Browndd235ee2013-01-11 08:55:51 +0900695
696static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
697{
698 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000699 int hp_reading = 32;
700 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900701 int ret;
702
703 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
704
705 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000706 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900707
708 info->hpdet_active = true;
709
Mark Brown03409072013-02-12 13:00:31 +0000710 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900711
712 ret = regmap_update_bits(arizona->regmap,
713 ARIZONA_ACCESSORY_DETECT_MODE_1,
714 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
715 info->micd_modes[0].src |
716 ARIZONA_ACCDET_MODE_HPL);
717 if (ret != 0) {
718 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
719 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900720 }
721
Mark Brown9c2ba272013-02-25 23:42:31 +0000722 if (arizona->pdata.hpdet_acc_id_line) {
723 ret = regmap_update_bits(arizona->regmap,
724 ARIZONA_HEADPHONE_DETECT_1,
725 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
726 if (ret != 0) {
727 dev_err(arizona->dev,
728 "Can't start HPDETL measurement: %d\n",
729 ret);
730 goto err;
731 }
732 } else {
733 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900734 }
735
736 return;
737
738err:
739 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
740 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
741
742 /* Just report headphone */
743 ret = extcon_update_state(&info->edev,
744 1 << ARIZONA_CABLE_HEADPHONE,
745 1 << ARIZONA_CABLE_HEADPHONE);
746 if (ret != 0)
747 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
748
Mark Brown4f340332013-01-11 08:55:43 +0900749 info->hpdet_active = false;
750}
751
Mark Brown939c5672013-04-01 19:17:34 +0100752static void arizona_micd_timeout_work(struct work_struct *work)
753{
754 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900755 struct arizona_extcon_info,
756 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100757
758 mutex_lock(&info->lock);
759
760 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
761 arizona_identify_headphone(info);
762
763 info->detecting = false;
764
765 arizona_stop_mic(info);
766
767 mutex_unlock(&info->lock);
768}
769
Mark Browncd59e792013-04-01 19:21:48 +0100770static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100771{
Mark Browncd59e792013-04-01 19:21:48 +0100772 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900773 struct arizona_extcon_info,
774 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100775 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100776 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100777 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100778
Mark Brown939c5672013-04-01 19:17:34 +0100779 cancel_delayed_work_sync(&info->micd_timeout_work);
780
Mark Brownf2c32a82012-06-24 12:09:45 +0100781 mutex_lock(&info->lock);
782
Charles Keepax31a847e2013-11-14 16:18:23 +0000783 /* If the cable was removed while measuring ignore the result */
784 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
785 if (ret < 0) {
786 dev_err(arizona->dev, "Failed to check cable state: %d\n",
787 ret);
788 mutex_unlock(&info->lock);
789 return;
790 } else if (!ret) {
791 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
792 mutex_unlock(&info->lock);
793 return;
794 }
795
Charles Keepaxffae24f2013-11-14 16:18:21 +0000796 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100797 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
798 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900799 dev_err(arizona->dev,
800 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100801 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100802 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100803 }
804
805 dev_dbg(arizona->dev, "MICDET: %x\n", val);
806
807 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900808 dev_warn(arizona->dev,
809 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100810 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100811 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100812 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100813 }
814
Charles Keepaxffae24f2013-11-14 16:18:21 +0000815 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100816 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100817 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100818 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100819 }
820
821 /* Due to jack detect this should never happen */
822 if (!(val & ARIZONA_MICD_STS)) {
823 dev_warn(arizona->dev, "Detected open circuit\n");
824 info->detecting = false;
825 goto handled;
826 }
827
828 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000829 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900830 arizona_identify_headphone(info);
831
Mark Brown325c6422012-06-28 13:08:30 +0100832 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900833 1 << ARIZONA_CABLE_MICROPHONE,
834 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100835
836 if (ret != 0)
837 dev_err(arizona->dev, "Headset report failed: %d\n",
838 ret);
839
Mark Brownbbbd46e2013-01-10 19:38:43 +0000840 /* Don't need to regulate for button detection */
841 ret = regulator_allow_bypass(info->micvdd, false);
842 if (ret != 0) {
843 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
844 ret);
845 }
846
Mark Brownf2c32a82012-06-24 12:09:45 +0100847 info->mic = true;
848 info->detecting = false;
849 goto handled;
850 }
851
852 /* If we detected a lower impedence during initial startup
853 * then we probably have the wrong polarity, flip it. Don't
854 * do this for the lowest impedences to speed up detection of
855 * plain headphones. If both polarities report a low
856 * impedence then give up and report headphones.
857 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000858 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800859 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900860 dev_dbg(arizona->dev, "Detected HP/line\n");
861 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100862
Mark Brown4f340332013-01-11 08:55:43 +0900863 info->detecting = false;
864
865 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100866 } else {
867 info->micd_mode++;
868 if (info->micd_mode == info->micd_num_modes)
869 info->micd_mode = 0;
870 arizona_extcon_set_mode(info, info->micd_mode);
871
872 info->jack_flips++;
873 }
874
875 goto handled;
876 }
877
878 /*
879 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100880 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100881 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000882 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100883 if (info->mic) {
884 dev_dbg(arizona->dev, "Mic button detected\n");
885
Mark Brown34efe4d2012-07-20 17:07:29 +0100886 lvl = val & ARIZONA_MICD_LVL_MASK;
887 lvl >>= ARIZONA_MICD_LVL_SHIFT;
888
Mark Brown41a57852013-04-01 19:18:18 +0100889 for (i = 0; i < info->num_micd_ranges; i++)
890 input_report_key(info->input,
891 info->micd_ranges[i].key, 0);
892
Mark Brown6fed4d82013-04-01 22:03:06 +0100893 WARN_ON(!lvl);
894 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
895 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
896 key = info->micd_ranges[ffs(lvl) - 1].key;
897 input_report_key(info->input, key, 1);
898 input_sync(info->input);
899 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100900
Mark Brownf2c32a82012-06-24 12:09:45 +0100901 } else if (info->detecting) {
902 dev_dbg(arizona->dev, "Headphone detected\n");
903 info->detecting = false;
904 arizona_stop_mic(info);
905
Mark Brown4f340332013-01-11 08:55:43 +0900906 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100907 } else {
908 dev_warn(arizona->dev, "Button with no mic: %x\n",
909 val);
910 }
911 } else {
912 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100913 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100914 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100915 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100916 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000917 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100918 }
919
920handled:
Mark Brown939c5672013-04-01 19:17:34 +0100921 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100922 queue_delayed_work(system_power_efficient_wq,
923 &info->micd_timeout_work,
924 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100925
Mark Brownf2c32a82012-06-24 12:09:45 +0100926 pm_runtime_mark_last_busy(info->dev);
927 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100928}
929
930static irqreturn_t arizona_micdet(int irq, void *data)
931{
932 struct arizona_extcon_info *info = data;
933 struct arizona *arizona = info->arizona;
934 int debounce = arizona->pdata.micd_detect_debounce;
935
936 cancel_delayed_work_sync(&info->micd_detect_work);
937 cancel_delayed_work_sync(&info->micd_timeout_work);
938
939 mutex_lock(&info->lock);
940 if (!info->detecting)
941 debounce = 0;
942 mutex_unlock(&info->lock);
943
944 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100945 queue_delayed_work(system_power_efficient_wq,
946 &info->micd_detect_work,
947 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100948 else
949 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100950
951 return IRQ_HANDLED;
952}
953
Mark Brown0e27bd32013-02-05 21:00:15 +0000954static void arizona_hpdet_work(struct work_struct *work)
955{
956 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900957 struct arizona_extcon_info,
958 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000959
960 mutex_lock(&info->lock);
961 arizona_start_hpdet_acc_id(info);
962 mutex_unlock(&info->lock);
963}
964
Mark Brownf2c32a82012-06-24 12:09:45 +0100965static irqreturn_t arizona_jackdet(int irq, void *data)
966{
967 struct arizona_extcon_info *info = data;
968 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900969 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100970 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100971 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100972
Mark Brown939c5672013-04-01 19:17:34 +0100973 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
974 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100975
Mark Browna3e20782013-04-01 19:05:27 +0100976 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000977
Mark Brownf2c32a82012-06-24 12:09:45 +0100978 mutex_lock(&info->lock);
979
Mark Brown92a49872013-01-11 08:55:39 +0900980 if (arizona->pdata.jd_gpio5) {
981 mask = ARIZONA_MICD_CLAMP_STS;
982 present = 0;
983 } else {
984 mask = ARIZONA_JD1_STS;
985 present = ARIZONA_JD1_STS;
986 }
987
Mark Brownf2c32a82012-06-24 12:09:45 +0100988 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
989 if (ret != 0) {
990 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
991 ret);
992 mutex_unlock(&info->lock);
993 pm_runtime_put_autosuspend(info->dev);
994 return IRQ_NONE;
995 }
996
Mark Browna3e20782013-04-01 19:05:27 +0100997 val &= mask;
998 if (val == info->last_jackdet) {
999 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001000 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001001 queue_delayed_work(system_power_efficient_wq,
1002 &info->hpdet_work,
1003 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001004
Chanwoo Choic2275d22013-08-23 10:21:37 +09001005 if (cancelled_mic) {
1006 int micd_timeout = info->micd_timeout;
1007
Mark Browndf9a5ab2013-07-18 22:42:22 +01001008 queue_delayed_work(system_power_efficient_wq,
1009 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001010 msecs_to_jiffies(micd_timeout));
1011 }
Mark Brown939c5672013-04-01 19:17:34 +01001012
Mark Browna3e20782013-04-01 19:05:27 +01001013 goto out;
1014 }
1015 info->last_jackdet = val;
1016
1017 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001018 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +01001019 ret = extcon_set_cable_state_(&info->edev,
1020 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001021
1022 if (ret != 0)
1023 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1024 ret);
1025
Mark Browndd235ee2013-01-11 08:55:51 +09001026 if (!arizona->pdata.hpdet_acc_id) {
1027 info->detecting = true;
1028 info->mic = false;
1029 info->jack_flips = 0;
1030
1031 arizona_start_mic(info);
1032 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001033 queue_delayed_work(system_power_efficient_wq,
1034 &info->hpdet_work,
1035 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001036 }
Mark Brown4e616872013-01-15 22:09:20 +09001037
1038 regmap_update_bits(arizona->regmap,
1039 ARIZONA_JACK_DETECT_DEBOUNCE,
1040 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001041 } else {
1042 dev_dbg(arizona->dev, "Detected jack removal\n");
1043
1044 arizona_stop_mic(info);
1045
Mark Browndd235ee2013-01-11 08:55:51 +09001046 info->num_hpdet_res = 0;
1047 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1048 info->hpdet_res[i] = 0;
1049 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001050 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001051 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001052
Mark Brown6fed4d82013-04-01 22:03:06 +01001053 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001054 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001055 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001056 input_sync(info->input);
1057
Mark Brownf2c32a82012-06-24 12:09:45 +01001058 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
1059 if (ret != 0)
1060 dev_err(arizona->dev, "Removal report failed: %d\n",
1061 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001062
1063 regmap_update_bits(arizona->regmap,
1064 ARIZONA_JACK_DETECT_DEBOUNCE,
1065 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1066 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001067 }
1068
Mark Brown7abd4e22013-04-01 19:25:55 +01001069 if (arizona->pdata.micd_timeout)
1070 info->micd_timeout = arizona->pdata.micd_timeout;
1071 else
1072 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1073
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001074out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001075 /* Clear trig_sts to make sure DCVDD is not forced up */
1076 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1077 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1078 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1079 ARIZONA_JD1_FALL_TRIG_STS |
1080 ARIZONA_JD1_RISE_TRIG_STS);
1081
Mark Brownf2c32a82012-06-24 12:09:45 +01001082 mutex_unlock(&info->lock);
1083
1084 pm_runtime_mark_last_busy(info->dev);
1085 pm_runtime_put_autosuspend(info->dev);
1086
1087 return IRQ_HANDLED;
1088}
1089
Mark Brown6fed4d82013-04-01 22:03:06 +01001090/* Map a level onto a slot in the register bank */
1091static void arizona_micd_set_level(struct arizona *arizona, int index,
1092 unsigned int level)
1093{
1094 int reg;
1095 unsigned int mask;
1096
1097 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1098
1099 if (!(index % 2)) {
1100 mask = 0x3f00;
1101 level <<= 8;
1102 } else {
1103 mask = 0x3f;
1104 }
1105
1106 /* Program the level itself */
1107 regmap_update_bits(arizona->regmap, reg, mask, level);
1108}
1109
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001110static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001111{
1112 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001113 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001114 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001115 unsigned int val;
Mark Brown92a49872013-01-11 08:55:39 +09001116 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001117 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001118
Mark Brownbbbd46e2013-01-10 19:38:43 +00001119 if (!arizona->dapm || !arizona->dapm->card)
1120 return -EPROBE_DEFER;
1121
Mark Brownf2c32a82012-06-24 12:09:45 +01001122 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1123 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001124 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +01001125 ret = -ENOMEM;
1126 goto err;
1127 }
1128
1129 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1130 if (IS_ERR(info->micvdd)) {
1131 ret = PTR_ERR(info->micvdd);
1132 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
1133 goto err;
1134 }
1135
1136 mutex_init(&info->lock);
1137 info->arizona = arizona;
1138 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001139 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001140 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001141 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001142 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001143 platform_set_drvdata(pdev, info);
1144
1145 switch (arizona->type) {
1146 case WM5102:
1147 switch (arizona->rev) {
1148 case 0:
1149 info->micd_reva = true;
1150 break;
1151 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001152 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001153 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001154 break;
1155 }
1156 break;
1157 default:
1158 break;
1159 }
1160
1161 info->edev.name = "Headset Jack";
Chanwoo Choi42d7d75392013-09-27 09:20:26 +09001162 info->edev.dev.parent = arizona->dev;
Mark Brownf2c32a82012-06-24 12:09:45 +01001163 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001164
Chanwoo Choi42d7d75392013-09-27 09:20:26 +09001165 ret = extcon_dev_register(&info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001166 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001167 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001168 ret);
1169 goto err;
1170 }
1171
Mark Brown6fed4d82013-04-01 22:03:06 +01001172 info->input = devm_input_allocate_device(&pdev->dev);
1173 if (!info->input) {
1174 dev_err(arizona->dev, "Can't allocate input dev\n");
1175 ret = -ENOMEM;
1176 goto err_register;
1177 }
1178
1179 info->input->name = "Headset";
1180 info->input->phys = "arizona/extcon";
1181 info->input->dev.parent = &pdev->dev;
1182
Mark Brownf2c32a82012-06-24 12:09:45 +01001183 if (pdata->num_micd_configs) {
1184 info->micd_modes = pdata->micd_configs;
1185 info->micd_num_modes = pdata->num_micd_configs;
1186 } else {
1187 info->micd_modes = micd_default_modes;
1188 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1189 }
1190
1191 if (arizona->pdata.micd_pol_gpio > 0) {
1192 if (info->micd_modes[0].gpio)
1193 mode = GPIOF_OUT_INIT_HIGH;
1194 else
1195 mode = GPIOF_OUT_INIT_LOW;
1196
1197 ret = devm_gpio_request_one(&pdev->dev,
1198 arizona->pdata.micd_pol_gpio,
1199 mode,
1200 "MICD polarity");
1201 if (ret != 0) {
1202 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1203 arizona->pdata.micd_pol_gpio, ret);
1204 goto err_register;
1205 }
1206 }
1207
Mark Brown1eda6aa2013-01-11 08:55:54 +09001208 if (arizona->pdata.hpdet_id_gpio > 0) {
1209 ret = devm_gpio_request_one(&pdev->dev,
1210 arizona->pdata.hpdet_id_gpio,
1211 GPIOF_OUT_INIT_LOW,
1212 "HPDET");
1213 if (ret != 0) {
1214 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1215 arizona->pdata.hpdet_id_gpio, ret);
1216 goto err_register;
1217 }
1218 }
1219
Mark Brownb17e5462013-01-11 08:55:24 +09001220 if (arizona->pdata.micd_bias_start_time)
1221 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1222 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1223 arizona->pdata.micd_bias_start_time
1224 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1225
Mark Brown2e033db2013-01-21 17:36:33 +09001226 if (arizona->pdata.micd_rate)
1227 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1228 ARIZONA_MICD_RATE_MASK,
1229 arizona->pdata.micd_rate
1230 << ARIZONA_MICD_RATE_SHIFT);
1231
1232 if (arizona->pdata.micd_dbtime)
1233 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1234 ARIZONA_MICD_DBTIME_MASK,
1235 arizona->pdata.micd_dbtime
1236 << ARIZONA_MICD_DBTIME_SHIFT);
1237
Mark Brown6fed4d82013-04-01 22:03:06 +01001238 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1239
1240 if (arizona->pdata.num_micd_ranges) {
1241 info->micd_ranges = pdata->micd_ranges;
1242 info->num_micd_ranges = pdata->num_micd_ranges;
1243 } else {
1244 info->micd_ranges = micd_default_ranges;
1245 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1246 }
1247
1248 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1249 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1250 arizona->pdata.num_micd_ranges);
1251 }
1252
1253 if (info->num_micd_ranges > 1) {
1254 for (i = 1; i < info->num_micd_ranges; i++) {
1255 if (info->micd_ranges[i - 1].max >
1256 info->micd_ranges[i].max) {
1257 dev_err(arizona->dev,
1258 "MICD ranges must be sorted\n");
1259 ret = -EINVAL;
1260 goto err_input;
1261 }
1262 }
1263 }
1264
1265 /* Disable all buttons by default */
1266 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1267 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1268
1269 /* Set up all the buttons the user specified */
1270 for (i = 0; i < info->num_micd_ranges; i++) {
1271 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1272 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1273 break;
1274
1275 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1276 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1277 info->micd_ranges[i].max);
1278 ret = -EINVAL;
1279 goto err_input;
1280 }
1281
1282 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1283 arizona_micd_levels[j], i);
1284
1285 arizona_micd_set_level(arizona, i, j);
1286 input_set_capability(info->input, EV_KEY,
1287 info->micd_ranges[i].key);
1288
1289 /* Enable reporting of that range */
1290 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1291 1 << i, 1 << i);
1292 }
1293
1294 /* Set all the remaining keys to a maximum */
1295 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1296 arizona_micd_set_level(arizona, i, 0x3f);
1297
Mark Browndab63eb2013-01-11 08:55:36 +09001298 /*
Mark Brown92a49872013-01-11 08:55:39 +09001299 * If we have a clamp use it, activating in conjunction with
1300 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001301 */
1302 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001303 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001304 /* Put the GPIO into input mode with optional pull */
1305 val = 0xc101;
1306 if (arizona->pdata.jd_gpio5_nopull)
1307 val &= ~ARIZONA_GPN_PU;
1308
Mark Brown92a49872013-01-11 08:55:39 +09001309 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001310 val);
Mark Brown92a49872013-01-11 08:55:39 +09001311
1312 regmap_update_bits(arizona->regmap,
1313 ARIZONA_MICD_CLAMP_CONTROL,
1314 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1315 } else {
1316 regmap_update_bits(arizona->regmap,
1317 ARIZONA_MICD_CLAMP_CONTROL,
1318 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1319 }
1320
Mark Browndab63eb2013-01-11 08:55:36 +09001321 regmap_update_bits(arizona->regmap,
1322 ARIZONA_JACK_DETECT_DEBOUNCE,
1323 ARIZONA_MICD_CLAMP_DB,
1324 ARIZONA_MICD_CLAMP_DB);
1325 }
1326
Mark Brownf2c32a82012-06-24 12:09:45 +01001327 arizona_extcon_set_mode(info, 0);
1328
1329 pm_runtime_enable(&pdev->dev);
1330 pm_runtime_idle(&pdev->dev);
1331 pm_runtime_get_sync(&pdev->dev);
1332
Mark Brown92a49872013-01-11 08:55:39 +09001333 if (arizona->pdata.jd_gpio5) {
1334 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1335 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1336 } else {
1337 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1338 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1339 }
1340
1341 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001342 "JACKDET rise", arizona_jackdet, info);
1343 if (ret != 0) {
1344 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1345 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001346 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001347 }
1348
Mark Brown92a49872013-01-11 08:55:39 +09001349 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001350 if (ret != 0) {
1351 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1352 ret);
1353 goto err_rise;
1354 }
1355
Mark Brown92a49872013-01-11 08:55:39 +09001356 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001357 "JACKDET fall", arizona_jackdet, info);
1358 if (ret != 0) {
1359 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1360 goto err_rise_wake;
1361 }
1362
Mark Brown92a49872013-01-11 08:55:39 +09001363 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001364 if (ret != 0) {
1365 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1366 ret);
1367 goto err_fall;
1368 }
1369
1370 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1371 "MICDET", arizona_micdet, info);
1372 if (ret != 0) {
1373 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1374 goto err_fall_wake;
1375 }
1376
Mark Brown4f340332013-01-11 08:55:43 +09001377 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1378 "HPDET", arizona_hpdet_irq, info);
1379 if (ret != 0) {
1380 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1381 goto err_micdet;
1382 }
1383
Mark Brownf2c32a82012-06-24 12:09:45 +01001384 arizona_clk32k_enable(arizona);
1385 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1386 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1387 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1388 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1389
Mark Brownb8575a12012-09-07 17:01:15 +08001390 ret = regulator_allow_bypass(info->micvdd, true);
1391 if (ret != 0)
1392 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1393 ret);
1394
Mark Brownf2c32a82012-06-24 12:09:45 +01001395 pm_runtime_put(&pdev->dev);
1396
Mark Brown34efe4d2012-07-20 17:07:29 +01001397 ret = input_register_device(info->input);
1398 if (ret) {
1399 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001400 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001401 }
1402
Mark Brownf2c32a82012-06-24 12:09:45 +01001403 return 0;
1404
Mark Brown4f340332013-01-11 08:55:43 +09001405err_hpdet:
1406 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001407err_micdet:
1408 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001409err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001410 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001411err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001412 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001413err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001414 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001415err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001416 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001417err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001418err_register:
1419 pm_runtime_disable(&pdev->dev);
1420 extcon_dev_unregister(&info->edev);
1421err:
1422 return ret;
1423}
1424
Bill Pemberton93ed0322012-11-19 13:25:49 -05001425static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001426{
1427 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1428 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001429 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001430
1431 pm_runtime_disable(&pdev->dev);
1432
Mark Browndab63eb2013-01-11 08:55:36 +09001433 regmap_update_bits(arizona->regmap,
1434 ARIZONA_MICD_CLAMP_CONTROL,
1435 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1436
Mark Brown92a49872013-01-11 08:55:39 +09001437 if (arizona->pdata.jd_gpio5) {
1438 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1439 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1440 } else {
1441 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1442 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1443 }
1444
1445 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1446 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1447 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001448 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001449 arizona_free_irq(arizona, jack_irq_rise, info);
1450 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001451 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001452 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1453 ARIZONA_JD1_ENA, 0);
1454 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001455 extcon_dev_unregister(&info->edev);
1456
1457 return 0;
1458}
1459
1460static struct platform_driver arizona_extcon_driver = {
1461 .driver = {
1462 .name = "arizona-extcon",
1463 .owner = THIS_MODULE,
1464 },
1465 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001466 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001467};
1468
1469module_platform_driver(arizona_extcon_driver);
1470
1471MODULE_DESCRIPTION("Arizona Extcon driver");
1472MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1473MODULE_LICENSE("GPL");
1474MODULE_ALIAS("platform:extcon-arizona");