blob: fefb8563db9eb760a1941483092b535022225e14 [file] [log] [blame]
Mark Brownf2c32a82012-06-24 12:09:45 +01001/*
2 * extcon-arizona.c - Extcon driver Wolfson Arizona devices
3 *
4 * Copyright (C) 2012 Wolfson Microelectronics plc
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/i2c.h>
20#include <linux/slab.h>
21#include <linux/interrupt.h>
22#include <linux/err.h>
23#include <linux/gpio.h>
Mark Brown34efe4d2012-07-20 17:07:29 +010024#include <linux/input.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010025#include <linux/platform_device.h>
26#include <linux/pm_runtime.h>
27#include <linux/regulator/consumer.h>
28#include <linux/extcon.h>
29
Mark Brownbbbd46e2013-01-10 19:38:43 +000030#include <sound/soc.h>
31
Mark Brownf2c32a82012-06-24 12:09:45 +010032#include <linux/mfd/arizona/core.h>
33#include <linux/mfd/arizona/pdata.h>
34#include <linux/mfd/arizona/registers.h>
35
Mark Brown6fed4d82013-04-01 22:03:06 +010036#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010037
Mark Brown4f340332013-01-11 08:55:43 +090038#define ARIZONA_ACCDET_MODE_MIC 0
39#define ARIZONA_ACCDET_MODE_HPL 1
40#define ARIZONA_ACCDET_MODE_HPR 2
41
Mark Brown9dd5e532013-04-01 19:09:45 +010042#define ARIZONA_HPDET_MAX 10000
43
Mark Brown2643fd62013-04-01 19:07:28 +010044#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010045#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010046
Charles Keepaxffae24f2013-11-14 16:18:21 +000047#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
48 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
49 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
50 ARIZONA_MICD_LVL_7)
51
52#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
53
54#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
55
Mark Brownf2c32a82012-06-24 12:09:45 +010056struct arizona_extcon_info {
57 struct device *dev;
58 struct arizona *arizona;
59 struct mutex lock;
60 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010061 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010062
Mark Browna3e20782013-04-01 19:05:27 +010063 u16 last_jackdet;
64
Mark Brownf2c32a82012-06-24 12:09:45 +010065 int micd_mode;
66 const struct arizona_micd_config *micd_modes;
67 int micd_num_modes;
68
Mark Brown6fed4d82013-04-01 22:03:06 +010069 const struct arizona_micd_range *micd_ranges;
70 int num_micd_ranges;
71
Mark Brown7abd4e22013-04-01 19:25:55 +010072 int micd_timeout;
73
Mark Brownf2c32a82012-06-24 12:09:45 +010074 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090075 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010076
Mark Brown0e27bd32013-02-05 21:00:15 +000077 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010078 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010079 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000080
Mark Brown4f340332013-01-11 08:55:43 +090081 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000082 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010083 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090084
Mark Browndd235ee2013-01-11 08:55:51 +090085 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090086 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090087
Mark Brownf2c32a82012-06-24 12:09:45 +010088 bool mic;
89 bool detecting;
90 int jack_flips;
91
Mark Brown4f340332013-01-11 08:55:43 +090092 int hpdet_ip;
93
Mark Brownf2c32a82012-06-24 12:09:45 +010094 struct extcon_dev edev;
95};
96
97static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +010098 { ARIZONA_ACCDET_SRC, 1, 0 },
99 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100100};
101
Mark Brown6fed4d82013-04-01 22:03:06 +0100102static const struct arizona_micd_range micd_default_ranges[] = {
103 { .max = 11, .key = BTN_0 },
104 { .max = 28, .key = BTN_1 },
105 { .max = 54, .key = BTN_2 },
106 { .max = 100, .key = BTN_3 },
107 { .max = 186, .key = BTN_4 },
108 { .max = 430, .key = BTN_5 },
109};
110
111static const int arizona_micd_levels[] = {
112 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
113 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
114 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
115 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
116 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100117};
118
Mark Brown325c6422012-06-28 13:08:30 +0100119#define ARIZONA_CABLE_MECHANICAL 0
120#define ARIZONA_CABLE_MICROPHONE 1
121#define ARIZONA_CABLE_HEADPHONE 2
Mark Brown4f340332013-01-11 08:55:43 +0900122#define ARIZONA_CABLE_LINEOUT 3
Mark Brownf2c32a82012-06-24 12:09:45 +0100123
124static const char *arizona_cable[] = {
Mark Brown325c6422012-06-28 13:08:30 +0100125 "Mechanical",
126 "Microphone",
127 "Headphone",
Mark Brown4f340332013-01-11 08:55:43 +0900128 "Line-out",
Mark Brownf2c32a82012-06-24 12:09:45 +0100129 NULL,
130};
131
Mark Brown9dd5e532013-04-01 19:09:45 +0100132static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
133
Mark Brown03409072013-02-12 13:00:31 +0000134static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
135 unsigned int magic)
136{
137 struct arizona *arizona = info->arizona;
Mark Brown03409072013-02-12 13:00:31 +0000138 int ret;
139
140 mutex_lock(&arizona->dapm->card->dapm_mutex);
141
Mark Browndf8c3db2013-02-22 18:38:03 +0000142 arizona->hpdet_magic = magic;
143
144 /* Keep the HP output stages disabled while doing the magic */
145 if (magic) {
146 ret = regmap_update_bits(arizona->regmap,
147 ARIZONA_OUTPUT_ENABLES_1,
148 ARIZONA_OUT1L_ENA |
149 ARIZONA_OUT1R_ENA, 0);
150 if (ret != 0)
151 dev_warn(arizona->dev,
152 "Failed to disable headphone outputs: %d\n",
153 ret);
Mark Brown03409072013-02-12 13:00:31 +0000154 }
155
Mark Browndf8c3db2013-02-22 18:38:03 +0000156 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
157 magic);
158 if (ret != 0)
159 dev_warn(arizona->dev, "Failed to do magic: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000160 ret);
161
Mark Browndf8c3db2013-02-22 18:38:03 +0000162 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
163 magic);
164 if (ret != 0)
165 dev_warn(arizona->dev, "Failed to do magic: %d\n",
166 ret);
167
168 /* Restore the desired state while not doing the magic */
169 if (!magic) {
170 ret = regmap_update_bits(arizona->regmap,
171 ARIZONA_OUTPUT_ENABLES_1,
172 ARIZONA_OUT1L_ENA |
173 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000174 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000175 dev_warn(arizona->dev,
176 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000177 ret);
178 }
179
180 mutex_unlock(&arizona->dapm->card->dapm_mutex);
181}
182
Mark Brownf2c32a82012-06-24 12:09:45 +0100183static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
184{
185 struct arizona *arizona = info->arizona;
186
Mark Brown6fed4d82013-04-01 22:03:06 +0100187 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800188
Mark Browncd74f7b2012-11-27 16:14:26 +0900189 if (arizona->pdata.micd_pol_gpio > 0)
190 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
191 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100192 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
193 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100194 info->micd_modes[mode].bias <<
195 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100196 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
197 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
198
199 info->micd_mode = mode;
200
201 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
202}
203
Mark Brownbbbd46e2013-01-10 19:38:43 +0000204static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
205{
Charles Keepax41024242013-09-23 14:33:59 +0100206 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000207 case 1:
208 return "MICBIAS1";
209 case 2:
210 return "MICBIAS2";
211 case 3:
212 return "MICBIAS3";
213 default:
214 return "MICVDD";
215 }
216}
217
218static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
219{
220 struct arizona *arizona = info->arizona;
221 const char *widget = arizona_extcon_get_micbias(info);
222 struct snd_soc_dapm_context *dapm = arizona->dapm;
223 int ret;
224
225 mutex_lock(&dapm->card->dapm_mutex);
226
227 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
228 if (ret != 0)
229 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
230 widget, ret);
231
232 mutex_unlock(&dapm->card->dapm_mutex);
233
234 snd_soc_dapm_sync(dapm);
235
236 if (!arizona->pdata.micd_force_micbias) {
237 mutex_lock(&dapm->card->dapm_mutex);
238
239 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
240 if (ret != 0)
241 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
242 widget, ret);
243
244 mutex_unlock(&dapm->card->dapm_mutex);
245
246 snd_soc_dapm_sync(dapm);
247 }
248}
249
Mark Brown9b1270c2013-01-11 08:55:46 +0900250static void arizona_start_mic(struct arizona_extcon_info *info)
251{
252 struct arizona *arizona = info->arizona;
253 bool change;
254 int ret;
255
Mark Brown9b1270c2013-01-11 08:55:46 +0900256 /* Microphone detection can't use idle mode */
257 pm_runtime_get(info->dev);
258
Mark Brownbbbd46e2013-01-10 19:38:43 +0000259 if (info->detecting) {
260 ret = regulator_allow_bypass(info->micvdd, false);
261 if (ret != 0) {
262 dev_err(arizona->dev,
263 "Failed to regulate MICVDD: %d\n",
264 ret);
265 }
266 }
267
Mark Brown9b1270c2013-01-11 08:55:46 +0900268 ret = regulator_enable(info->micvdd);
269 if (ret != 0) {
270 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
271 ret);
272 }
273
274 if (info->micd_reva) {
275 regmap_write(arizona->regmap, 0x80, 0x3);
276 regmap_write(arizona->regmap, 0x294, 0);
277 regmap_write(arizona->regmap, 0x80, 0x0);
278 }
279
280 regmap_update_bits(arizona->regmap,
281 ARIZONA_ACCESSORY_DETECT_MODE_1,
282 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
283
Mark Brownbbbd46e2013-01-10 19:38:43 +0000284 arizona_extcon_pulse_micbias(info);
285
Mark Brown9b1270c2013-01-11 08:55:46 +0900286 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
287 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
288 &change);
289 if (!change) {
290 regulator_disable(info->micvdd);
291 pm_runtime_put_autosuspend(info->dev);
292 }
293}
294
295static void arizona_stop_mic(struct arizona_extcon_info *info)
296{
297 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000298 const char *widget = arizona_extcon_get_micbias(info);
299 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900300 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000301 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900302
303 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
304 ARIZONA_MICD_ENA, 0,
305 &change);
306
Mark Brownbbbd46e2013-01-10 19:38:43 +0000307 mutex_lock(&dapm->card->dapm_mutex);
308
309 ret = snd_soc_dapm_disable_pin(dapm, widget);
310 if (ret != 0)
311 dev_warn(arizona->dev,
312 "Failed to disable %s: %d\n",
313 widget, ret);
314
315 mutex_unlock(&dapm->card->dapm_mutex);
316
317 snd_soc_dapm_sync(dapm);
318
Mark Brown9b1270c2013-01-11 08:55:46 +0900319 if (info->micd_reva) {
320 regmap_write(arizona->regmap, 0x80, 0x3);
321 regmap_write(arizona->regmap, 0x294, 2);
322 regmap_write(arizona->regmap, 0x80, 0x0);
323 }
324
Mark Brownbbbd46e2013-01-10 19:38:43 +0000325 ret = regulator_allow_bypass(info->micvdd, true);
326 if (ret != 0) {
327 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
328 ret);
329 }
330
Mark Brown9b1270c2013-01-11 08:55:46 +0900331 if (change) {
332 regulator_disable(info->micvdd);
333 pm_runtime_mark_last_busy(info->dev);
334 pm_runtime_put_autosuspend(info->dev);
335 }
336}
337
Mark Brown4f340332013-01-11 08:55:43 +0900338static struct {
339 unsigned int factor_a;
340 unsigned int factor_b;
341} arizona_hpdet_b_ranges[] = {
342 { 5528, 362464 },
343 { 11084, 6186851 },
344 { 11065, 65460395 },
345};
346
347static struct {
348 int min;
349 int max;
350} arizona_hpdet_c_ranges[] = {
351 { 0, 30 },
352 { 8, 100 },
353 { 100, 1000 },
354 { 1000, 10000 },
355};
356
357static int arizona_hpdet_read(struct arizona_extcon_info *info)
358{
359 struct arizona *arizona = info->arizona;
360 unsigned int val, range;
361 int ret;
362
363 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
364 if (ret != 0) {
365 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
366 ret);
367 return ret;
368 }
369
370 switch (info->hpdet_ip) {
371 case 0:
372 if (!(val & ARIZONA_HP_DONE)) {
373 dev_err(arizona->dev, "HPDET did not complete: %x\n",
374 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900375 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900376 }
377
378 val &= ARIZONA_HP_LVL_MASK;
379 break;
380
381 case 1:
382 if (!(val & ARIZONA_HP_DONE_B)) {
383 dev_err(arizona->dev, "HPDET did not complete: %x\n",
384 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900385 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900386 }
387
388 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
389 if (ret != 0) {
390 dev_err(arizona->dev, "Failed to read HP value: %d\n",
391 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900392 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900393 }
394
395 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
396 &range);
397 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
398 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
399
400 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100401 (val < 100 || val >= 0x3fb)) {
Mark Brown4f340332013-01-11 08:55:43 +0900402 range++;
403 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
404 range);
405 regmap_update_bits(arizona->regmap,
406 ARIZONA_HEADPHONE_DETECT_1,
407 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
408 range <<
409 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
410 return -EAGAIN;
411 }
412
413 /* If we go out of range report top of range */
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100414 if (val < 100 || val >= 0x3fb) {
Mark Brown4f340332013-01-11 08:55:43 +0900415 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100416 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900417 }
418
419 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
420 val, range);
421
422 val = arizona_hpdet_b_ranges[range].factor_b
423 / ((val * 100) -
424 arizona_hpdet_b_ranges[range].factor_a);
425 break;
426
427 default:
428 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
429 info->hpdet_ip);
430 case 2:
431 if (!(val & ARIZONA_HP_DONE_B)) {
432 dev_err(arizona->dev, "HPDET did not complete: %x\n",
433 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900434 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900435 }
436
437 val &= ARIZONA_HP_LVL_B_MASK;
438
439 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
440 &range);
441 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
442 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
443
444 /* Skip up or down a range? */
445 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
446 range--;
447 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
448 arizona_hpdet_c_ranges[range].min,
449 arizona_hpdet_c_ranges[range].max);
450 regmap_update_bits(arizona->regmap,
451 ARIZONA_HEADPHONE_DETECT_1,
452 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
453 range <<
454 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
455 return -EAGAIN;
456 }
457
458 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
459 (val >= arizona_hpdet_c_ranges[range].max)) {
460 range++;
461 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
462 arizona_hpdet_c_ranges[range].min,
463 arizona_hpdet_c_ranges[range].max);
464 regmap_update_bits(arizona->regmap,
465 ARIZONA_HEADPHONE_DETECT_1,
466 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
467 range <<
468 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
469 return -EAGAIN;
470 }
471 }
472
473 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
474 return val;
475}
476
Mark Brown9c2ba272013-02-25 23:42:31 +0000477static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
478 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900479{
480 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900481 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900482
483 /*
484 * If we're using HPDET for accessory identification we need
485 * to take multiple measurements, step through them in sequence.
486 */
487 if (arizona->pdata.hpdet_acc_id) {
488 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900489
490 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000491 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900492 dev_dbg(arizona->dev, "Measuring mic\n");
493
494 regmap_update_bits(arizona->regmap,
495 ARIZONA_ACCESSORY_DETECT_MODE_1,
496 ARIZONA_ACCDET_MODE_MASK |
497 ARIZONA_ACCDET_SRC,
498 ARIZONA_ACCDET_MODE_HPR |
499 info->micd_modes[0].src);
500
501 gpio_set_value_cansleep(id_gpio, 1);
502
Mark Browndd235ee2013-01-11 08:55:51 +0900503 regmap_update_bits(arizona->regmap,
504 ARIZONA_HEADPHONE_DETECT_1,
505 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
506 return -EAGAIN;
507 }
508
509 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000510 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
511 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000512
513 /* Take the headphone impedance for the main report */
514 *reading = info->hpdet_res[0];
515
Mark Brown9dd5e532013-04-01 19:09:45 +0100516 /* Sometimes we get false readings due to slow insert */
517 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
518 dev_dbg(arizona->dev, "Retrying high impedance\n");
519 info->num_hpdet_res = 0;
520 info->hpdet_retried = true;
521 arizona_start_hpdet_acc_id(info);
522 pm_runtime_put(info->dev);
523 return -EAGAIN;
524 }
525
Mark Brown1eda6aa2013-01-11 08:55:54 +0900526 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530527 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900528 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000529 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900530 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000531 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000532 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900533 } else {
534 dev_dbg(arizona->dev, "Detected headphone\n");
535 }
536
537 /* Make sure everything is reset back to the real polarity */
538 regmap_update_bits(arizona->regmap,
539 ARIZONA_ACCESSORY_DETECT_MODE_1,
540 ARIZONA_ACCDET_SRC,
541 info->micd_modes[0].src);
542 }
543
544 return 0;
545}
546
Mark Brown4f340332013-01-11 08:55:43 +0900547static irqreturn_t arizona_hpdet_irq(int irq, void *data)
548{
549 struct arizona_extcon_info *info = data;
550 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900551 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900552 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900553 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000554 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900555
556 mutex_lock(&info->lock);
557
558 /* If we got a spurious IRQ for some reason then ignore it */
559 if (!info->hpdet_active) {
560 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
561 mutex_unlock(&info->lock);
562 return IRQ_NONE;
563 }
564
565 /* If the cable was removed while measuring ignore the result */
566 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
567 if (ret < 0) {
568 dev_err(arizona->dev, "Failed to check cable state: %d\n",
569 ret);
570 goto out;
571 } else if (!ret) {
572 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
573 goto done;
574 }
575
576 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900577 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900578 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900579 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900580 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900581 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900582
583 /* Reset back to starting range */
584 regmap_update_bits(arizona->regmap,
585 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900586 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
587 0);
588
Mark Brown9c2ba272013-02-25 23:42:31 +0000589 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900590 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900591 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900592 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900593 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900594
595 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900596 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900597 report = ARIZONA_CABLE_LINEOUT;
598 else
599 report = ARIZONA_CABLE_HEADPHONE;
600
601 ret = extcon_set_cable_state_(&info->edev, report, true);
602 if (ret != 0)
603 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
604 ret);
605
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000606done:
607 /* Reset back to starting range */
608 regmap_update_bits(arizona->regmap,
609 ARIZONA_HEADPHONE_DETECT_1,
610 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
611 0);
612
Mark Brown03409072013-02-12 13:00:31 +0000613 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900614
Mark Brown1eda6aa2013-01-11 08:55:54 +0900615 if (id_gpio)
616 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900617
618 /* Revert back to MICDET mode */
619 regmap_update_bits(arizona->regmap,
620 ARIZONA_ACCESSORY_DETECT_MODE_1,
621 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
622
623 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000624 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900625 arizona_start_mic(info);
626
627 if (info->hpdet_active) {
628 pm_runtime_put_autosuspend(info->dev);
629 info->hpdet_active = false;
630 }
631
Mark Brownbf14ee52013-02-05 20:20:17 +0000632 info->hpdet_done = true;
633
Mark Brown4f340332013-01-11 08:55:43 +0900634out:
635 mutex_unlock(&info->lock);
636
637 return IRQ_HANDLED;
638}
639
640static void arizona_identify_headphone(struct arizona_extcon_info *info)
641{
642 struct arizona *arizona = info->arizona;
643 int ret;
644
Mark Brownbf14ee52013-02-05 20:20:17 +0000645 if (info->hpdet_done)
646 return;
647
Mark Brown4f340332013-01-11 08:55:43 +0900648 dev_dbg(arizona->dev, "Starting HPDET\n");
649
650 /* Make sure we keep the device enabled during the measurement */
651 pm_runtime_get(info->dev);
652
653 info->hpdet_active = true;
654
655 if (info->mic)
656 arizona_stop_mic(info);
657
Mark Brown03409072013-02-12 13:00:31 +0000658 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900659
660 ret = regmap_update_bits(arizona->regmap,
661 ARIZONA_ACCESSORY_DETECT_MODE_1,
662 ARIZONA_ACCDET_MODE_MASK,
663 ARIZONA_ACCDET_MODE_HPL);
664 if (ret != 0) {
665 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
666 goto err;
667 }
668
669 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
670 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
671 if (ret != 0) {
672 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
673 ret);
674 goto err;
675 }
676
677 return;
678
679err:
680 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
681 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
682
683 /* Just report headphone */
684 ret = extcon_update_state(&info->edev,
685 1 << ARIZONA_CABLE_HEADPHONE,
686 1 << ARIZONA_CABLE_HEADPHONE);
687 if (ret != 0)
688 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
689
690 if (info->mic)
691 arizona_start_mic(info);
692
693 info->hpdet_active = false;
694}
Mark Browndd235ee2013-01-11 08:55:51 +0900695
696static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
697{
698 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000699 int hp_reading = 32;
700 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900701 int ret;
702
703 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
704
705 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000706 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900707
708 info->hpdet_active = true;
709
Mark Brown03409072013-02-12 13:00:31 +0000710 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900711
712 ret = regmap_update_bits(arizona->regmap,
713 ARIZONA_ACCESSORY_DETECT_MODE_1,
714 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
715 info->micd_modes[0].src |
716 ARIZONA_ACCDET_MODE_HPL);
717 if (ret != 0) {
718 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
719 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900720 }
721
Mark Brown9c2ba272013-02-25 23:42:31 +0000722 if (arizona->pdata.hpdet_acc_id_line) {
723 ret = regmap_update_bits(arizona->regmap,
724 ARIZONA_HEADPHONE_DETECT_1,
725 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
726 if (ret != 0) {
727 dev_err(arizona->dev,
728 "Can't start HPDETL measurement: %d\n",
729 ret);
730 goto err;
731 }
732 } else {
733 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900734 }
735
736 return;
737
738err:
739 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
740 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
741
742 /* Just report headphone */
743 ret = extcon_update_state(&info->edev,
744 1 << ARIZONA_CABLE_HEADPHONE,
745 1 << ARIZONA_CABLE_HEADPHONE);
746 if (ret != 0)
747 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
748
Mark Brown4f340332013-01-11 08:55:43 +0900749 info->hpdet_active = false;
750}
751
Mark Brown939c5672013-04-01 19:17:34 +0100752static void arizona_micd_timeout_work(struct work_struct *work)
753{
754 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900755 struct arizona_extcon_info,
756 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100757
758 mutex_lock(&info->lock);
759
760 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
761 arizona_identify_headphone(info);
762
763 info->detecting = false;
764
765 arizona_stop_mic(info);
766
767 mutex_unlock(&info->lock);
768}
769
Mark Browncd59e792013-04-01 19:21:48 +0100770static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100771{
Mark Browncd59e792013-04-01 19:21:48 +0100772 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900773 struct arizona_extcon_info,
774 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100775 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100776 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100777 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100778
Mark Brown939c5672013-04-01 19:17:34 +0100779 cancel_delayed_work_sync(&info->micd_timeout_work);
780
Mark Brownf2c32a82012-06-24 12:09:45 +0100781 mutex_lock(&info->lock);
782
Charles Keepaxffae24f2013-11-14 16:18:21 +0000783 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100784 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
785 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900786 dev_err(arizona->dev,
787 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100788 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100789 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100790 }
791
792 dev_dbg(arizona->dev, "MICDET: %x\n", val);
793
794 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900795 dev_warn(arizona->dev,
796 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100797 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100798 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100799 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100800 }
801
Charles Keepaxffae24f2013-11-14 16:18:21 +0000802 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100803 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100804 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100805 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100806 }
807
808 /* Due to jack detect this should never happen */
809 if (!(val & ARIZONA_MICD_STS)) {
810 dev_warn(arizona->dev, "Detected open circuit\n");
811 info->detecting = false;
812 goto handled;
813 }
814
815 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000816 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900817 arizona_identify_headphone(info);
818
Mark Brown325c6422012-06-28 13:08:30 +0100819 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900820 1 << ARIZONA_CABLE_MICROPHONE,
821 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100822
823 if (ret != 0)
824 dev_err(arizona->dev, "Headset report failed: %d\n",
825 ret);
826
Mark Brownbbbd46e2013-01-10 19:38:43 +0000827 /* Don't need to regulate for button detection */
828 ret = regulator_allow_bypass(info->micvdd, false);
829 if (ret != 0) {
830 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
831 ret);
832 }
833
Mark Brownf2c32a82012-06-24 12:09:45 +0100834 info->mic = true;
835 info->detecting = false;
836 goto handled;
837 }
838
839 /* If we detected a lower impedence during initial startup
840 * then we probably have the wrong polarity, flip it. Don't
841 * do this for the lowest impedences to speed up detection of
842 * plain headphones. If both polarities report a low
843 * impedence then give up and report headphones.
844 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000845 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800846 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900847 dev_dbg(arizona->dev, "Detected HP/line\n");
848 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100849
Mark Brown4f340332013-01-11 08:55:43 +0900850 info->detecting = false;
851
852 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100853 } else {
854 info->micd_mode++;
855 if (info->micd_mode == info->micd_num_modes)
856 info->micd_mode = 0;
857 arizona_extcon_set_mode(info, info->micd_mode);
858
859 info->jack_flips++;
860 }
861
862 goto handled;
863 }
864
865 /*
866 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100867 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100868 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000869 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100870 if (info->mic) {
871 dev_dbg(arizona->dev, "Mic button detected\n");
872
Mark Brown34efe4d2012-07-20 17:07:29 +0100873 lvl = val & ARIZONA_MICD_LVL_MASK;
874 lvl >>= ARIZONA_MICD_LVL_SHIFT;
875
Mark Brown41a57852013-04-01 19:18:18 +0100876 for (i = 0; i < info->num_micd_ranges; i++)
877 input_report_key(info->input,
878 info->micd_ranges[i].key, 0);
879
Mark Brown6fed4d82013-04-01 22:03:06 +0100880 WARN_ON(!lvl);
881 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
882 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
883 key = info->micd_ranges[ffs(lvl) - 1].key;
884 input_report_key(info->input, key, 1);
885 input_sync(info->input);
886 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100887
Mark Brownf2c32a82012-06-24 12:09:45 +0100888 } else if (info->detecting) {
889 dev_dbg(arizona->dev, "Headphone detected\n");
890 info->detecting = false;
891 arizona_stop_mic(info);
892
Mark Brown4f340332013-01-11 08:55:43 +0900893 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100894 } else {
895 dev_warn(arizona->dev, "Button with no mic: %x\n",
896 val);
897 }
898 } else {
899 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100900 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100901 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100902 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100903 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000904 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100905 }
906
907handled:
Mark Brown939c5672013-04-01 19:17:34 +0100908 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100909 queue_delayed_work(system_power_efficient_wq,
910 &info->micd_timeout_work,
911 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100912
Mark Brownf2c32a82012-06-24 12:09:45 +0100913 pm_runtime_mark_last_busy(info->dev);
914 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100915}
916
917static irqreturn_t arizona_micdet(int irq, void *data)
918{
919 struct arizona_extcon_info *info = data;
920 struct arizona *arizona = info->arizona;
921 int debounce = arizona->pdata.micd_detect_debounce;
922
923 cancel_delayed_work_sync(&info->micd_detect_work);
924 cancel_delayed_work_sync(&info->micd_timeout_work);
925
926 mutex_lock(&info->lock);
927 if (!info->detecting)
928 debounce = 0;
929 mutex_unlock(&info->lock);
930
931 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100932 queue_delayed_work(system_power_efficient_wq,
933 &info->micd_detect_work,
934 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100935 else
936 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100937
938 return IRQ_HANDLED;
939}
940
Mark Brown0e27bd32013-02-05 21:00:15 +0000941static void arizona_hpdet_work(struct work_struct *work)
942{
943 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900944 struct arizona_extcon_info,
945 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000946
947 mutex_lock(&info->lock);
948 arizona_start_hpdet_acc_id(info);
949 mutex_unlock(&info->lock);
950}
951
Mark Brownf2c32a82012-06-24 12:09:45 +0100952static irqreturn_t arizona_jackdet(int irq, void *data)
953{
954 struct arizona_extcon_info *info = data;
955 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900956 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100957 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100958 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100959
Mark Brown939c5672013-04-01 19:17:34 +0100960 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
961 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100962
Mark Browna3e20782013-04-01 19:05:27 +0100963 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000964
Mark Brownf2c32a82012-06-24 12:09:45 +0100965 mutex_lock(&info->lock);
966
Mark Brown92a49872013-01-11 08:55:39 +0900967 if (arizona->pdata.jd_gpio5) {
968 mask = ARIZONA_MICD_CLAMP_STS;
969 present = 0;
970 } else {
971 mask = ARIZONA_JD1_STS;
972 present = ARIZONA_JD1_STS;
973 }
974
Mark Brownf2c32a82012-06-24 12:09:45 +0100975 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
976 if (ret != 0) {
977 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
978 ret);
979 mutex_unlock(&info->lock);
980 pm_runtime_put_autosuspend(info->dev);
981 return IRQ_NONE;
982 }
983
Mark Browna3e20782013-04-01 19:05:27 +0100984 val &= mask;
985 if (val == info->last_jackdet) {
986 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +0100987 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100988 queue_delayed_work(system_power_efficient_wq,
989 &info->hpdet_work,
990 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +0100991
Chanwoo Choic2275d22013-08-23 10:21:37 +0900992 if (cancelled_mic) {
993 int micd_timeout = info->micd_timeout;
994
Mark Browndf9a5ab2013-07-18 22:42:22 +0100995 queue_delayed_work(system_power_efficient_wq,
996 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900997 msecs_to_jiffies(micd_timeout));
998 }
Mark Brown939c5672013-04-01 19:17:34 +0100999
Mark Browna3e20782013-04-01 19:05:27 +01001000 goto out;
1001 }
1002 info->last_jackdet = val;
1003
1004 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001005 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +01001006 ret = extcon_set_cable_state_(&info->edev,
1007 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001008
1009 if (ret != 0)
1010 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1011 ret);
1012
Mark Browndd235ee2013-01-11 08:55:51 +09001013 if (!arizona->pdata.hpdet_acc_id) {
1014 info->detecting = true;
1015 info->mic = false;
1016 info->jack_flips = 0;
1017
1018 arizona_start_mic(info);
1019 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001020 queue_delayed_work(system_power_efficient_wq,
1021 &info->hpdet_work,
1022 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001023 }
Mark Brown4e616872013-01-15 22:09:20 +09001024
1025 regmap_update_bits(arizona->regmap,
1026 ARIZONA_JACK_DETECT_DEBOUNCE,
1027 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001028 } else {
1029 dev_dbg(arizona->dev, "Detected jack removal\n");
1030
1031 arizona_stop_mic(info);
1032
Mark Browndd235ee2013-01-11 08:55:51 +09001033 info->num_hpdet_res = 0;
1034 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1035 info->hpdet_res[i] = 0;
1036 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001037 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001038 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001039
Mark Brown6fed4d82013-04-01 22:03:06 +01001040 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001041 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001042 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001043 input_sync(info->input);
1044
Mark Brownf2c32a82012-06-24 12:09:45 +01001045 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
1046 if (ret != 0)
1047 dev_err(arizona->dev, "Removal report failed: %d\n",
1048 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001049
1050 regmap_update_bits(arizona->regmap,
1051 ARIZONA_JACK_DETECT_DEBOUNCE,
1052 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1053 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001054 }
1055
Mark Brown7abd4e22013-04-01 19:25:55 +01001056 if (arizona->pdata.micd_timeout)
1057 info->micd_timeout = arizona->pdata.micd_timeout;
1058 else
1059 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1060
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001061out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001062 /* Clear trig_sts to make sure DCVDD is not forced up */
1063 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1064 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1065 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1066 ARIZONA_JD1_FALL_TRIG_STS |
1067 ARIZONA_JD1_RISE_TRIG_STS);
1068
Mark Brownf2c32a82012-06-24 12:09:45 +01001069 mutex_unlock(&info->lock);
1070
1071 pm_runtime_mark_last_busy(info->dev);
1072 pm_runtime_put_autosuspend(info->dev);
1073
1074 return IRQ_HANDLED;
1075}
1076
Mark Brown6fed4d82013-04-01 22:03:06 +01001077/* Map a level onto a slot in the register bank */
1078static void arizona_micd_set_level(struct arizona *arizona, int index,
1079 unsigned int level)
1080{
1081 int reg;
1082 unsigned int mask;
1083
1084 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1085
1086 if (!(index % 2)) {
1087 mask = 0x3f00;
1088 level <<= 8;
1089 } else {
1090 mask = 0x3f;
1091 }
1092
1093 /* Program the level itself */
1094 regmap_update_bits(arizona->regmap, reg, mask, level);
1095}
1096
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001097static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001098{
1099 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001100 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001101 struct arizona_extcon_info *info;
Mark Browne56a0a572013-04-01 19:03:52 +01001102 unsigned int val;
Mark Brown92a49872013-01-11 08:55:39 +09001103 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001104 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001105
Mark Brownbbbd46e2013-01-10 19:38:43 +00001106 if (!arizona->dapm || !arizona->dapm->card)
1107 return -EPROBE_DEFER;
1108
Mark Brownf2c32a82012-06-24 12:09:45 +01001109 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1110 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001111 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +01001112 ret = -ENOMEM;
1113 goto err;
1114 }
1115
1116 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1117 if (IS_ERR(info->micvdd)) {
1118 ret = PTR_ERR(info->micvdd);
1119 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
1120 goto err;
1121 }
1122
1123 mutex_init(&info->lock);
1124 info->arizona = arizona;
1125 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001126 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001127 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001128 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001129 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001130 platform_set_drvdata(pdev, info);
1131
1132 switch (arizona->type) {
1133 case WM5102:
1134 switch (arizona->rev) {
1135 case 0:
1136 info->micd_reva = true;
1137 break;
1138 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001139 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001140 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001141 break;
1142 }
1143 break;
1144 default:
1145 break;
1146 }
1147
1148 info->edev.name = "Headset Jack";
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001149 info->edev.dev.parent = arizona->dev;
Mark Brownf2c32a82012-06-24 12:09:45 +01001150 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001151
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001152 ret = extcon_dev_register(&info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001153 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001154 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001155 ret);
1156 goto err;
1157 }
1158
Mark Brown6fed4d82013-04-01 22:03:06 +01001159 info->input = devm_input_allocate_device(&pdev->dev);
1160 if (!info->input) {
1161 dev_err(arizona->dev, "Can't allocate input dev\n");
1162 ret = -ENOMEM;
1163 goto err_register;
1164 }
1165
1166 info->input->name = "Headset";
1167 info->input->phys = "arizona/extcon";
1168 info->input->dev.parent = &pdev->dev;
1169
Mark Brownf2c32a82012-06-24 12:09:45 +01001170 if (pdata->num_micd_configs) {
1171 info->micd_modes = pdata->micd_configs;
1172 info->micd_num_modes = pdata->num_micd_configs;
1173 } else {
1174 info->micd_modes = micd_default_modes;
1175 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1176 }
1177
1178 if (arizona->pdata.micd_pol_gpio > 0) {
1179 if (info->micd_modes[0].gpio)
1180 mode = GPIOF_OUT_INIT_HIGH;
1181 else
1182 mode = GPIOF_OUT_INIT_LOW;
1183
1184 ret = devm_gpio_request_one(&pdev->dev,
1185 arizona->pdata.micd_pol_gpio,
1186 mode,
1187 "MICD polarity");
1188 if (ret != 0) {
1189 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1190 arizona->pdata.micd_pol_gpio, ret);
1191 goto err_register;
1192 }
1193 }
1194
Mark Brown1eda6aa2013-01-11 08:55:54 +09001195 if (arizona->pdata.hpdet_id_gpio > 0) {
1196 ret = devm_gpio_request_one(&pdev->dev,
1197 arizona->pdata.hpdet_id_gpio,
1198 GPIOF_OUT_INIT_LOW,
1199 "HPDET");
1200 if (ret != 0) {
1201 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1202 arizona->pdata.hpdet_id_gpio, ret);
1203 goto err_register;
1204 }
1205 }
1206
Mark Brownb17e5462013-01-11 08:55:24 +09001207 if (arizona->pdata.micd_bias_start_time)
1208 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1209 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1210 arizona->pdata.micd_bias_start_time
1211 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1212
Mark Brown2e033db2013-01-21 17:36:33 +09001213 if (arizona->pdata.micd_rate)
1214 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1215 ARIZONA_MICD_RATE_MASK,
1216 arizona->pdata.micd_rate
1217 << ARIZONA_MICD_RATE_SHIFT);
1218
1219 if (arizona->pdata.micd_dbtime)
1220 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1221 ARIZONA_MICD_DBTIME_MASK,
1222 arizona->pdata.micd_dbtime
1223 << ARIZONA_MICD_DBTIME_SHIFT);
1224
Mark Brown6fed4d82013-04-01 22:03:06 +01001225 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1226
1227 if (arizona->pdata.num_micd_ranges) {
1228 info->micd_ranges = pdata->micd_ranges;
1229 info->num_micd_ranges = pdata->num_micd_ranges;
1230 } else {
1231 info->micd_ranges = micd_default_ranges;
1232 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1233 }
1234
1235 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1236 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1237 arizona->pdata.num_micd_ranges);
1238 }
1239
1240 if (info->num_micd_ranges > 1) {
1241 for (i = 1; i < info->num_micd_ranges; i++) {
1242 if (info->micd_ranges[i - 1].max >
1243 info->micd_ranges[i].max) {
1244 dev_err(arizona->dev,
1245 "MICD ranges must be sorted\n");
1246 ret = -EINVAL;
1247 goto err_input;
1248 }
1249 }
1250 }
1251
1252 /* Disable all buttons by default */
1253 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1254 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1255
1256 /* Set up all the buttons the user specified */
1257 for (i = 0; i < info->num_micd_ranges; i++) {
1258 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1259 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1260 break;
1261
1262 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1263 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1264 info->micd_ranges[i].max);
1265 ret = -EINVAL;
1266 goto err_input;
1267 }
1268
1269 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1270 arizona_micd_levels[j], i);
1271
1272 arizona_micd_set_level(arizona, i, j);
1273 input_set_capability(info->input, EV_KEY,
1274 info->micd_ranges[i].key);
1275
1276 /* Enable reporting of that range */
1277 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1278 1 << i, 1 << i);
1279 }
1280
1281 /* Set all the remaining keys to a maximum */
1282 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1283 arizona_micd_set_level(arizona, i, 0x3f);
1284
Mark Browndab63eb2013-01-11 08:55:36 +09001285 /*
Mark Brown92a49872013-01-11 08:55:39 +09001286 * If we have a clamp use it, activating in conjunction with
1287 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001288 */
1289 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001290 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a572013-04-01 19:03:52 +01001291 /* Put the GPIO into input mode with optional pull */
1292 val = 0xc101;
1293 if (arizona->pdata.jd_gpio5_nopull)
1294 val &= ~ARIZONA_GPN_PU;
1295
Mark Brown92a49872013-01-11 08:55:39 +09001296 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a572013-04-01 19:03:52 +01001297 val);
Mark Brown92a49872013-01-11 08:55:39 +09001298
1299 regmap_update_bits(arizona->regmap,
1300 ARIZONA_MICD_CLAMP_CONTROL,
1301 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1302 } else {
1303 regmap_update_bits(arizona->regmap,
1304 ARIZONA_MICD_CLAMP_CONTROL,
1305 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1306 }
1307
Mark Browndab63eb2013-01-11 08:55:36 +09001308 regmap_update_bits(arizona->regmap,
1309 ARIZONA_JACK_DETECT_DEBOUNCE,
1310 ARIZONA_MICD_CLAMP_DB,
1311 ARIZONA_MICD_CLAMP_DB);
1312 }
1313
Mark Brownf2c32a82012-06-24 12:09:45 +01001314 arizona_extcon_set_mode(info, 0);
1315
1316 pm_runtime_enable(&pdev->dev);
1317 pm_runtime_idle(&pdev->dev);
1318 pm_runtime_get_sync(&pdev->dev);
1319
Mark Brown92a49872013-01-11 08:55:39 +09001320 if (arizona->pdata.jd_gpio5) {
1321 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1322 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1323 } else {
1324 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1325 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1326 }
1327
1328 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001329 "JACKDET rise", arizona_jackdet, info);
1330 if (ret != 0) {
1331 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1332 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001333 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001334 }
1335
Mark Brown92a49872013-01-11 08:55:39 +09001336 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001337 if (ret != 0) {
1338 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1339 ret);
1340 goto err_rise;
1341 }
1342
Mark Brown92a49872013-01-11 08:55:39 +09001343 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001344 "JACKDET fall", arizona_jackdet, info);
1345 if (ret != 0) {
1346 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1347 goto err_rise_wake;
1348 }
1349
Mark Brown92a49872013-01-11 08:55:39 +09001350 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001351 if (ret != 0) {
1352 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1353 ret);
1354 goto err_fall;
1355 }
1356
1357 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1358 "MICDET", arizona_micdet, info);
1359 if (ret != 0) {
1360 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1361 goto err_fall_wake;
1362 }
1363
Mark Brown4f340332013-01-11 08:55:43 +09001364 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1365 "HPDET", arizona_hpdet_irq, info);
1366 if (ret != 0) {
1367 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1368 goto err_micdet;
1369 }
1370
Mark Brownf2c32a82012-06-24 12:09:45 +01001371 arizona_clk32k_enable(arizona);
1372 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1373 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1374 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1375 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1376
Mark Brownb8575a12012-09-07 17:01:15 +08001377 ret = regulator_allow_bypass(info->micvdd, true);
1378 if (ret != 0)
1379 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1380 ret);
1381
Mark Brownf2c32a82012-06-24 12:09:45 +01001382 pm_runtime_put(&pdev->dev);
1383
Mark Brown34efe4d2012-07-20 17:07:29 +01001384 ret = input_register_device(info->input);
1385 if (ret) {
1386 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001387 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001388 }
1389
Mark Brownf2c32a82012-06-24 12:09:45 +01001390 return 0;
1391
Mark Brown4f340332013-01-11 08:55:43 +09001392err_hpdet:
1393 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001394err_micdet:
1395 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001396err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001397 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001398err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001399 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001400err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001401 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001402err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001403 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001404err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001405err_register:
1406 pm_runtime_disable(&pdev->dev);
1407 extcon_dev_unregister(&info->edev);
1408err:
1409 return ret;
1410}
1411
Bill Pemberton93ed0322012-11-19 13:25:49 -05001412static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001413{
1414 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1415 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001416 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001417
1418 pm_runtime_disable(&pdev->dev);
1419
Mark Browndab63eb2013-01-11 08:55:36 +09001420 regmap_update_bits(arizona->regmap,
1421 ARIZONA_MICD_CLAMP_CONTROL,
1422 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1423
Mark Brown92a49872013-01-11 08:55:39 +09001424 if (arizona->pdata.jd_gpio5) {
1425 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1426 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1427 } else {
1428 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1429 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1430 }
1431
1432 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1433 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1434 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001435 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001436 arizona_free_irq(arizona, jack_irq_rise, info);
1437 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001438 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001439 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1440 ARIZONA_JD1_ENA, 0);
1441 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001442 extcon_dev_unregister(&info->edev);
1443
1444 return 0;
1445}
1446
1447static struct platform_driver arizona_extcon_driver = {
1448 .driver = {
1449 .name = "arizona-extcon",
1450 .owner = THIS_MODULE,
1451 },
1452 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001453 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001454};
1455
1456module_platform_driver(arizona_extcon_driver);
1457
1458MODULE_DESCRIPTION("Arizona Extcon driver");
1459MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1460MODULE_LICENSE("GPL");
1461MODULE_ALIAS("platform:extcon-arizona");