blob: 5775f055bd0213391627d8ebf47413dcd02b5098 [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
Mark Brown03409072013-02-12 13:00:31 +0000606 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900607
608done:
Mark Brown1eda6aa2013-01-11 08:55:54 +0900609 if (id_gpio)
610 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900611
612 /* Revert back to MICDET mode */
613 regmap_update_bits(arizona->regmap,
614 ARIZONA_ACCESSORY_DETECT_MODE_1,
615 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
616
617 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000618 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900619 arizona_start_mic(info);
620
621 if (info->hpdet_active) {
622 pm_runtime_put_autosuspend(info->dev);
623 info->hpdet_active = false;
624 }
625
Mark Brownbf14ee52013-02-05 20:20:17 +0000626 info->hpdet_done = true;
627
Mark Brown4f340332013-01-11 08:55:43 +0900628out:
629 mutex_unlock(&info->lock);
630
631 return IRQ_HANDLED;
632}
633
634static void arizona_identify_headphone(struct arizona_extcon_info *info)
635{
636 struct arizona *arizona = info->arizona;
637 int ret;
638
Mark Brownbf14ee52013-02-05 20:20:17 +0000639 if (info->hpdet_done)
640 return;
641
Mark Brown4f340332013-01-11 08:55:43 +0900642 dev_dbg(arizona->dev, "Starting HPDET\n");
643
644 /* Make sure we keep the device enabled during the measurement */
645 pm_runtime_get(info->dev);
646
647 info->hpdet_active = true;
648
649 if (info->mic)
650 arizona_stop_mic(info);
651
Mark Brown03409072013-02-12 13:00:31 +0000652 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900653
654 ret = regmap_update_bits(arizona->regmap,
655 ARIZONA_ACCESSORY_DETECT_MODE_1,
656 ARIZONA_ACCDET_MODE_MASK,
657 ARIZONA_ACCDET_MODE_HPL);
658 if (ret != 0) {
659 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
660 goto err;
661 }
662
663 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
664 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
665 if (ret != 0) {
666 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
667 ret);
668 goto err;
669 }
670
671 return;
672
673err:
674 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
675 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
676
677 /* Just report headphone */
678 ret = extcon_update_state(&info->edev,
679 1 << ARIZONA_CABLE_HEADPHONE,
680 1 << ARIZONA_CABLE_HEADPHONE);
681 if (ret != 0)
682 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
683
684 if (info->mic)
685 arizona_start_mic(info);
686
687 info->hpdet_active = false;
688}
Mark Browndd235ee2013-01-11 08:55:51 +0900689
690static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
691{
692 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000693 int hp_reading = 32;
694 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900695 int ret;
696
697 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
698
699 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000700 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900701
702 info->hpdet_active = true;
703
Mark Brown03409072013-02-12 13:00:31 +0000704 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900705
706 ret = regmap_update_bits(arizona->regmap,
707 ARIZONA_ACCESSORY_DETECT_MODE_1,
708 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
709 info->micd_modes[0].src |
710 ARIZONA_ACCDET_MODE_HPL);
711 if (ret != 0) {
712 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
713 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900714 }
715
Mark Brown9c2ba272013-02-25 23:42:31 +0000716 if (arizona->pdata.hpdet_acc_id_line) {
717 ret = regmap_update_bits(arizona->regmap,
718 ARIZONA_HEADPHONE_DETECT_1,
719 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
720 if (ret != 0) {
721 dev_err(arizona->dev,
722 "Can't start HPDETL measurement: %d\n",
723 ret);
724 goto err;
725 }
726 } else {
727 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900728 }
729
730 return;
731
732err:
733 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
734 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
735
736 /* Just report headphone */
737 ret = extcon_update_state(&info->edev,
738 1 << ARIZONA_CABLE_HEADPHONE,
739 1 << ARIZONA_CABLE_HEADPHONE);
740 if (ret != 0)
741 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
742
Mark Brown4f340332013-01-11 08:55:43 +0900743 info->hpdet_active = false;
744}
745
Mark Brown939c5672013-04-01 19:17:34 +0100746static void arizona_micd_timeout_work(struct work_struct *work)
747{
748 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900749 struct arizona_extcon_info,
750 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100751
752 mutex_lock(&info->lock);
753
754 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
755 arizona_identify_headphone(info);
756
757 info->detecting = false;
758
759 arizona_stop_mic(info);
760
761 mutex_unlock(&info->lock);
762}
763
Mark Browncd59e792013-04-01 19:21:48 +0100764static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100765{
Mark Browncd59e792013-04-01 19:21:48 +0100766 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900767 struct arizona_extcon_info,
768 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100769 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100770 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100771 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100772
Mark Brown939c5672013-04-01 19:17:34 +0100773 cancel_delayed_work_sync(&info->micd_timeout_work);
774
Mark Brownf2c32a82012-06-24 12:09:45 +0100775 mutex_lock(&info->lock);
776
Charles Keepaxffae24f2013-11-14 16:18:21 +0000777 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100778 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
779 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900780 dev_err(arizona->dev,
781 "Failed to read MICDET: %d\n", ret);
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 }
785
786 dev_dbg(arizona->dev, "MICDET: %x\n", val);
787
788 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900789 dev_warn(arizona->dev,
790 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100791 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100792 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100793 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100794 }
795
Charles Keepaxffae24f2013-11-14 16:18:21 +0000796 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100797 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100798 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100799 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100800 }
801
802 /* Due to jack detect this should never happen */
803 if (!(val & ARIZONA_MICD_STS)) {
804 dev_warn(arizona->dev, "Detected open circuit\n");
805 info->detecting = false;
806 goto handled;
807 }
808
809 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000810 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900811 arizona_identify_headphone(info);
812
Mark Brown325c6422012-06-28 13:08:30 +0100813 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900814 1 << ARIZONA_CABLE_MICROPHONE,
815 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100816
817 if (ret != 0)
818 dev_err(arizona->dev, "Headset report failed: %d\n",
819 ret);
820
Mark Brownbbbd46e2013-01-10 19:38:43 +0000821 /* Don't need to regulate for button detection */
822 ret = regulator_allow_bypass(info->micvdd, false);
823 if (ret != 0) {
824 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
825 ret);
826 }
827
Mark Brownf2c32a82012-06-24 12:09:45 +0100828 info->mic = true;
829 info->detecting = false;
830 goto handled;
831 }
832
833 /* If we detected a lower impedence during initial startup
834 * then we probably have the wrong polarity, flip it. Don't
835 * do this for the lowest impedences to speed up detection of
836 * plain headphones. If both polarities report a low
837 * impedence then give up and report headphones.
838 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000839 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800840 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900841 dev_dbg(arizona->dev, "Detected HP/line\n");
842 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100843
Mark Brown4f340332013-01-11 08:55:43 +0900844 info->detecting = false;
845
846 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100847 } else {
848 info->micd_mode++;
849 if (info->micd_mode == info->micd_num_modes)
850 info->micd_mode = 0;
851 arizona_extcon_set_mode(info, info->micd_mode);
852
853 info->jack_flips++;
854 }
855
856 goto handled;
857 }
858
859 /*
860 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100861 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100862 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000863 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100864 if (info->mic) {
865 dev_dbg(arizona->dev, "Mic button detected\n");
866
Mark Brown34efe4d2012-07-20 17:07:29 +0100867 lvl = val & ARIZONA_MICD_LVL_MASK;
868 lvl >>= ARIZONA_MICD_LVL_SHIFT;
869
Mark Brown41a57852013-04-01 19:18:18 +0100870 for (i = 0; i < info->num_micd_ranges; i++)
871 input_report_key(info->input,
872 info->micd_ranges[i].key, 0);
873
Mark Brown6fed4d82013-04-01 22:03:06 +0100874 WARN_ON(!lvl);
875 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
876 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
877 key = info->micd_ranges[ffs(lvl) - 1].key;
878 input_report_key(info->input, key, 1);
879 input_sync(info->input);
880 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100881
Mark Brownf2c32a82012-06-24 12:09:45 +0100882 } else if (info->detecting) {
883 dev_dbg(arizona->dev, "Headphone detected\n");
884 info->detecting = false;
885 arizona_stop_mic(info);
886
Mark Brown4f340332013-01-11 08:55:43 +0900887 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100888 } else {
889 dev_warn(arizona->dev, "Button with no mic: %x\n",
890 val);
891 }
892 } else {
893 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100894 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100895 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100896 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100897 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000898 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100899 }
900
901handled:
Mark Brown939c5672013-04-01 19:17:34 +0100902 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100903 queue_delayed_work(system_power_efficient_wq,
904 &info->micd_timeout_work,
905 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100906
Mark Brownf2c32a82012-06-24 12:09:45 +0100907 pm_runtime_mark_last_busy(info->dev);
908 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100909}
910
911static irqreturn_t arizona_micdet(int irq, void *data)
912{
913 struct arizona_extcon_info *info = data;
914 struct arizona *arizona = info->arizona;
915 int debounce = arizona->pdata.micd_detect_debounce;
916
917 cancel_delayed_work_sync(&info->micd_detect_work);
918 cancel_delayed_work_sync(&info->micd_timeout_work);
919
920 mutex_lock(&info->lock);
921 if (!info->detecting)
922 debounce = 0;
923 mutex_unlock(&info->lock);
924
925 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100926 queue_delayed_work(system_power_efficient_wq,
927 &info->micd_detect_work,
928 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100929 else
930 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100931
932 return IRQ_HANDLED;
933}
934
Mark Brown0e27bd32013-02-05 21:00:15 +0000935static void arizona_hpdet_work(struct work_struct *work)
936{
937 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900938 struct arizona_extcon_info,
939 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000940
941 mutex_lock(&info->lock);
942 arizona_start_hpdet_acc_id(info);
943 mutex_unlock(&info->lock);
944}
945
Mark Brownf2c32a82012-06-24 12:09:45 +0100946static irqreturn_t arizona_jackdet(int irq, void *data)
947{
948 struct arizona_extcon_info *info = data;
949 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900950 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100951 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100952 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100953
Mark Brown939c5672013-04-01 19:17:34 +0100954 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
955 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100956
Mark Browna3e20782013-04-01 19:05:27 +0100957 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000958
Mark Brownf2c32a82012-06-24 12:09:45 +0100959 mutex_lock(&info->lock);
960
Mark Brown92a49872013-01-11 08:55:39 +0900961 if (arizona->pdata.jd_gpio5) {
962 mask = ARIZONA_MICD_CLAMP_STS;
963 present = 0;
964 } else {
965 mask = ARIZONA_JD1_STS;
966 present = ARIZONA_JD1_STS;
967 }
968
Mark Brownf2c32a82012-06-24 12:09:45 +0100969 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
970 if (ret != 0) {
971 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
972 ret);
973 mutex_unlock(&info->lock);
974 pm_runtime_put_autosuspend(info->dev);
975 return IRQ_NONE;
976 }
977
Mark Browna3e20782013-04-01 19:05:27 +0100978 val &= mask;
979 if (val == info->last_jackdet) {
980 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +0100981 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100982 queue_delayed_work(system_power_efficient_wq,
983 &info->hpdet_work,
984 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +0100985
Chanwoo Choic2275d22013-08-23 10:21:37 +0900986 if (cancelled_mic) {
987 int micd_timeout = info->micd_timeout;
988
Mark Browndf9a5ab2013-07-18 22:42:22 +0100989 queue_delayed_work(system_power_efficient_wq,
990 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900991 msecs_to_jiffies(micd_timeout));
992 }
Mark Brown939c5672013-04-01 19:17:34 +0100993
Mark Browna3e20782013-04-01 19:05:27 +0100994 goto out;
995 }
996 info->last_jackdet = val;
997
998 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100999 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +01001000 ret = extcon_set_cable_state_(&info->edev,
1001 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001002
1003 if (ret != 0)
1004 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1005 ret);
1006
Mark Browndd235ee2013-01-11 08:55:51 +09001007 if (!arizona->pdata.hpdet_acc_id) {
1008 info->detecting = true;
1009 info->mic = false;
1010 info->jack_flips = 0;
1011
1012 arizona_start_mic(info);
1013 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001014 queue_delayed_work(system_power_efficient_wq,
1015 &info->hpdet_work,
1016 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001017 }
Mark Brown4e616872013-01-15 22:09:20 +09001018
1019 regmap_update_bits(arizona->regmap,
1020 ARIZONA_JACK_DETECT_DEBOUNCE,
1021 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001022 } else {
1023 dev_dbg(arizona->dev, "Detected jack removal\n");
1024
1025 arizona_stop_mic(info);
1026
Mark Browndd235ee2013-01-11 08:55:51 +09001027 info->num_hpdet_res = 0;
1028 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1029 info->hpdet_res[i] = 0;
1030 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001031 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001032 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001033
Mark Brown6fed4d82013-04-01 22:03:06 +01001034 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001035 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001036 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001037 input_sync(info->input);
1038
Mark Brownf2c32a82012-06-24 12:09:45 +01001039 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
1040 if (ret != 0)
1041 dev_err(arizona->dev, "Removal report failed: %d\n",
1042 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001043
1044 regmap_update_bits(arizona->regmap,
1045 ARIZONA_JACK_DETECT_DEBOUNCE,
1046 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1047 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001048 }
1049
Mark Brown7abd4e22013-04-01 19:25:55 +01001050 if (arizona->pdata.micd_timeout)
1051 info->micd_timeout = arizona->pdata.micd_timeout;
1052 else
1053 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1054
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001055out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001056 /* Clear trig_sts to make sure DCVDD is not forced up */
1057 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1058 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1059 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1060 ARIZONA_JD1_FALL_TRIG_STS |
1061 ARIZONA_JD1_RISE_TRIG_STS);
1062
Mark Brownf2c32a82012-06-24 12:09:45 +01001063 mutex_unlock(&info->lock);
1064
1065 pm_runtime_mark_last_busy(info->dev);
1066 pm_runtime_put_autosuspend(info->dev);
1067
1068 return IRQ_HANDLED;
1069}
1070
Mark Brown6fed4d82013-04-01 22:03:06 +01001071/* Map a level onto a slot in the register bank */
1072static void arizona_micd_set_level(struct arizona *arizona, int index,
1073 unsigned int level)
1074{
1075 int reg;
1076 unsigned int mask;
1077
1078 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1079
1080 if (!(index % 2)) {
1081 mask = 0x3f00;
1082 level <<= 8;
1083 } else {
1084 mask = 0x3f;
1085 }
1086
1087 /* Program the level itself */
1088 regmap_update_bits(arizona->regmap, reg, mask, level);
1089}
1090
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001091static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001092{
1093 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001094 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001095 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001096 unsigned int val;
Mark Brown92a49872013-01-11 08:55:39 +09001097 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001098 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001099
Mark Brownbbbd46e2013-01-10 19:38:43 +00001100 if (!arizona->dapm || !arizona->dapm->card)
1101 return -EPROBE_DEFER;
1102
Mark Brownf2c32a82012-06-24 12:09:45 +01001103 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1104 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001105 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +01001106 ret = -ENOMEM;
1107 goto err;
1108 }
1109
1110 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1111 if (IS_ERR(info->micvdd)) {
1112 ret = PTR_ERR(info->micvdd);
1113 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
1114 goto err;
1115 }
1116
1117 mutex_init(&info->lock);
1118 info->arizona = arizona;
1119 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001120 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001121 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001122 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001123 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001124 platform_set_drvdata(pdev, info);
1125
1126 switch (arizona->type) {
1127 case WM5102:
1128 switch (arizona->rev) {
1129 case 0:
1130 info->micd_reva = true;
1131 break;
1132 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001133 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001134 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001135 break;
1136 }
1137 break;
1138 default:
1139 break;
1140 }
1141
1142 info->edev.name = "Headset Jack";
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001143 info->edev.dev.parent = arizona->dev;
Mark Brownf2c32a82012-06-24 12:09:45 +01001144 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001145
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001146 ret = extcon_dev_register(&info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001147 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001148 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001149 ret);
1150 goto err;
1151 }
1152
Mark Brown6fed4d82013-04-01 22:03:06 +01001153 info->input = devm_input_allocate_device(&pdev->dev);
1154 if (!info->input) {
1155 dev_err(arizona->dev, "Can't allocate input dev\n");
1156 ret = -ENOMEM;
1157 goto err_register;
1158 }
1159
1160 info->input->name = "Headset";
1161 info->input->phys = "arizona/extcon";
1162 info->input->dev.parent = &pdev->dev;
1163
Mark Brownf2c32a82012-06-24 12:09:45 +01001164 if (pdata->num_micd_configs) {
1165 info->micd_modes = pdata->micd_configs;
1166 info->micd_num_modes = pdata->num_micd_configs;
1167 } else {
1168 info->micd_modes = micd_default_modes;
1169 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1170 }
1171
1172 if (arizona->pdata.micd_pol_gpio > 0) {
1173 if (info->micd_modes[0].gpio)
1174 mode = GPIOF_OUT_INIT_HIGH;
1175 else
1176 mode = GPIOF_OUT_INIT_LOW;
1177
1178 ret = devm_gpio_request_one(&pdev->dev,
1179 arizona->pdata.micd_pol_gpio,
1180 mode,
1181 "MICD polarity");
1182 if (ret != 0) {
1183 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1184 arizona->pdata.micd_pol_gpio, ret);
1185 goto err_register;
1186 }
1187 }
1188
Mark Brown1eda6aa2013-01-11 08:55:54 +09001189 if (arizona->pdata.hpdet_id_gpio > 0) {
1190 ret = devm_gpio_request_one(&pdev->dev,
1191 arizona->pdata.hpdet_id_gpio,
1192 GPIOF_OUT_INIT_LOW,
1193 "HPDET");
1194 if (ret != 0) {
1195 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1196 arizona->pdata.hpdet_id_gpio, ret);
1197 goto err_register;
1198 }
1199 }
1200
Mark Brownb17e5462013-01-11 08:55:24 +09001201 if (arizona->pdata.micd_bias_start_time)
1202 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1203 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1204 arizona->pdata.micd_bias_start_time
1205 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1206
Mark Brown2e033db2013-01-21 17:36:33 +09001207 if (arizona->pdata.micd_rate)
1208 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1209 ARIZONA_MICD_RATE_MASK,
1210 arizona->pdata.micd_rate
1211 << ARIZONA_MICD_RATE_SHIFT);
1212
1213 if (arizona->pdata.micd_dbtime)
1214 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1215 ARIZONA_MICD_DBTIME_MASK,
1216 arizona->pdata.micd_dbtime
1217 << ARIZONA_MICD_DBTIME_SHIFT);
1218
Mark Brown6fed4d82013-04-01 22:03:06 +01001219 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1220
1221 if (arizona->pdata.num_micd_ranges) {
1222 info->micd_ranges = pdata->micd_ranges;
1223 info->num_micd_ranges = pdata->num_micd_ranges;
1224 } else {
1225 info->micd_ranges = micd_default_ranges;
1226 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1227 }
1228
1229 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1230 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1231 arizona->pdata.num_micd_ranges);
1232 }
1233
1234 if (info->num_micd_ranges > 1) {
1235 for (i = 1; i < info->num_micd_ranges; i++) {
1236 if (info->micd_ranges[i - 1].max >
1237 info->micd_ranges[i].max) {
1238 dev_err(arizona->dev,
1239 "MICD ranges must be sorted\n");
1240 ret = -EINVAL;
1241 goto err_input;
1242 }
1243 }
1244 }
1245
1246 /* Disable all buttons by default */
1247 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1248 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1249
1250 /* Set up all the buttons the user specified */
1251 for (i = 0; i < info->num_micd_ranges; i++) {
1252 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1253 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1254 break;
1255
1256 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1257 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1258 info->micd_ranges[i].max);
1259 ret = -EINVAL;
1260 goto err_input;
1261 }
1262
1263 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1264 arizona_micd_levels[j], i);
1265
1266 arizona_micd_set_level(arizona, i, j);
1267 input_set_capability(info->input, EV_KEY,
1268 info->micd_ranges[i].key);
1269
1270 /* Enable reporting of that range */
1271 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1272 1 << i, 1 << i);
1273 }
1274
1275 /* Set all the remaining keys to a maximum */
1276 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1277 arizona_micd_set_level(arizona, i, 0x3f);
1278
Mark Browndab63eb2013-01-11 08:55:36 +09001279 /*
Mark Brown92a49872013-01-11 08:55:39 +09001280 * If we have a clamp use it, activating in conjunction with
1281 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001282 */
1283 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001284 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001285 /* Put the GPIO into input mode with optional pull */
1286 val = 0xc101;
1287 if (arizona->pdata.jd_gpio5_nopull)
1288 val &= ~ARIZONA_GPN_PU;
1289
Mark Brown92a49872013-01-11 08:55:39 +09001290 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001291 val);
Mark Brown92a49872013-01-11 08:55:39 +09001292
1293 regmap_update_bits(arizona->regmap,
1294 ARIZONA_MICD_CLAMP_CONTROL,
1295 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1296 } else {
1297 regmap_update_bits(arizona->regmap,
1298 ARIZONA_MICD_CLAMP_CONTROL,
1299 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1300 }
1301
Mark Browndab63eb2013-01-11 08:55:36 +09001302 regmap_update_bits(arizona->regmap,
1303 ARIZONA_JACK_DETECT_DEBOUNCE,
1304 ARIZONA_MICD_CLAMP_DB,
1305 ARIZONA_MICD_CLAMP_DB);
1306 }
1307
Mark Brownf2c32a82012-06-24 12:09:45 +01001308 arizona_extcon_set_mode(info, 0);
1309
1310 pm_runtime_enable(&pdev->dev);
1311 pm_runtime_idle(&pdev->dev);
1312 pm_runtime_get_sync(&pdev->dev);
1313
Mark Brown92a49872013-01-11 08:55:39 +09001314 if (arizona->pdata.jd_gpio5) {
1315 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1316 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1317 } else {
1318 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1319 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1320 }
1321
1322 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001323 "JACKDET rise", arizona_jackdet, info);
1324 if (ret != 0) {
1325 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1326 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001327 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001328 }
1329
Mark Brown92a49872013-01-11 08:55:39 +09001330 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001331 if (ret != 0) {
1332 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1333 ret);
1334 goto err_rise;
1335 }
1336
Mark Brown92a49872013-01-11 08:55:39 +09001337 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001338 "JACKDET fall", arizona_jackdet, info);
1339 if (ret != 0) {
1340 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1341 goto err_rise_wake;
1342 }
1343
Mark Brown92a49872013-01-11 08:55:39 +09001344 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001345 if (ret != 0) {
1346 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1347 ret);
1348 goto err_fall;
1349 }
1350
1351 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1352 "MICDET", arizona_micdet, info);
1353 if (ret != 0) {
1354 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1355 goto err_fall_wake;
1356 }
1357
Mark Brown4f340332013-01-11 08:55:43 +09001358 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1359 "HPDET", arizona_hpdet_irq, info);
1360 if (ret != 0) {
1361 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1362 goto err_micdet;
1363 }
1364
Mark Brownf2c32a82012-06-24 12:09:45 +01001365 arizona_clk32k_enable(arizona);
1366 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1367 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1368 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1369 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1370
Mark Brownb8575a12012-09-07 17:01:15 +08001371 ret = regulator_allow_bypass(info->micvdd, true);
1372 if (ret != 0)
1373 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1374 ret);
1375
Mark Brownf2c32a82012-06-24 12:09:45 +01001376 pm_runtime_put(&pdev->dev);
1377
Mark Brown34efe4d2012-07-20 17:07:29 +01001378 ret = input_register_device(info->input);
1379 if (ret) {
1380 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001381 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001382 }
1383
Mark Brownf2c32a82012-06-24 12:09:45 +01001384 return 0;
1385
Mark Brown4f340332013-01-11 08:55:43 +09001386err_hpdet:
1387 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001388err_micdet:
1389 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001390err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001391 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001392err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001393 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001394err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001395 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001396err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001397 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001398err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001399err_register:
1400 pm_runtime_disable(&pdev->dev);
1401 extcon_dev_unregister(&info->edev);
1402err:
1403 return ret;
1404}
1405
Bill Pemberton93ed0322012-11-19 13:25:49 -05001406static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001407{
1408 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1409 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001410 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001411
1412 pm_runtime_disable(&pdev->dev);
1413
Mark Browndab63eb2013-01-11 08:55:36 +09001414 regmap_update_bits(arizona->regmap,
1415 ARIZONA_MICD_CLAMP_CONTROL,
1416 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1417
Mark Brown92a49872013-01-11 08:55:39 +09001418 if (arizona->pdata.jd_gpio5) {
1419 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1420 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1421 } else {
1422 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1423 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1424 }
1425
1426 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1427 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1428 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001429 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001430 arizona_free_irq(arizona, jack_irq_rise, info);
1431 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001432 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001433 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1434 ARIZONA_JD1_ENA, 0);
1435 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001436 extcon_dev_unregister(&info->edev);
1437
1438 return 0;
1439}
1440
1441static struct platform_driver arizona_extcon_driver = {
1442 .driver = {
1443 .name = "arizona-extcon",
1444 .owner = THIS_MODULE,
1445 },
1446 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001447 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001448};
1449
1450module_platform_driver(arizona_extcon_driver);
1451
1452MODULE_DESCRIPTION("Arizona Extcon driver");
1453MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1454MODULE_LICENSE("GPL");
1455MODULE_ALIAS("platform:extcon-arizona");