blob: 98a14f6143a7087accee9c5d2b127c99c300b81d [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
Mark Brownbbbd46e2013-01-10 19:38:43 +0000225 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
226 if (ret != 0)
227 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
228 widget, ret);
229
Mark Brownbbbd46e2013-01-10 19:38:43 +0000230 snd_soc_dapm_sync(dapm);
231
232 if (!arizona->pdata.micd_force_micbias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000233 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
234 if (ret != 0)
235 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
236 widget, ret);
237
Mark Brownbbbd46e2013-01-10 19:38:43 +0000238 snd_soc_dapm_sync(dapm);
239 }
240}
241
Mark Brown9b1270c2013-01-11 08:55:46 +0900242static void arizona_start_mic(struct arizona_extcon_info *info)
243{
244 struct arizona *arizona = info->arizona;
245 bool change;
246 int ret;
247
Mark Brown9b1270c2013-01-11 08:55:46 +0900248 /* Microphone detection can't use idle mode */
249 pm_runtime_get(info->dev);
250
Mark Brownbbbd46e2013-01-10 19:38:43 +0000251 if (info->detecting) {
252 ret = regulator_allow_bypass(info->micvdd, false);
253 if (ret != 0) {
254 dev_err(arizona->dev,
255 "Failed to regulate MICVDD: %d\n",
256 ret);
257 }
258 }
259
Mark Brown9b1270c2013-01-11 08:55:46 +0900260 ret = regulator_enable(info->micvdd);
261 if (ret != 0) {
262 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
263 ret);
264 }
265
266 if (info->micd_reva) {
267 regmap_write(arizona->regmap, 0x80, 0x3);
268 regmap_write(arizona->regmap, 0x294, 0);
269 regmap_write(arizona->regmap, 0x80, 0x0);
270 }
271
272 regmap_update_bits(arizona->regmap,
273 ARIZONA_ACCESSORY_DETECT_MODE_1,
274 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
275
Mark Brownbbbd46e2013-01-10 19:38:43 +0000276 arizona_extcon_pulse_micbias(info);
277
Mark Brown9b1270c2013-01-11 08:55:46 +0900278 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
279 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
280 &change);
281 if (!change) {
282 regulator_disable(info->micvdd);
283 pm_runtime_put_autosuspend(info->dev);
284 }
285}
286
287static void arizona_stop_mic(struct arizona_extcon_info *info)
288{
289 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000290 const char *widget = arizona_extcon_get_micbias(info);
291 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900292 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000293 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900294
295 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
296 ARIZONA_MICD_ENA, 0,
297 &change);
298
Mark Brownbbbd46e2013-01-10 19:38:43 +0000299 ret = snd_soc_dapm_disable_pin(dapm, widget);
300 if (ret != 0)
301 dev_warn(arizona->dev,
302 "Failed to disable %s: %d\n",
303 widget, ret);
304
Mark Brownbbbd46e2013-01-10 19:38:43 +0000305 snd_soc_dapm_sync(dapm);
306
Mark Brown9b1270c2013-01-11 08:55:46 +0900307 if (info->micd_reva) {
308 regmap_write(arizona->regmap, 0x80, 0x3);
309 regmap_write(arizona->regmap, 0x294, 2);
310 regmap_write(arizona->regmap, 0x80, 0x0);
311 }
312
Mark Brownbbbd46e2013-01-10 19:38:43 +0000313 ret = regulator_allow_bypass(info->micvdd, true);
314 if (ret != 0) {
315 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
316 ret);
317 }
318
Mark Brown9b1270c2013-01-11 08:55:46 +0900319 if (change) {
320 regulator_disable(info->micvdd);
321 pm_runtime_mark_last_busy(info->dev);
322 pm_runtime_put_autosuspend(info->dev);
323 }
324}
325
Mark Brown4f340332013-01-11 08:55:43 +0900326static struct {
327 unsigned int factor_a;
328 unsigned int factor_b;
329} arizona_hpdet_b_ranges[] = {
330 { 5528, 362464 },
331 { 11084, 6186851 },
332 { 11065, 65460395 },
333};
334
335static struct {
336 int min;
337 int max;
338} arizona_hpdet_c_ranges[] = {
339 { 0, 30 },
340 { 8, 100 },
341 { 100, 1000 },
342 { 1000, 10000 },
343};
344
345static int arizona_hpdet_read(struct arizona_extcon_info *info)
346{
347 struct arizona *arizona = info->arizona;
348 unsigned int val, range;
349 int ret;
350
351 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
352 if (ret != 0) {
353 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
354 ret);
355 return ret;
356 }
357
358 switch (info->hpdet_ip) {
359 case 0:
360 if (!(val & ARIZONA_HP_DONE)) {
361 dev_err(arizona->dev, "HPDET did not complete: %x\n",
362 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900363 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900364 }
365
366 val &= ARIZONA_HP_LVL_MASK;
367 break;
368
369 case 1:
370 if (!(val & ARIZONA_HP_DONE_B)) {
371 dev_err(arizona->dev, "HPDET did not complete: %x\n",
372 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900373 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900374 }
375
376 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
377 if (ret != 0) {
378 dev_err(arizona->dev, "Failed to read HP value: %d\n",
379 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900380 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900381 }
382
383 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
384 &range);
385 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
386 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
387
388 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100389 (val < 100 || val >= 0x3fb)) {
Mark Brown4f340332013-01-11 08:55:43 +0900390 range++;
391 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
392 range);
393 regmap_update_bits(arizona->regmap,
394 ARIZONA_HEADPHONE_DETECT_1,
395 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
396 range <<
397 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
398 return -EAGAIN;
399 }
400
401 /* If we go out of range report top of range */
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100402 if (val < 100 || val >= 0x3fb) {
Mark Brown4f340332013-01-11 08:55:43 +0900403 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100404 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900405 }
406
407 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
408 val, range);
409
410 val = arizona_hpdet_b_ranges[range].factor_b
411 / ((val * 100) -
412 arizona_hpdet_b_ranges[range].factor_a);
413 break;
414
415 default:
416 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
417 info->hpdet_ip);
418 case 2:
419 if (!(val & ARIZONA_HP_DONE_B)) {
420 dev_err(arizona->dev, "HPDET did not complete: %x\n",
421 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900422 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900423 }
424
425 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000426 /* Convert to ohms, the value is in 0.5 ohm increments */
427 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900428
429 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
430 &range);
431 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
432 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
433
Charles Keepax91414612013-11-14 16:18:24 +0000434 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900435 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
436 (val >= arizona_hpdet_c_ranges[range].max)) {
437 range++;
438 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
439 arizona_hpdet_c_ranges[range].min,
440 arizona_hpdet_c_ranges[range].max);
441 regmap_update_bits(arizona->regmap,
442 ARIZONA_HEADPHONE_DETECT_1,
443 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
444 range <<
445 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
446 return -EAGAIN;
447 }
Charles Keepax91414612013-11-14 16:18:24 +0000448
449 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
450 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
451 arizona_hpdet_c_ranges[range].min);
452 val = arizona_hpdet_c_ranges[range].min;
453 }
Mark Brown4f340332013-01-11 08:55:43 +0900454 }
455
456 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
457 return val;
458}
459
Mark Brown9c2ba272013-02-25 23:42:31 +0000460static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
461 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900462{
463 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900464 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900465
466 /*
467 * If we're using HPDET for accessory identification we need
468 * to take multiple measurements, step through them in sequence.
469 */
470 if (arizona->pdata.hpdet_acc_id) {
471 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900472
473 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000474 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900475 dev_dbg(arizona->dev, "Measuring mic\n");
476
477 regmap_update_bits(arizona->regmap,
478 ARIZONA_ACCESSORY_DETECT_MODE_1,
479 ARIZONA_ACCDET_MODE_MASK |
480 ARIZONA_ACCDET_SRC,
481 ARIZONA_ACCDET_MODE_HPR |
482 info->micd_modes[0].src);
483
484 gpio_set_value_cansleep(id_gpio, 1);
485
Mark Browndd235ee2013-01-11 08:55:51 +0900486 regmap_update_bits(arizona->regmap,
487 ARIZONA_HEADPHONE_DETECT_1,
488 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
489 return -EAGAIN;
490 }
491
492 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000493 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
494 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000495
496 /* Take the headphone impedance for the main report */
497 *reading = info->hpdet_res[0];
498
Mark Brown9dd5e532013-04-01 19:09:45 +0100499 /* Sometimes we get false readings due to slow insert */
500 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
501 dev_dbg(arizona->dev, "Retrying high impedance\n");
502 info->num_hpdet_res = 0;
503 info->hpdet_retried = true;
504 arizona_start_hpdet_acc_id(info);
505 pm_runtime_put(info->dev);
506 return -EAGAIN;
507 }
508
Mark Brown1eda6aa2013-01-11 08:55:54 +0900509 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530510 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900511 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000512 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900513 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000514 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000515 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900516 } else {
517 dev_dbg(arizona->dev, "Detected headphone\n");
518 }
519
520 /* Make sure everything is reset back to the real polarity */
521 regmap_update_bits(arizona->regmap,
522 ARIZONA_ACCESSORY_DETECT_MODE_1,
523 ARIZONA_ACCDET_SRC,
524 info->micd_modes[0].src);
525 }
526
527 return 0;
528}
529
Mark Brown4f340332013-01-11 08:55:43 +0900530static irqreturn_t arizona_hpdet_irq(int irq, void *data)
531{
532 struct arizona_extcon_info *info = data;
533 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900534 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900535 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900536 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000537 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900538
539 mutex_lock(&info->lock);
540
541 /* If we got a spurious IRQ for some reason then ignore it */
542 if (!info->hpdet_active) {
543 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
544 mutex_unlock(&info->lock);
545 return IRQ_NONE;
546 }
547
548 /* If the cable was removed while measuring ignore the result */
549 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
550 if (ret < 0) {
551 dev_err(arizona->dev, "Failed to check cable state: %d\n",
552 ret);
553 goto out;
554 } else if (!ret) {
555 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
556 goto done;
557 }
558
559 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900560 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900561 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900562 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900563 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900564 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900565
566 /* Reset back to starting range */
567 regmap_update_bits(arizona->regmap,
568 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900569 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
570 0);
571
Mark Brown9c2ba272013-02-25 23:42:31 +0000572 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900573 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900574 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900575 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900576 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900577
578 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900579 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900580 report = ARIZONA_CABLE_LINEOUT;
581 else
582 report = ARIZONA_CABLE_HEADPHONE;
583
584 ret = extcon_set_cable_state_(&info->edev, report, true);
585 if (ret != 0)
586 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
587 ret);
588
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000589done:
590 /* Reset back to starting range */
591 regmap_update_bits(arizona->regmap,
592 ARIZONA_HEADPHONE_DETECT_1,
593 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
594 0);
595
Mark Brown03409072013-02-12 13:00:31 +0000596 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900597
Mark Brown1eda6aa2013-01-11 08:55:54 +0900598 if (id_gpio)
599 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900600
601 /* Revert back to MICDET mode */
602 regmap_update_bits(arizona->regmap,
603 ARIZONA_ACCESSORY_DETECT_MODE_1,
604 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
605
606 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000607 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900608 arizona_start_mic(info);
609
610 if (info->hpdet_active) {
611 pm_runtime_put_autosuspend(info->dev);
612 info->hpdet_active = false;
613 }
614
Mark Brownbf14ee52013-02-05 20:20:17 +0000615 info->hpdet_done = true;
616
Mark Brown4f340332013-01-11 08:55:43 +0900617out:
618 mutex_unlock(&info->lock);
619
620 return IRQ_HANDLED;
621}
622
623static void arizona_identify_headphone(struct arizona_extcon_info *info)
624{
625 struct arizona *arizona = info->arizona;
626 int ret;
627
Mark Brownbf14ee52013-02-05 20:20:17 +0000628 if (info->hpdet_done)
629 return;
630
Mark Brown4f340332013-01-11 08:55:43 +0900631 dev_dbg(arizona->dev, "Starting HPDET\n");
632
633 /* Make sure we keep the device enabled during the measurement */
634 pm_runtime_get(info->dev);
635
636 info->hpdet_active = true;
637
638 if (info->mic)
639 arizona_stop_mic(info);
640
Mark Brown03409072013-02-12 13:00:31 +0000641 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900642
643 ret = regmap_update_bits(arizona->regmap,
644 ARIZONA_ACCESSORY_DETECT_MODE_1,
645 ARIZONA_ACCDET_MODE_MASK,
646 ARIZONA_ACCDET_MODE_HPL);
647 if (ret != 0) {
648 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
649 goto err;
650 }
651
652 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
653 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
654 if (ret != 0) {
655 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
656 ret);
657 goto err;
658 }
659
660 return;
661
662err:
663 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
664 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
665
666 /* Just report headphone */
667 ret = extcon_update_state(&info->edev,
668 1 << ARIZONA_CABLE_HEADPHONE,
669 1 << ARIZONA_CABLE_HEADPHONE);
670 if (ret != 0)
671 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
672
673 if (info->mic)
674 arizona_start_mic(info);
675
676 info->hpdet_active = false;
677}
Mark Browndd235ee2013-01-11 08:55:51 +0900678
679static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
680{
681 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000682 int hp_reading = 32;
683 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900684 int ret;
685
686 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
687
688 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000689 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900690
691 info->hpdet_active = true;
692
Mark Brown03409072013-02-12 13:00:31 +0000693 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900694
695 ret = regmap_update_bits(arizona->regmap,
696 ARIZONA_ACCESSORY_DETECT_MODE_1,
697 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
698 info->micd_modes[0].src |
699 ARIZONA_ACCDET_MODE_HPL);
700 if (ret != 0) {
701 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
702 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900703 }
704
Mark Brown9c2ba272013-02-25 23:42:31 +0000705 if (arizona->pdata.hpdet_acc_id_line) {
706 ret = regmap_update_bits(arizona->regmap,
707 ARIZONA_HEADPHONE_DETECT_1,
708 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
709 if (ret != 0) {
710 dev_err(arizona->dev,
711 "Can't start HPDETL measurement: %d\n",
712 ret);
713 goto err;
714 }
715 } else {
716 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900717 }
718
719 return;
720
721err:
722 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
723 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
724
725 /* Just report headphone */
726 ret = extcon_update_state(&info->edev,
727 1 << ARIZONA_CABLE_HEADPHONE,
728 1 << ARIZONA_CABLE_HEADPHONE);
729 if (ret != 0)
730 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
731
Mark Brown4f340332013-01-11 08:55:43 +0900732 info->hpdet_active = false;
733}
734
Mark Brown939c5672013-04-01 19:17:34 +0100735static void arizona_micd_timeout_work(struct work_struct *work)
736{
737 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900738 struct arizona_extcon_info,
739 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100740
741 mutex_lock(&info->lock);
742
743 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
744 arizona_identify_headphone(info);
745
746 info->detecting = false;
747
748 arizona_stop_mic(info);
749
750 mutex_unlock(&info->lock);
751}
752
Mark Browncd59e792013-04-01 19:21:48 +0100753static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100754{
Mark Browncd59e792013-04-01 19:21:48 +0100755 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900756 struct arizona_extcon_info,
757 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100758 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100759 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100760 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100761
Mark Brown939c5672013-04-01 19:17:34 +0100762 cancel_delayed_work_sync(&info->micd_timeout_work);
763
Mark Brownf2c32a82012-06-24 12:09:45 +0100764 mutex_lock(&info->lock);
765
Charles Keepax31a847e2013-11-14 16:18:23 +0000766 /* If the cable was removed while measuring ignore the result */
767 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
768 if (ret < 0) {
769 dev_err(arizona->dev, "Failed to check cable state: %d\n",
770 ret);
771 mutex_unlock(&info->lock);
772 return;
773 } else if (!ret) {
774 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
775 mutex_unlock(&info->lock);
776 return;
777 }
778
Charles Keepaxffae24f2013-11-14 16:18:21 +0000779 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100780 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
781 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900782 dev_err(arizona->dev,
783 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100784 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100785 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100786 }
787
788 dev_dbg(arizona->dev, "MICDET: %x\n", val);
789
790 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900791 dev_warn(arizona->dev,
792 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100793 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100794 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100795 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100796 }
797
Charles Keepaxffae24f2013-11-14 16:18:21 +0000798 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100799 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100800 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100801 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100802 }
803
804 /* Due to jack detect this should never happen */
805 if (!(val & ARIZONA_MICD_STS)) {
806 dev_warn(arizona->dev, "Detected open circuit\n");
807 info->detecting = false;
808 goto handled;
809 }
810
811 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000812 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900813 arizona_identify_headphone(info);
814
Mark Brown325c6422012-06-28 13:08:30 +0100815 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900816 1 << ARIZONA_CABLE_MICROPHONE,
817 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100818
819 if (ret != 0)
820 dev_err(arizona->dev, "Headset report failed: %d\n",
821 ret);
822
Mark Brownbbbd46e2013-01-10 19:38:43 +0000823 /* Don't need to regulate for button detection */
824 ret = regulator_allow_bypass(info->micvdd, false);
825 if (ret != 0) {
826 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
827 ret);
828 }
829
Mark Brownf2c32a82012-06-24 12:09:45 +0100830 info->mic = true;
831 info->detecting = false;
832 goto handled;
833 }
834
835 /* If we detected a lower impedence during initial startup
836 * then we probably have the wrong polarity, flip it. Don't
837 * do this for the lowest impedences to speed up detection of
838 * plain headphones. If both polarities report a low
839 * impedence then give up and report headphones.
840 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000841 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800842 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900843 dev_dbg(arizona->dev, "Detected HP/line\n");
844 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100845
Mark Brown4f340332013-01-11 08:55:43 +0900846 info->detecting = false;
847
848 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100849 } else {
850 info->micd_mode++;
851 if (info->micd_mode == info->micd_num_modes)
852 info->micd_mode = 0;
853 arizona_extcon_set_mode(info, info->micd_mode);
854
855 info->jack_flips++;
856 }
857
858 goto handled;
859 }
860
861 /*
862 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100863 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100864 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000865 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100866 if (info->mic) {
867 dev_dbg(arizona->dev, "Mic button detected\n");
868
Mark Brown34efe4d2012-07-20 17:07:29 +0100869 lvl = val & ARIZONA_MICD_LVL_MASK;
870 lvl >>= ARIZONA_MICD_LVL_SHIFT;
871
Mark Brown41a57852013-04-01 19:18:18 +0100872 for (i = 0; i < info->num_micd_ranges; i++)
873 input_report_key(info->input,
874 info->micd_ranges[i].key, 0);
875
Mark Brown6fed4d82013-04-01 22:03:06 +0100876 WARN_ON(!lvl);
877 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
878 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
879 key = info->micd_ranges[ffs(lvl) - 1].key;
880 input_report_key(info->input, key, 1);
881 input_sync(info->input);
882 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100883
Mark Brownf2c32a82012-06-24 12:09:45 +0100884 } else if (info->detecting) {
885 dev_dbg(arizona->dev, "Headphone detected\n");
886 info->detecting = false;
887 arizona_stop_mic(info);
888
Mark Brown4f340332013-01-11 08:55:43 +0900889 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100890 } else {
891 dev_warn(arizona->dev, "Button with no mic: %x\n",
892 val);
893 }
894 } else {
895 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100896 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100897 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100898 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100899 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000900 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100901 }
902
903handled:
Mark Brown939c5672013-04-01 19:17:34 +0100904 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100905 queue_delayed_work(system_power_efficient_wq,
906 &info->micd_timeout_work,
907 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100908
Mark Brownf2c32a82012-06-24 12:09:45 +0100909 pm_runtime_mark_last_busy(info->dev);
910 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100911}
912
913static irqreturn_t arizona_micdet(int irq, void *data)
914{
915 struct arizona_extcon_info *info = data;
916 struct arizona *arizona = info->arizona;
917 int debounce = arizona->pdata.micd_detect_debounce;
918
919 cancel_delayed_work_sync(&info->micd_detect_work);
920 cancel_delayed_work_sync(&info->micd_timeout_work);
921
922 mutex_lock(&info->lock);
923 if (!info->detecting)
924 debounce = 0;
925 mutex_unlock(&info->lock);
926
927 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100928 queue_delayed_work(system_power_efficient_wq,
929 &info->micd_detect_work,
930 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100931 else
932 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100933
934 return IRQ_HANDLED;
935}
936
Mark Brown0e27bd32013-02-05 21:00:15 +0000937static void arizona_hpdet_work(struct work_struct *work)
938{
939 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900940 struct arizona_extcon_info,
941 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000942
943 mutex_lock(&info->lock);
944 arizona_start_hpdet_acc_id(info);
945 mutex_unlock(&info->lock);
946}
947
Mark Brownf2c32a82012-06-24 12:09:45 +0100948static irqreturn_t arizona_jackdet(int irq, void *data)
949{
950 struct arizona_extcon_info *info = data;
951 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900952 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100953 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100954 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100955
Mark Brown939c5672013-04-01 19:17:34 +0100956 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
957 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100958
Mark Browna3e20782013-04-01 19:05:27 +0100959 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000960
Mark Brownf2c32a82012-06-24 12:09:45 +0100961 mutex_lock(&info->lock);
962
Mark Brown92a49872013-01-11 08:55:39 +0900963 if (arizona->pdata.jd_gpio5) {
964 mask = ARIZONA_MICD_CLAMP_STS;
965 present = 0;
966 } else {
967 mask = ARIZONA_JD1_STS;
968 present = ARIZONA_JD1_STS;
969 }
970
Mark Brownf2c32a82012-06-24 12:09:45 +0100971 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
972 if (ret != 0) {
973 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
974 ret);
975 mutex_unlock(&info->lock);
976 pm_runtime_put_autosuspend(info->dev);
977 return IRQ_NONE;
978 }
979
Mark Browna3e20782013-04-01 19:05:27 +0100980 val &= mask;
981 if (val == info->last_jackdet) {
982 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +0100983 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100984 queue_delayed_work(system_power_efficient_wq,
985 &info->hpdet_work,
986 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +0100987
Chanwoo Choic2275d22013-08-23 10:21:37 +0900988 if (cancelled_mic) {
989 int micd_timeout = info->micd_timeout;
990
Mark Browndf9a5ab2013-07-18 22:42:22 +0100991 queue_delayed_work(system_power_efficient_wq,
992 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900993 msecs_to_jiffies(micd_timeout));
994 }
Mark Brown939c5672013-04-01 19:17:34 +0100995
Mark Browna3e20782013-04-01 19:05:27 +0100996 goto out;
997 }
998 info->last_jackdet = val;
999
1000 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001001 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +01001002 ret = extcon_set_cable_state_(&info->edev,
1003 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001004
1005 if (ret != 0)
1006 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1007 ret);
1008
Mark Browndd235ee2013-01-11 08:55:51 +09001009 if (!arizona->pdata.hpdet_acc_id) {
1010 info->detecting = true;
1011 info->mic = false;
1012 info->jack_flips = 0;
1013
1014 arizona_start_mic(info);
1015 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001016 queue_delayed_work(system_power_efficient_wq,
1017 &info->hpdet_work,
1018 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001019 }
Mark Brown4e616872013-01-15 22:09:20 +09001020
1021 regmap_update_bits(arizona->regmap,
1022 ARIZONA_JACK_DETECT_DEBOUNCE,
1023 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001024 } else {
1025 dev_dbg(arizona->dev, "Detected jack removal\n");
1026
1027 arizona_stop_mic(info);
1028
Mark Browndd235ee2013-01-11 08:55:51 +09001029 info->num_hpdet_res = 0;
1030 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1031 info->hpdet_res[i] = 0;
1032 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001033 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001034 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001035
Mark Brown6fed4d82013-04-01 22:03:06 +01001036 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001037 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001038 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001039 input_sync(info->input);
1040
Mark Brownf2c32a82012-06-24 12:09:45 +01001041 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
1042 if (ret != 0)
1043 dev_err(arizona->dev, "Removal report failed: %d\n",
1044 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001045
1046 regmap_update_bits(arizona->regmap,
1047 ARIZONA_JACK_DETECT_DEBOUNCE,
1048 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1049 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001050 }
1051
Mark Brown7abd4e22013-04-01 19:25:55 +01001052 if (arizona->pdata.micd_timeout)
1053 info->micd_timeout = arizona->pdata.micd_timeout;
1054 else
1055 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1056
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001057out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001058 /* Clear trig_sts to make sure DCVDD is not forced up */
1059 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1060 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1061 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1062 ARIZONA_JD1_FALL_TRIG_STS |
1063 ARIZONA_JD1_RISE_TRIG_STS);
1064
Mark Brownf2c32a82012-06-24 12:09:45 +01001065 mutex_unlock(&info->lock);
1066
1067 pm_runtime_mark_last_busy(info->dev);
1068 pm_runtime_put_autosuspend(info->dev);
1069
1070 return IRQ_HANDLED;
1071}
1072
Mark Brown6fed4d82013-04-01 22:03:06 +01001073/* Map a level onto a slot in the register bank */
1074static void arizona_micd_set_level(struct arizona *arizona, int index,
1075 unsigned int level)
1076{
1077 int reg;
1078 unsigned int mask;
1079
1080 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1081
1082 if (!(index % 2)) {
1083 mask = 0x3f00;
1084 level <<= 8;
1085 } else {
1086 mask = 0x3f;
1087 }
1088
1089 /* Program the level itself */
1090 regmap_update_bits(arizona->regmap, reg, mask, level);
1091}
1092
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001093static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001094{
1095 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001096 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001097 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001098 unsigned int val;
Mark Brown92a49872013-01-11 08:55:39 +09001099 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001100 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001101
Mark Brownbbbd46e2013-01-10 19:38:43 +00001102 if (!arizona->dapm || !arizona->dapm->card)
1103 return -EPROBE_DEFER;
1104
Mark Brownf2c32a82012-06-24 12:09:45 +01001105 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1106 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001107 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +01001108 ret = -ENOMEM;
1109 goto err;
1110 }
1111
1112 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1113 if (IS_ERR(info->micvdd)) {
1114 ret = PTR_ERR(info->micvdd);
1115 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
1116 goto err;
1117 }
1118
1119 mutex_init(&info->lock);
1120 info->arizona = arizona;
1121 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001122 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001123 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001124 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001125 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001126 platform_set_drvdata(pdev, info);
1127
1128 switch (arizona->type) {
1129 case WM5102:
1130 switch (arizona->rev) {
1131 case 0:
1132 info->micd_reva = true;
1133 break;
1134 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001135 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001136 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001137 break;
1138 }
1139 break;
Charles Keepax77438612013-11-14 16:18:25 +00001140 case WM5110:
1141 switch (arizona->rev) {
1142 case 0 ... 2:
1143 break;
1144 default:
1145 info->micd_clamp = true;
1146 info->hpdet_ip = 2;
1147 break;
1148 }
1149 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001150 default:
1151 break;
1152 }
1153
1154 info->edev.name = "Headset Jack";
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001155 info->edev.dev.parent = arizona->dev;
Mark Brownf2c32a82012-06-24 12:09:45 +01001156 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001157
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001158 ret = extcon_dev_register(&info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001159 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001160 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001161 ret);
1162 goto err;
1163 }
1164
Mark Brown6fed4d82013-04-01 22:03:06 +01001165 info->input = devm_input_allocate_device(&pdev->dev);
1166 if (!info->input) {
1167 dev_err(arizona->dev, "Can't allocate input dev\n");
1168 ret = -ENOMEM;
1169 goto err_register;
1170 }
1171
1172 info->input->name = "Headset";
1173 info->input->phys = "arizona/extcon";
1174 info->input->dev.parent = &pdev->dev;
1175
Mark Brownf2c32a82012-06-24 12:09:45 +01001176 if (pdata->num_micd_configs) {
1177 info->micd_modes = pdata->micd_configs;
1178 info->micd_num_modes = pdata->num_micd_configs;
1179 } else {
1180 info->micd_modes = micd_default_modes;
1181 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1182 }
1183
1184 if (arizona->pdata.micd_pol_gpio > 0) {
1185 if (info->micd_modes[0].gpio)
1186 mode = GPIOF_OUT_INIT_HIGH;
1187 else
1188 mode = GPIOF_OUT_INIT_LOW;
1189
1190 ret = devm_gpio_request_one(&pdev->dev,
1191 arizona->pdata.micd_pol_gpio,
1192 mode,
1193 "MICD polarity");
1194 if (ret != 0) {
1195 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1196 arizona->pdata.micd_pol_gpio, ret);
1197 goto err_register;
1198 }
1199 }
1200
Mark Brown1eda6aa2013-01-11 08:55:54 +09001201 if (arizona->pdata.hpdet_id_gpio > 0) {
1202 ret = devm_gpio_request_one(&pdev->dev,
1203 arizona->pdata.hpdet_id_gpio,
1204 GPIOF_OUT_INIT_LOW,
1205 "HPDET");
1206 if (ret != 0) {
1207 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1208 arizona->pdata.hpdet_id_gpio, ret);
1209 goto err_register;
1210 }
1211 }
1212
Mark Brownb17e5462013-01-11 08:55:24 +09001213 if (arizona->pdata.micd_bias_start_time)
1214 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1215 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1216 arizona->pdata.micd_bias_start_time
1217 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1218
Mark Brown2e033db2013-01-21 17:36:33 +09001219 if (arizona->pdata.micd_rate)
1220 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1221 ARIZONA_MICD_RATE_MASK,
1222 arizona->pdata.micd_rate
1223 << ARIZONA_MICD_RATE_SHIFT);
1224
1225 if (arizona->pdata.micd_dbtime)
1226 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1227 ARIZONA_MICD_DBTIME_MASK,
1228 arizona->pdata.micd_dbtime
1229 << ARIZONA_MICD_DBTIME_SHIFT);
1230
Mark Brown6fed4d82013-04-01 22:03:06 +01001231 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1232
1233 if (arizona->pdata.num_micd_ranges) {
1234 info->micd_ranges = pdata->micd_ranges;
1235 info->num_micd_ranges = pdata->num_micd_ranges;
1236 } else {
1237 info->micd_ranges = micd_default_ranges;
1238 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1239 }
1240
1241 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1242 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1243 arizona->pdata.num_micd_ranges);
1244 }
1245
1246 if (info->num_micd_ranges > 1) {
1247 for (i = 1; i < info->num_micd_ranges; i++) {
1248 if (info->micd_ranges[i - 1].max >
1249 info->micd_ranges[i].max) {
1250 dev_err(arizona->dev,
1251 "MICD ranges must be sorted\n");
1252 ret = -EINVAL;
1253 goto err_input;
1254 }
1255 }
1256 }
1257
1258 /* Disable all buttons by default */
1259 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1260 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1261
1262 /* Set up all the buttons the user specified */
1263 for (i = 0; i < info->num_micd_ranges; i++) {
1264 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1265 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1266 break;
1267
1268 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1269 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1270 info->micd_ranges[i].max);
1271 ret = -EINVAL;
1272 goto err_input;
1273 }
1274
1275 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1276 arizona_micd_levels[j], i);
1277
1278 arizona_micd_set_level(arizona, i, j);
1279 input_set_capability(info->input, EV_KEY,
1280 info->micd_ranges[i].key);
1281
1282 /* Enable reporting of that range */
1283 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1284 1 << i, 1 << i);
1285 }
1286
1287 /* Set all the remaining keys to a maximum */
1288 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1289 arizona_micd_set_level(arizona, i, 0x3f);
1290
Mark Browndab63eb2013-01-11 08:55:36 +09001291 /*
Mark Brown92a49872013-01-11 08:55:39 +09001292 * If we have a clamp use it, activating in conjunction with
1293 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001294 */
1295 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001296 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001297 /* Put the GPIO into input mode with optional pull */
1298 val = 0xc101;
1299 if (arizona->pdata.jd_gpio5_nopull)
1300 val &= ~ARIZONA_GPN_PU;
1301
Mark Brown92a49872013-01-11 08:55:39 +09001302 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001303 val);
Mark Brown92a49872013-01-11 08:55:39 +09001304
1305 regmap_update_bits(arizona->regmap,
1306 ARIZONA_MICD_CLAMP_CONTROL,
1307 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1308 } else {
1309 regmap_update_bits(arizona->regmap,
1310 ARIZONA_MICD_CLAMP_CONTROL,
1311 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1312 }
1313
Mark Browndab63eb2013-01-11 08:55:36 +09001314 regmap_update_bits(arizona->regmap,
1315 ARIZONA_JACK_DETECT_DEBOUNCE,
1316 ARIZONA_MICD_CLAMP_DB,
1317 ARIZONA_MICD_CLAMP_DB);
1318 }
1319
Mark Brownf2c32a82012-06-24 12:09:45 +01001320 arizona_extcon_set_mode(info, 0);
1321
1322 pm_runtime_enable(&pdev->dev);
1323 pm_runtime_idle(&pdev->dev);
1324 pm_runtime_get_sync(&pdev->dev);
1325
Mark Brown92a49872013-01-11 08:55:39 +09001326 if (arizona->pdata.jd_gpio5) {
1327 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1328 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1329 } else {
1330 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1331 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1332 }
1333
1334 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001335 "JACKDET rise", arizona_jackdet, info);
1336 if (ret != 0) {
1337 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1338 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001339 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001340 }
1341
Mark Brown92a49872013-01-11 08:55:39 +09001342 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001343 if (ret != 0) {
1344 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1345 ret);
1346 goto err_rise;
1347 }
1348
Mark Brown92a49872013-01-11 08:55:39 +09001349 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001350 "JACKDET fall", arizona_jackdet, info);
1351 if (ret != 0) {
1352 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1353 goto err_rise_wake;
1354 }
1355
Mark Brown92a49872013-01-11 08:55:39 +09001356 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001357 if (ret != 0) {
1358 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1359 ret);
1360 goto err_fall;
1361 }
1362
1363 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1364 "MICDET", arizona_micdet, info);
1365 if (ret != 0) {
1366 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1367 goto err_fall_wake;
1368 }
1369
Mark Brown4f340332013-01-11 08:55:43 +09001370 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1371 "HPDET", arizona_hpdet_irq, info);
1372 if (ret != 0) {
1373 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1374 goto err_micdet;
1375 }
1376
Mark Brownf2c32a82012-06-24 12:09:45 +01001377 arizona_clk32k_enable(arizona);
1378 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1379 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1380 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1381 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1382
Mark Brownb8575a12012-09-07 17:01:15 +08001383 ret = regulator_allow_bypass(info->micvdd, true);
1384 if (ret != 0)
1385 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1386 ret);
1387
Mark Brownf2c32a82012-06-24 12:09:45 +01001388 pm_runtime_put(&pdev->dev);
1389
Mark Brown34efe4d2012-07-20 17:07:29 +01001390 ret = input_register_device(info->input);
1391 if (ret) {
1392 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001393 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001394 }
1395
Mark Brownf2c32a82012-06-24 12:09:45 +01001396 return 0;
1397
Mark Brown4f340332013-01-11 08:55:43 +09001398err_hpdet:
1399 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001400err_micdet:
1401 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001402err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001403 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001404err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001405 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001406err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001407 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001408err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001409 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001410err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001411err_register:
1412 pm_runtime_disable(&pdev->dev);
1413 extcon_dev_unregister(&info->edev);
1414err:
1415 return ret;
1416}
1417
Bill Pemberton93ed0322012-11-19 13:25:49 -05001418static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001419{
1420 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1421 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001422 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001423
1424 pm_runtime_disable(&pdev->dev);
1425
Mark Browndab63eb2013-01-11 08:55:36 +09001426 regmap_update_bits(arizona->regmap,
1427 ARIZONA_MICD_CLAMP_CONTROL,
1428 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1429
Mark Brown92a49872013-01-11 08:55:39 +09001430 if (arizona->pdata.jd_gpio5) {
1431 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1432 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1433 } else {
1434 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1435 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1436 }
1437
1438 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1439 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1440 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001441 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001442 arizona_free_irq(arizona, jack_irq_rise, info);
1443 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001444 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001445 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1446 ARIZONA_JD1_ENA, 0);
1447 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001448 extcon_dev_unregister(&info->edev);
1449
1450 return 0;
1451}
1452
1453static struct platform_driver arizona_extcon_driver = {
1454 .driver = {
1455 .name = "arizona-extcon",
1456 .owner = THIS_MODULE,
1457 },
1458 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001459 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001460};
1461
1462module_platform_driver(arizona_extcon_driver);
1463
1464MODULE_DESCRIPTION("Arizona Extcon driver");
1465MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1466MODULE_LICENSE("GPL");
1467MODULE_ALIAS("platform:extcon-arizona");