blob: c20602f601ee22732635aa3fa04fe94e44ed6020 [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;
Charles Keepax77438612013-11-14 16:18:25 +0000438 /* Convert to ohms, the value is in 0.5 ohm increments */
439 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900440
441 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
442 &range);
443 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
444 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
445
Charles Keepax91414612013-11-14 16:18:24 +0000446 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900447 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
448 (val >= arizona_hpdet_c_ranges[range].max)) {
449 range++;
450 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
451 arizona_hpdet_c_ranges[range].min,
452 arizona_hpdet_c_ranges[range].max);
453 regmap_update_bits(arizona->regmap,
454 ARIZONA_HEADPHONE_DETECT_1,
455 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
456 range <<
457 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
458 return -EAGAIN;
459 }
Charles Keepax91414612013-11-14 16:18:24 +0000460
461 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
462 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
463 arizona_hpdet_c_ranges[range].min);
464 val = arizona_hpdet_c_ranges[range].min;
465 }
Mark Brown4f340332013-01-11 08:55:43 +0900466 }
467
468 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
469 return val;
470}
471
Mark Brown9c2ba272013-02-25 23:42:31 +0000472static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
473 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900474{
475 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900476 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900477
478 /*
479 * If we're using HPDET for accessory identification we need
480 * to take multiple measurements, step through them in sequence.
481 */
482 if (arizona->pdata.hpdet_acc_id) {
483 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900484
485 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000486 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900487 dev_dbg(arizona->dev, "Measuring mic\n");
488
489 regmap_update_bits(arizona->regmap,
490 ARIZONA_ACCESSORY_DETECT_MODE_1,
491 ARIZONA_ACCDET_MODE_MASK |
492 ARIZONA_ACCDET_SRC,
493 ARIZONA_ACCDET_MODE_HPR |
494 info->micd_modes[0].src);
495
496 gpio_set_value_cansleep(id_gpio, 1);
497
Mark Browndd235ee2013-01-11 08:55:51 +0900498 regmap_update_bits(arizona->regmap,
499 ARIZONA_HEADPHONE_DETECT_1,
500 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
501 return -EAGAIN;
502 }
503
504 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000505 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
506 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000507
508 /* Take the headphone impedance for the main report */
509 *reading = info->hpdet_res[0];
510
Mark Brown9dd5e532013-04-01 19:09:45 +0100511 /* Sometimes we get false readings due to slow insert */
512 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
513 dev_dbg(arizona->dev, "Retrying high impedance\n");
514 info->num_hpdet_res = 0;
515 info->hpdet_retried = true;
516 arizona_start_hpdet_acc_id(info);
517 pm_runtime_put(info->dev);
518 return -EAGAIN;
519 }
520
Mark Brown1eda6aa2013-01-11 08:55:54 +0900521 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530522 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900523 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000524 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900525 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000526 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000527 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900528 } else {
529 dev_dbg(arizona->dev, "Detected headphone\n");
530 }
531
532 /* Make sure everything is reset back to the real polarity */
533 regmap_update_bits(arizona->regmap,
534 ARIZONA_ACCESSORY_DETECT_MODE_1,
535 ARIZONA_ACCDET_SRC,
536 info->micd_modes[0].src);
537 }
538
539 return 0;
540}
541
Mark Brown4f340332013-01-11 08:55:43 +0900542static irqreturn_t arizona_hpdet_irq(int irq, void *data)
543{
544 struct arizona_extcon_info *info = data;
545 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900546 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900547 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900548 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000549 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900550
551 mutex_lock(&info->lock);
552
553 /* If we got a spurious IRQ for some reason then ignore it */
554 if (!info->hpdet_active) {
555 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
556 mutex_unlock(&info->lock);
557 return IRQ_NONE;
558 }
559
560 /* If the cable was removed while measuring ignore the result */
561 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
562 if (ret < 0) {
563 dev_err(arizona->dev, "Failed to check cable state: %d\n",
564 ret);
565 goto out;
566 } else if (!ret) {
567 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
568 goto done;
569 }
570
571 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900572 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900573 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900574 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900575 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900576 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900577
578 /* Reset back to starting range */
579 regmap_update_bits(arizona->regmap,
580 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900581 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
582 0);
583
Mark Brown9c2ba272013-02-25 23:42:31 +0000584 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900585 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900586 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900587 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900588 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900589
590 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900591 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900592 report = ARIZONA_CABLE_LINEOUT;
593 else
594 report = ARIZONA_CABLE_HEADPHONE;
595
596 ret = extcon_set_cable_state_(&info->edev, report, true);
597 if (ret != 0)
598 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
599 ret);
600
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000601done:
602 /* Reset back to starting range */
603 regmap_update_bits(arizona->regmap,
604 ARIZONA_HEADPHONE_DETECT_1,
605 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
606 0);
607
Mark Brown03409072013-02-12 13:00:31 +0000608 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900609
Mark Brown1eda6aa2013-01-11 08:55:54 +0900610 if (id_gpio)
611 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900612
613 /* Revert back to MICDET mode */
614 regmap_update_bits(arizona->regmap,
615 ARIZONA_ACCESSORY_DETECT_MODE_1,
616 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
617
618 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000619 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900620 arizona_start_mic(info);
621
622 if (info->hpdet_active) {
623 pm_runtime_put_autosuspend(info->dev);
624 info->hpdet_active = false;
625 }
626
Mark Brownbf14ee52013-02-05 20:20:17 +0000627 info->hpdet_done = true;
628
Mark Brown4f340332013-01-11 08:55:43 +0900629out:
630 mutex_unlock(&info->lock);
631
632 return IRQ_HANDLED;
633}
634
635static void arizona_identify_headphone(struct arizona_extcon_info *info)
636{
637 struct arizona *arizona = info->arizona;
638 int ret;
639
Mark Brownbf14ee52013-02-05 20:20:17 +0000640 if (info->hpdet_done)
641 return;
642
Mark Brown4f340332013-01-11 08:55:43 +0900643 dev_dbg(arizona->dev, "Starting HPDET\n");
644
645 /* Make sure we keep the device enabled during the measurement */
646 pm_runtime_get(info->dev);
647
648 info->hpdet_active = true;
649
650 if (info->mic)
651 arizona_stop_mic(info);
652
Mark Brown03409072013-02-12 13:00:31 +0000653 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900654
655 ret = regmap_update_bits(arizona->regmap,
656 ARIZONA_ACCESSORY_DETECT_MODE_1,
657 ARIZONA_ACCDET_MODE_MASK,
658 ARIZONA_ACCDET_MODE_HPL);
659 if (ret != 0) {
660 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
661 goto err;
662 }
663
664 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
665 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
666 if (ret != 0) {
667 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
668 ret);
669 goto err;
670 }
671
672 return;
673
674err:
675 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
676 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
677
678 /* Just report headphone */
679 ret = extcon_update_state(&info->edev,
680 1 << ARIZONA_CABLE_HEADPHONE,
681 1 << ARIZONA_CABLE_HEADPHONE);
682 if (ret != 0)
683 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
684
685 if (info->mic)
686 arizona_start_mic(info);
687
688 info->hpdet_active = false;
689}
Mark Browndd235ee2013-01-11 08:55:51 +0900690
691static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
692{
693 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000694 int hp_reading = 32;
695 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900696 int ret;
697
698 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
699
700 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000701 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900702
703 info->hpdet_active = true;
704
Mark Brown03409072013-02-12 13:00:31 +0000705 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900706
707 ret = regmap_update_bits(arizona->regmap,
708 ARIZONA_ACCESSORY_DETECT_MODE_1,
709 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
710 info->micd_modes[0].src |
711 ARIZONA_ACCDET_MODE_HPL);
712 if (ret != 0) {
713 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
714 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900715 }
716
Mark Brown9c2ba272013-02-25 23:42:31 +0000717 if (arizona->pdata.hpdet_acc_id_line) {
718 ret = regmap_update_bits(arizona->regmap,
719 ARIZONA_HEADPHONE_DETECT_1,
720 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
721 if (ret != 0) {
722 dev_err(arizona->dev,
723 "Can't start HPDETL measurement: %d\n",
724 ret);
725 goto err;
726 }
727 } else {
728 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900729 }
730
731 return;
732
733err:
734 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
735 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
736
737 /* Just report headphone */
738 ret = extcon_update_state(&info->edev,
739 1 << ARIZONA_CABLE_HEADPHONE,
740 1 << ARIZONA_CABLE_HEADPHONE);
741 if (ret != 0)
742 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
743
Mark Brown4f340332013-01-11 08:55:43 +0900744 info->hpdet_active = false;
745}
746
Mark Brown939c5672013-04-01 19:17:34 +0100747static void arizona_micd_timeout_work(struct work_struct *work)
748{
749 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900750 struct arizona_extcon_info,
751 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100752
753 mutex_lock(&info->lock);
754
755 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
756 arizona_identify_headphone(info);
757
758 info->detecting = false;
759
760 arizona_stop_mic(info);
761
762 mutex_unlock(&info->lock);
763}
764
Mark Browncd59e792013-04-01 19:21:48 +0100765static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100766{
Mark Browncd59e792013-04-01 19:21:48 +0100767 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900768 struct arizona_extcon_info,
769 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100770 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100771 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100772 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100773
Mark Brown939c5672013-04-01 19:17:34 +0100774 cancel_delayed_work_sync(&info->micd_timeout_work);
775
Mark Brownf2c32a82012-06-24 12:09:45 +0100776 mutex_lock(&info->lock);
777
Charles Keepax31a847e2013-11-14 16:18:23 +0000778 /* If the cable was removed while measuring ignore the result */
779 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
780 if (ret < 0) {
781 dev_err(arizona->dev, "Failed to check cable state: %d\n",
782 ret);
783 mutex_unlock(&info->lock);
784 return;
785 } else if (!ret) {
786 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
787 mutex_unlock(&info->lock);
788 return;
789 }
790
Charles Keepaxffae24f2013-11-14 16:18:21 +0000791 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100792 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
793 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900794 dev_err(arizona->dev,
795 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100796 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100797 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100798 }
799
800 dev_dbg(arizona->dev, "MICDET: %x\n", val);
801
802 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900803 dev_warn(arizona->dev,
804 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100805 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100806 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100807 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100808 }
809
Charles Keepaxffae24f2013-11-14 16:18:21 +0000810 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100811 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100812 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100813 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100814 }
815
816 /* Due to jack detect this should never happen */
817 if (!(val & ARIZONA_MICD_STS)) {
818 dev_warn(arizona->dev, "Detected open circuit\n");
819 info->detecting = false;
820 goto handled;
821 }
822
823 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000824 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900825 arizona_identify_headphone(info);
826
Mark Brown325c6422012-06-28 13:08:30 +0100827 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900828 1 << ARIZONA_CABLE_MICROPHONE,
829 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100830
831 if (ret != 0)
832 dev_err(arizona->dev, "Headset report failed: %d\n",
833 ret);
834
Mark Brownbbbd46e2013-01-10 19:38:43 +0000835 /* Don't need to regulate for button detection */
836 ret = regulator_allow_bypass(info->micvdd, false);
837 if (ret != 0) {
838 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
839 ret);
840 }
841
Mark Brownf2c32a82012-06-24 12:09:45 +0100842 info->mic = true;
843 info->detecting = false;
844 goto handled;
845 }
846
847 /* If we detected a lower impedence during initial startup
848 * then we probably have the wrong polarity, flip it. Don't
849 * do this for the lowest impedences to speed up detection of
850 * plain headphones. If both polarities report a low
851 * impedence then give up and report headphones.
852 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000853 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800854 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900855 dev_dbg(arizona->dev, "Detected HP/line\n");
856 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100857
Mark Brown4f340332013-01-11 08:55:43 +0900858 info->detecting = false;
859
860 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100861 } else {
862 info->micd_mode++;
863 if (info->micd_mode == info->micd_num_modes)
864 info->micd_mode = 0;
865 arizona_extcon_set_mode(info, info->micd_mode);
866
867 info->jack_flips++;
868 }
869
870 goto handled;
871 }
872
873 /*
874 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100875 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100876 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000877 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100878 if (info->mic) {
879 dev_dbg(arizona->dev, "Mic button detected\n");
880
Mark Brown34efe4d2012-07-20 17:07:29 +0100881 lvl = val & ARIZONA_MICD_LVL_MASK;
882 lvl >>= ARIZONA_MICD_LVL_SHIFT;
883
Mark Brown41a57852013-04-01 19:18:18 +0100884 for (i = 0; i < info->num_micd_ranges; i++)
885 input_report_key(info->input,
886 info->micd_ranges[i].key, 0);
887
Mark Brown6fed4d82013-04-01 22:03:06 +0100888 WARN_ON(!lvl);
889 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
890 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
891 key = info->micd_ranges[ffs(lvl) - 1].key;
892 input_report_key(info->input, key, 1);
893 input_sync(info->input);
894 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100895
Mark Brownf2c32a82012-06-24 12:09:45 +0100896 } else if (info->detecting) {
897 dev_dbg(arizona->dev, "Headphone detected\n");
898 info->detecting = false;
899 arizona_stop_mic(info);
900
Mark Brown4f340332013-01-11 08:55:43 +0900901 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100902 } else {
903 dev_warn(arizona->dev, "Button with no mic: %x\n",
904 val);
905 }
906 } else {
907 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100908 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100909 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100910 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100911 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000912 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100913 }
914
915handled:
Mark Brown939c5672013-04-01 19:17:34 +0100916 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100917 queue_delayed_work(system_power_efficient_wq,
918 &info->micd_timeout_work,
919 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100920
Mark Brownf2c32a82012-06-24 12:09:45 +0100921 pm_runtime_mark_last_busy(info->dev);
922 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100923}
924
925static irqreturn_t arizona_micdet(int irq, void *data)
926{
927 struct arizona_extcon_info *info = data;
928 struct arizona *arizona = info->arizona;
929 int debounce = arizona->pdata.micd_detect_debounce;
930
931 cancel_delayed_work_sync(&info->micd_detect_work);
932 cancel_delayed_work_sync(&info->micd_timeout_work);
933
934 mutex_lock(&info->lock);
935 if (!info->detecting)
936 debounce = 0;
937 mutex_unlock(&info->lock);
938
939 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100940 queue_delayed_work(system_power_efficient_wq,
941 &info->micd_detect_work,
942 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100943 else
944 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100945
946 return IRQ_HANDLED;
947}
948
Mark Brown0e27bd32013-02-05 21:00:15 +0000949static void arizona_hpdet_work(struct work_struct *work)
950{
951 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900952 struct arizona_extcon_info,
953 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000954
955 mutex_lock(&info->lock);
956 arizona_start_hpdet_acc_id(info);
957 mutex_unlock(&info->lock);
958}
959
Mark Brownf2c32a82012-06-24 12:09:45 +0100960static irqreturn_t arizona_jackdet(int irq, void *data)
961{
962 struct arizona_extcon_info *info = data;
963 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900964 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100965 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100966 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100967
Mark Brown939c5672013-04-01 19:17:34 +0100968 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
969 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100970
Mark Browna3e20782013-04-01 19:05:27 +0100971 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000972
Mark Brownf2c32a82012-06-24 12:09:45 +0100973 mutex_lock(&info->lock);
974
Mark Brown92a49872013-01-11 08:55:39 +0900975 if (arizona->pdata.jd_gpio5) {
976 mask = ARIZONA_MICD_CLAMP_STS;
977 present = 0;
978 } else {
979 mask = ARIZONA_JD1_STS;
980 present = ARIZONA_JD1_STS;
981 }
982
Mark Brownf2c32a82012-06-24 12:09:45 +0100983 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
984 if (ret != 0) {
985 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
986 ret);
987 mutex_unlock(&info->lock);
988 pm_runtime_put_autosuspend(info->dev);
989 return IRQ_NONE;
990 }
991
Mark Browna3e20782013-04-01 19:05:27 +0100992 val &= mask;
993 if (val == info->last_jackdet) {
994 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +0100995 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100996 queue_delayed_work(system_power_efficient_wq,
997 &info->hpdet_work,
998 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +0100999
Chanwoo Choic2275d22013-08-23 10:21:37 +09001000 if (cancelled_mic) {
1001 int micd_timeout = info->micd_timeout;
1002
Mark Browndf9a5ab2013-07-18 22:42:22 +01001003 queue_delayed_work(system_power_efficient_wq,
1004 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001005 msecs_to_jiffies(micd_timeout));
1006 }
Mark Brown939c5672013-04-01 19:17:34 +01001007
Mark Browna3e20782013-04-01 19:05:27 +01001008 goto out;
1009 }
1010 info->last_jackdet = val;
1011
1012 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001013 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +01001014 ret = extcon_set_cable_state_(&info->edev,
1015 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001016
1017 if (ret != 0)
1018 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1019 ret);
1020
Mark Browndd235ee2013-01-11 08:55:51 +09001021 if (!arizona->pdata.hpdet_acc_id) {
1022 info->detecting = true;
1023 info->mic = false;
1024 info->jack_flips = 0;
1025
1026 arizona_start_mic(info);
1027 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001028 queue_delayed_work(system_power_efficient_wq,
1029 &info->hpdet_work,
1030 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001031 }
Mark Brown4e616872013-01-15 22:09:20 +09001032
1033 regmap_update_bits(arizona->regmap,
1034 ARIZONA_JACK_DETECT_DEBOUNCE,
1035 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001036 } else {
1037 dev_dbg(arizona->dev, "Detected jack removal\n");
1038
1039 arizona_stop_mic(info);
1040
Mark Browndd235ee2013-01-11 08:55:51 +09001041 info->num_hpdet_res = 0;
1042 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1043 info->hpdet_res[i] = 0;
1044 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001045 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001046 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001047
Mark Brown6fed4d82013-04-01 22:03:06 +01001048 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001049 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001050 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001051 input_sync(info->input);
1052
Mark Brownf2c32a82012-06-24 12:09:45 +01001053 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
1054 if (ret != 0)
1055 dev_err(arizona->dev, "Removal report failed: %d\n",
1056 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001057
1058 regmap_update_bits(arizona->regmap,
1059 ARIZONA_JACK_DETECT_DEBOUNCE,
1060 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1061 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001062 }
1063
Mark Brown7abd4e22013-04-01 19:25:55 +01001064 if (arizona->pdata.micd_timeout)
1065 info->micd_timeout = arizona->pdata.micd_timeout;
1066 else
1067 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1068
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001069out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001070 /* Clear trig_sts to make sure DCVDD is not forced up */
1071 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1072 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1073 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1074 ARIZONA_JD1_FALL_TRIG_STS |
1075 ARIZONA_JD1_RISE_TRIG_STS);
1076
Mark Brownf2c32a82012-06-24 12:09:45 +01001077 mutex_unlock(&info->lock);
1078
1079 pm_runtime_mark_last_busy(info->dev);
1080 pm_runtime_put_autosuspend(info->dev);
1081
1082 return IRQ_HANDLED;
1083}
1084
Mark Brown6fed4d82013-04-01 22:03:06 +01001085/* Map a level onto a slot in the register bank */
1086static void arizona_micd_set_level(struct arizona *arizona, int index,
1087 unsigned int level)
1088{
1089 int reg;
1090 unsigned int mask;
1091
1092 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1093
1094 if (!(index % 2)) {
1095 mask = 0x3f00;
1096 level <<= 8;
1097 } else {
1098 mask = 0x3f;
1099 }
1100
1101 /* Program the level itself */
1102 regmap_update_bits(arizona->regmap, reg, mask, level);
1103}
1104
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001105static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001106{
1107 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001108 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001109 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001110 unsigned int val;
Mark Brown92a49872013-01-11 08:55:39 +09001111 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001112 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001113
Mark Brownbbbd46e2013-01-10 19:38:43 +00001114 if (!arizona->dapm || !arizona->dapm->card)
1115 return -EPROBE_DEFER;
1116
Mark Brownf2c32a82012-06-24 12:09:45 +01001117 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1118 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001119 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +01001120 ret = -ENOMEM;
1121 goto err;
1122 }
1123
1124 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1125 if (IS_ERR(info->micvdd)) {
1126 ret = PTR_ERR(info->micvdd);
1127 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
1128 goto err;
1129 }
1130
1131 mutex_init(&info->lock);
1132 info->arizona = arizona;
1133 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001134 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001135 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001136 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001137 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001138 platform_set_drvdata(pdev, info);
1139
1140 switch (arizona->type) {
1141 case WM5102:
1142 switch (arizona->rev) {
1143 case 0:
1144 info->micd_reva = true;
1145 break;
1146 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001147 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001148 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001149 break;
1150 }
1151 break;
Charles Keepax77438612013-11-14 16:18:25 +00001152 case WM5110:
1153 switch (arizona->rev) {
1154 case 0 ... 2:
1155 break;
1156 default:
1157 info->micd_clamp = true;
1158 info->hpdet_ip = 2;
1159 break;
1160 }
1161 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001162 default:
1163 break;
1164 }
1165
1166 info->edev.name = "Headset Jack";
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001167 info->edev.dev.parent = arizona->dev;
Mark Brownf2c32a82012-06-24 12:09:45 +01001168 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001169
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001170 ret = extcon_dev_register(&info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001171 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001172 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001173 ret);
1174 goto err;
1175 }
1176
Mark Brown6fed4d82013-04-01 22:03:06 +01001177 info->input = devm_input_allocate_device(&pdev->dev);
1178 if (!info->input) {
1179 dev_err(arizona->dev, "Can't allocate input dev\n");
1180 ret = -ENOMEM;
1181 goto err_register;
1182 }
1183
1184 info->input->name = "Headset";
1185 info->input->phys = "arizona/extcon";
1186 info->input->dev.parent = &pdev->dev;
1187
Mark Brownf2c32a82012-06-24 12:09:45 +01001188 if (pdata->num_micd_configs) {
1189 info->micd_modes = pdata->micd_configs;
1190 info->micd_num_modes = pdata->num_micd_configs;
1191 } else {
1192 info->micd_modes = micd_default_modes;
1193 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1194 }
1195
1196 if (arizona->pdata.micd_pol_gpio > 0) {
1197 if (info->micd_modes[0].gpio)
1198 mode = GPIOF_OUT_INIT_HIGH;
1199 else
1200 mode = GPIOF_OUT_INIT_LOW;
1201
1202 ret = devm_gpio_request_one(&pdev->dev,
1203 arizona->pdata.micd_pol_gpio,
1204 mode,
1205 "MICD polarity");
1206 if (ret != 0) {
1207 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1208 arizona->pdata.micd_pol_gpio, ret);
1209 goto err_register;
1210 }
1211 }
1212
Mark Brown1eda6aa2013-01-11 08:55:54 +09001213 if (arizona->pdata.hpdet_id_gpio > 0) {
1214 ret = devm_gpio_request_one(&pdev->dev,
1215 arizona->pdata.hpdet_id_gpio,
1216 GPIOF_OUT_INIT_LOW,
1217 "HPDET");
1218 if (ret != 0) {
1219 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1220 arizona->pdata.hpdet_id_gpio, ret);
1221 goto err_register;
1222 }
1223 }
1224
Mark Brownb17e5462013-01-11 08:55:24 +09001225 if (arizona->pdata.micd_bias_start_time)
1226 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1227 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1228 arizona->pdata.micd_bias_start_time
1229 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1230
Mark Brown2e033db2013-01-21 17:36:33 +09001231 if (arizona->pdata.micd_rate)
1232 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1233 ARIZONA_MICD_RATE_MASK,
1234 arizona->pdata.micd_rate
1235 << ARIZONA_MICD_RATE_SHIFT);
1236
1237 if (arizona->pdata.micd_dbtime)
1238 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1239 ARIZONA_MICD_DBTIME_MASK,
1240 arizona->pdata.micd_dbtime
1241 << ARIZONA_MICD_DBTIME_SHIFT);
1242
Mark Brown6fed4d82013-04-01 22:03:06 +01001243 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1244
1245 if (arizona->pdata.num_micd_ranges) {
1246 info->micd_ranges = pdata->micd_ranges;
1247 info->num_micd_ranges = pdata->num_micd_ranges;
1248 } else {
1249 info->micd_ranges = micd_default_ranges;
1250 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1251 }
1252
1253 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1254 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1255 arizona->pdata.num_micd_ranges);
1256 }
1257
1258 if (info->num_micd_ranges > 1) {
1259 for (i = 1; i < info->num_micd_ranges; i++) {
1260 if (info->micd_ranges[i - 1].max >
1261 info->micd_ranges[i].max) {
1262 dev_err(arizona->dev,
1263 "MICD ranges must be sorted\n");
1264 ret = -EINVAL;
1265 goto err_input;
1266 }
1267 }
1268 }
1269
1270 /* Disable all buttons by default */
1271 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1272 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1273
1274 /* Set up all the buttons the user specified */
1275 for (i = 0; i < info->num_micd_ranges; i++) {
1276 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1277 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1278 break;
1279
1280 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1281 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1282 info->micd_ranges[i].max);
1283 ret = -EINVAL;
1284 goto err_input;
1285 }
1286
1287 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1288 arizona_micd_levels[j], i);
1289
1290 arizona_micd_set_level(arizona, i, j);
1291 input_set_capability(info->input, EV_KEY,
1292 info->micd_ranges[i].key);
1293
1294 /* Enable reporting of that range */
1295 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1296 1 << i, 1 << i);
1297 }
1298
1299 /* Set all the remaining keys to a maximum */
1300 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1301 arizona_micd_set_level(arizona, i, 0x3f);
1302
Mark Browndab63eb2013-01-11 08:55:36 +09001303 /*
Mark Brown92a49872013-01-11 08:55:39 +09001304 * If we have a clamp use it, activating in conjunction with
1305 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001306 */
1307 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001308 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001309 /* Put the GPIO into input mode with optional pull */
1310 val = 0xc101;
1311 if (arizona->pdata.jd_gpio5_nopull)
1312 val &= ~ARIZONA_GPN_PU;
1313
Mark Brown92a49872013-01-11 08:55:39 +09001314 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001315 val);
Mark Brown92a49872013-01-11 08:55:39 +09001316
1317 regmap_update_bits(arizona->regmap,
1318 ARIZONA_MICD_CLAMP_CONTROL,
1319 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1320 } else {
1321 regmap_update_bits(arizona->regmap,
1322 ARIZONA_MICD_CLAMP_CONTROL,
1323 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1324 }
1325
Mark Browndab63eb2013-01-11 08:55:36 +09001326 regmap_update_bits(arizona->regmap,
1327 ARIZONA_JACK_DETECT_DEBOUNCE,
1328 ARIZONA_MICD_CLAMP_DB,
1329 ARIZONA_MICD_CLAMP_DB);
1330 }
1331
Mark Brownf2c32a82012-06-24 12:09:45 +01001332 arizona_extcon_set_mode(info, 0);
1333
1334 pm_runtime_enable(&pdev->dev);
1335 pm_runtime_idle(&pdev->dev);
1336 pm_runtime_get_sync(&pdev->dev);
1337
Mark Brown92a49872013-01-11 08:55:39 +09001338 if (arizona->pdata.jd_gpio5) {
1339 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1340 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1341 } else {
1342 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1343 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1344 }
1345
1346 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001347 "JACKDET rise", arizona_jackdet, info);
1348 if (ret != 0) {
1349 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1350 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001351 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001352 }
1353
Mark Brown92a49872013-01-11 08:55:39 +09001354 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001355 if (ret != 0) {
1356 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1357 ret);
1358 goto err_rise;
1359 }
1360
Mark Brown92a49872013-01-11 08:55:39 +09001361 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001362 "JACKDET fall", arizona_jackdet, info);
1363 if (ret != 0) {
1364 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1365 goto err_rise_wake;
1366 }
1367
Mark Brown92a49872013-01-11 08:55:39 +09001368 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001369 if (ret != 0) {
1370 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1371 ret);
1372 goto err_fall;
1373 }
1374
1375 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1376 "MICDET", arizona_micdet, info);
1377 if (ret != 0) {
1378 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1379 goto err_fall_wake;
1380 }
1381
Mark Brown4f340332013-01-11 08:55:43 +09001382 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1383 "HPDET", arizona_hpdet_irq, info);
1384 if (ret != 0) {
1385 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1386 goto err_micdet;
1387 }
1388
Mark Brownf2c32a82012-06-24 12:09:45 +01001389 arizona_clk32k_enable(arizona);
1390 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1391 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1392 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1393 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1394
Mark Brownb8575a12012-09-07 17:01:15 +08001395 ret = regulator_allow_bypass(info->micvdd, true);
1396 if (ret != 0)
1397 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1398 ret);
1399
Mark Brownf2c32a82012-06-24 12:09:45 +01001400 pm_runtime_put(&pdev->dev);
1401
Mark Brown34efe4d2012-07-20 17:07:29 +01001402 ret = input_register_device(info->input);
1403 if (ret) {
1404 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001405 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001406 }
1407
Mark Brownf2c32a82012-06-24 12:09:45 +01001408 return 0;
1409
Mark Brown4f340332013-01-11 08:55:43 +09001410err_hpdet:
1411 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001412err_micdet:
1413 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001414err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001415 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001416err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001417 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001418err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001419 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001420err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001421 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001422err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001423err_register:
1424 pm_runtime_disable(&pdev->dev);
1425 extcon_dev_unregister(&info->edev);
1426err:
1427 return ret;
1428}
1429
Bill Pemberton93ed0322012-11-19 13:25:49 -05001430static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001431{
1432 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1433 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001434 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001435
1436 pm_runtime_disable(&pdev->dev);
1437
Mark Browndab63eb2013-01-11 08:55:36 +09001438 regmap_update_bits(arizona->regmap,
1439 ARIZONA_MICD_CLAMP_CONTROL,
1440 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1441
Mark Brown92a49872013-01-11 08:55:39 +09001442 if (arizona->pdata.jd_gpio5) {
1443 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1444 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1445 } else {
1446 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1447 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1448 }
1449
1450 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1451 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1452 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001453 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001454 arizona_free_irq(arizona, jack_irq_rise, info);
1455 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001456 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001457 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1458 ARIZONA_JD1_ENA, 0);
1459 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001460 extcon_dev_unregister(&info->edev);
1461
1462 return 0;
1463}
1464
1465static struct platform_driver arizona_extcon_driver = {
1466 .driver = {
1467 .name = "arizona-extcon",
1468 .owner = THIS_MODULE,
1469 },
1470 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001471 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001472};
1473
1474module_platform_driver(arizona_extcon_driver);
1475
1476MODULE_DESCRIPTION("Arizona Extcon driver");
1477MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1478MODULE_LICENSE("GPL");
1479MODULE_ALIAS("platform:extcon-arizona");