blob: 4487bdaf9b439c3769341c4233def0762c2a5526 [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
Charles Keepax91414612013-11-14 16:18:24 +0000444 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900445 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
446 (val >= arizona_hpdet_c_ranges[range].max)) {
447 range++;
448 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
449 arizona_hpdet_c_ranges[range].min,
450 arizona_hpdet_c_ranges[range].max);
451 regmap_update_bits(arizona->regmap,
452 ARIZONA_HEADPHONE_DETECT_1,
453 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
454 range <<
455 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
456 return -EAGAIN;
457 }
Charles Keepax91414612013-11-14 16:18:24 +0000458
459 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
460 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
461 arizona_hpdet_c_ranges[range].min);
462 val = arizona_hpdet_c_ranges[range].min;
463 }
Mark Brown4f340332013-01-11 08:55:43 +0900464 }
465
466 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
467 return val;
468}
469
Mark Brown9c2ba272013-02-25 23:42:31 +0000470static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
471 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900472{
473 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900474 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900475
476 /*
477 * If we're using HPDET for accessory identification we need
478 * to take multiple measurements, step through them in sequence.
479 */
480 if (arizona->pdata.hpdet_acc_id) {
481 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900482
483 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000484 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900485 dev_dbg(arizona->dev, "Measuring mic\n");
486
487 regmap_update_bits(arizona->regmap,
488 ARIZONA_ACCESSORY_DETECT_MODE_1,
489 ARIZONA_ACCDET_MODE_MASK |
490 ARIZONA_ACCDET_SRC,
491 ARIZONA_ACCDET_MODE_HPR |
492 info->micd_modes[0].src);
493
494 gpio_set_value_cansleep(id_gpio, 1);
495
Mark Browndd235ee2013-01-11 08:55:51 +0900496 regmap_update_bits(arizona->regmap,
497 ARIZONA_HEADPHONE_DETECT_1,
498 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
499 return -EAGAIN;
500 }
501
502 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000503 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
504 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000505
506 /* Take the headphone impedance for the main report */
507 *reading = info->hpdet_res[0];
508
Mark Brown9dd5e532013-04-01 19:09:45 +0100509 /* Sometimes we get false readings due to slow insert */
510 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
511 dev_dbg(arizona->dev, "Retrying high impedance\n");
512 info->num_hpdet_res = 0;
513 info->hpdet_retried = true;
514 arizona_start_hpdet_acc_id(info);
515 pm_runtime_put(info->dev);
516 return -EAGAIN;
517 }
518
Mark Brown1eda6aa2013-01-11 08:55:54 +0900519 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530520 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900521 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000522 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900523 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000524 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000525 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900526 } else {
527 dev_dbg(arizona->dev, "Detected headphone\n");
528 }
529
530 /* Make sure everything is reset back to the real polarity */
531 regmap_update_bits(arizona->regmap,
532 ARIZONA_ACCESSORY_DETECT_MODE_1,
533 ARIZONA_ACCDET_SRC,
534 info->micd_modes[0].src);
535 }
536
537 return 0;
538}
539
Mark Brown4f340332013-01-11 08:55:43 +0900540static irqreturn_t arizona_hpdet_irq(int irq, void *data)
541{
542 struct arizona_extcon_info *info = data;
543 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900544 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900545 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900546 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000547 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900548
549 mutex_lock(&info->lock);
550
551 /* If we got a spurious IRQ for some reason then ignore it */
552 if (!info->hpdet_active) {
553 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
554 mutex_unlock(&info->lock);
555 return IRQ_NONE;
556 }
557
558 /* If the cable was removed while measuring ignore the result */
559 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
560 if (ret < 0) {
561 dev_err(arizona->dev, "Failed to check cable state: %d\n",
562 ret);
563 goto out;
564 } else if (!ret) {
565 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
566 goto done;
567 }
568
569 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900570 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900571 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900572 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900573 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900574 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900575
576 /* Reset back to starting range */
577 regmap_update_bits(arizona->regmap,
578 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900579 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
580 0);
581
Mark Brown9c2ba272013-02-25 23:42:31 +0000582 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900583 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900584 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900585 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900586 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900587
588 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900589 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900590 report = ARIZONA_CABLE_LINEOUT;
591 else
592 report = ARIZONA_CABLE_HEADPHONE;
593
594 ret = extcon_set_cable_state_(&info->edev, report, true);
595 if (ret != 0)
596 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
597 ret);
598
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000599done:
600 /* Reset back to starting range */
601 regmap_update_bits(arizona->regmap,
602 ARIZONA_HEADPHONE_DETECT_1,
603 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
604 0);
605
Mark Brown03409072013-02-12 13:00:31 +0000606 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900607
Mark Brown1eda6aa2013-01-11 08:55:54 +0900608 if (id_gpio)
609 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900610
611 /* Revert back to MICDET mode */
612 regmap_update_bits(arizona->regmap,
613 ARIZONA_ACCESSORY_DETECT_MODE_1,
614 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
615
616 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000617 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900618 arizona_start_mic(info);
619
620 if (info->hpdet_active) {
621 pm_runtime_put_autosuspend(info->dev);
622 info->hpdet_active = false;
623 }
624
Mark Brownbf14ee52013-02-05 20:20:17 +0000625 info->hpdet_done = true;
626
Mark Brown4f340332013-01-11 08:55:43 +0900627out:
628 mutex_unlock(&info->lock);
629
630 return IRQ_HANDLED;
631}
632
633static void arizona_identify_headphone(struct arizona_extcon_info *info)
634{
635 struct arizona *arizona = info->arizona;
636 int ret;
637
Mark Brownbf14ee52013-02-05 20:20:17 +0000638 if (info->hpdet_done)
639 return;
640
Mark Brown4f340332013-01-11 08:55:43 +0900641 dev_dbg(arizona->dev, "Starting HPDET\n");
642
643 /* Make sure we keep the device enabled during the measurement */
644 pm_runtime_get(info->dev);
645
646 info->hpdet_active = true;
647
648 if (info->mic)
649 arizona_stop_mic(info);
650
Mark Brown03409072013-02-12 13:00:31 +0000651 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900652
653 ret = regmap_update_bits(arizona->regmap,
654 ARIZONA_ACCESSORY_DETECT_MODE_1,
655 ARIZONA_ACCDET_MODE_MASK,
656 ARIZONA_ACCDET_MODE_HPL);
657 if (ret != 0) {
658 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
659 goto err;
660 }
661
662 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
663 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
664 if (ret != 0) {
665 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
666 ret);
667 goto err;
668 }
669
670 return;
671
672err:
673 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
674 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
675
676 /* Just report headphone */
677 ret = extcon_update_state(&info->edev,
678 1 << ARIZONA_CABLE_HEADPHONE,
679 1 << ARIZONA_CABLE_HEADPHONE);
680 if (ret != 0)
681 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
682
683 if (info->mic)
684 arizona_start_mic(info);
685
686 info->hpdet_active = false;
687}
Mark Browndd235ee2013-01-11 08:55:51 +0900688
689static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
690{
691 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000692 int hp_reading = 32;
693 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900694 int ret;
695
696 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
697
698 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000699 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900700
701 info->hpdet_active = true;
702
Mark Brown03409072013-02-12 13:00:31 +0000703 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900704
705 ret = regmap_update_bits(arizona->regmap,
706 ARIZONA_ACCESSORY_DETECT_MODE_1,
707 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
708 info->micd_modes[0].src |
709 ARIZONA_ACCDET_MODE_HPL);
710 if (ret != 0) {
711 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
712 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900713 }
714
Mark Brown9c2ba272013-02-25 23:42:31 +0000715 if (arizona->pdata.hpdet_acc_id_line) {
716 ret = regmap_update_bits(arizona->regmap,
717 ARIZONA_HEADPHONE_DETECT_1,
718 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
719 if (ret != 0) {
720 dev_err(arizona->dev,
721 "Can't start HPDETL measurement: %d\n",
722 ret);
723 goto err;
724 }
725 } else {
726 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900727 }
728
729 return;
730
731err:
732 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
733 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
734
735 /* Just report headphone */
736 ret = extcon_update_state(&info->edev,
737 1 << ARIZONA_CABLE_HEADPHONE,
738 1 << ARIZONA_CABLE_HEADPHONE);
739 if (ret != 0)
740 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
741
Mark Brown4f340332013-01-11 08:55:43 +0900742 info->hpdet_active = false;
743}
744
Mark Brown939c5672013-04-01 19:17:34 +0100745static void arizona_micd_timeout_work(struct work_struct *work)
746{
747 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900748 struct arizona_extcon_info,
749 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100750
751 mutex_lock(&info->lock);
752
753 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
754 arizona_identify_headphone(info);
755
756 info->detecting = false;
757
758 arizona_stop_mic(info);
759
760 mutex_unlock(&info->lock);
761}
762
Mark Browncd59e792013-04-01 19:21:48 +0100763static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100764{
Mark Browncd59e792013-04-01 19:21:48 +0100765 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900766 struct arizona_extcon_info,
767 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100768 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100769 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100770 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100771
Mark Brown939c5672013-04-01 19:17:34 +0100772 cancel_delayed_work_sync(&info->micd_timeout_work);
773
Mark Brownf2c32a82012-06-24 12:09:45 +0100774 mutex_lock(&info->lock);
775
Charles Keepax31a847e2013-11-14 16:18:23 +0000776 /* If the cable was removed while measuring ignore the result */
777 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
778 if (ret < 0) {
779 dev_err(arizona->dev, "Failed to check cable state: %d\n",
780 ret);
781 mutex_unlock(&info->lock);
782 return;
783 } else if (!ret) {
784 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
785 mutex_unlock(&info->lock);
786 return;
787 }
788
Charles Keepaxffae24f2013-11-14 16:18:21 +0000789 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100790 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
791 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900792 dev_err(arizona->dev,
793 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100794 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100795 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100796 }
797
798 dev_dbg(arizona->dev, "MICDET: %x\n", val);
799
800 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900801 dev_warn(arizona->dev,
802 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100803 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100804 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100805 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100806 }
807
Charles Keepaxffae24f2013-11-14 16:18:21 +0000808 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100809 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100810 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100811 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100812 }
813
814 /* Due to jack detect this should never happen */
815 if (!(val & ARIZONA_MICD_STS)) {
816 dev_warn(arizona->dev, "Detected open circuit\n");
817 info->detecting = false;
818 goto handled;
819 }
820
821 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000822 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900823 arizona_identify_headphone(info);
824
Mark Brown325c6422012-06-28 13:08:30 +0100825 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900826 1 << ARIZONA_CABLE_MICROPHONE,
827 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100828
829 if (ret != 0)
830 dev_err(arizona->dev, "Headset report failed: %d\n",
831 ret);
832
Mark Brownbbbd46e2013-01-10 19:38:43 +0000833 /* Don't need to regulate for button detection */
834 ret = regulator_allow_bypass(info->micvdd, false);
835 if (ret != 0) {
836 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
837 ret);
838 }
839
Mark Brownf2c32a82012-06-24 12:09:45 +0100840 info->mic = true;
841 info->detecting = false;
842 goto handled;
843 }
844
845 /* If we detected a lower impedence during initial startup
846 * then we probably have the wrong polarity, flip it. Don't
847 * do this for the lowest impedences to speed up detection of
848 * plain headphones. If both polarities report a low
849 * impedence then give up and report headphones.
850 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000851 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800852 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900853 dev_dbg(arizona->dev, "Detected HP/line\n");
854 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100855
Mark Brown4f340332013-01-11 08:55:43 +0900856 info->detecting = false;
857
858 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100859 } else {
860 info->micd_mode++;
861 if (info->micd_mode == info->micd_num_modes)
862 info->micd_mode = 0;
863 arizona_extcon_set_mode(info, info->micd_mode);
864
865 info->jack_flips++;
866 }
867
868 goto handled;
869 }
870
871 /*
872 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100873 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100874 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000875 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100876 if (info->mic) {
877 dev_dbg(arizona->dev, "Mic button detected\n");
878
Mark Brown34efe4d2012-07-20 17:07:29 +0100879 lvl = val & ARIZONA_MICD_LVL_MASK;
880 lvl >>= ARIZONA_MICD_LVL_SHIFT;
881
Mark Brown41a57852013-04-01 19:18:18 +0100882 for (i = 0; i < info->num_micd_ranges; i++)
883 input_report_key(info->input,
884 info->micd_ranges[i].key, 0);
885
Mark Brown6fed4d82013-04-01 22:03:06 +0100886 WARN_ON(!lvl);
887 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
888 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
889 key = info->micd_ranges[ffs(lvl) - 1].key;
890 input_report_key(info->input, key, 1);
891 input_sync(info->input);
892 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100893
Mark Brownf2c32a82012-06-24 12:09:45 +0100894 } else if (info->detecting) {
895 dev_dbg(arizona->dev, "Headphone detected\n");
896 info->detecting = false;
897 arizona_stop_mic(info);
898
Mark Brown4f340332013-01-11 08:55:43 +0900899 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100900 } else {
901 dev_warn(arizona->dev, "Button with no mic: %x\n",
902 val);
903 }
904 } else {
905 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100906 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100907 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100908 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100909 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000910 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100911 }
912
913handled:
Mark Brown939c5672013-04-01 19:17:34 +0100914 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100915 queue_delayed_work(system_power_efficient_wq,
916 &info->micd_timeout_work,
917 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100918
Mark Brownf2c32a82012-06-24 12:09:45 +0100919 pm_runtime_mark_last_busy(info->dev);
920 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100921}
922
923static irqreturn_t arizona_micdet(int irq, void *data)
924{
925 struct arizona_extcon_info *info = data;
926 struct arizona *arizona = info->arizona;
927 int debounce = arizona->pdata.micd_detect_debounce;
928
929 cancel_delayed_work_sync(&info->micd_detect_work);
930 cancel_delayed_work_sync(&info->micd_timeout_work);
931
932 mutex_lock(&info->lock);
933 if (!info->detecting)
934 debounce = 0;
935 mutex_unlock(&info->lock);
936
937 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100938 queue_delayed_work(system_power_efficient_wq,
939 &info->micd_detect_work,
940 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100941 else
942 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100943
944 return IRQ_HANDLED;
945}
946
Mark Brown0e27bd32013-02-05 21:00:15 +0000947static void arizona_hpdet_work(struct work_struct *work)
948{
949 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900950 struct arizona_extcon_info,
951 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000952
953 mutex_lock(&info->lock);
954 arizona_start_hpdet_acc_id(info);
955 mutex_unlock(&info->lock);
956}
957
Mark Brownf2c32a82012-06-24 12:09:45 +0100958static irqreturn_t arizona_jackdet(int irq, void *data)
959{
960 struct arizona_extcon_info *info = data;
961 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900962 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100963 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100964 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100965
Mark Brown939c5672013-04-01 19:17:34 +0100966 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
967 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100968
Mark Browna3e20782013-04-01 19:05:27 +0100969 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000970
Mark Brownf2c32a82012-06-24 12:09:45 +0100971 mutex_lock(&info->lock);
972
Mark Brown92a49872013-01-11 08:55:39 +0900973 if (arizona->pdata.jd_gpio5) {
974 mask = ARIZONA_MICD_CLAMP_STS;
975 present = 0;
976 } else {
977 mask = ARIZONA_JD1_STS;
978 present = ARIZONA_JD1_STS;
979 }
980
Mark Brownf2c32a82012-06-24 12:09:45 +0100981 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
982 if (ret != 0) {
983 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
984 ret);
985 mutex_unlock(&info->lock);
986 pm_runtime_put_autosuspend(info->dev);
987 return IRQ_NONE;
988 }
989
Mark Browna3e20782013-04-01 19:05:27 +0100990 val &= mask;
991 if (val == info->last_jackdet) {
992 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +0100993 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100994 queue_delayed_work(system_power_efficient_wq,
995 &info->hpdet_work,
996 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +0100997
Chanwoo Choic2275d22013-08-23 10:21:37 +0900998 if (cancelled_mic) {
999 int micd_timeout = info->micd_timeout;
1000
Mark Browndf9a5ab2013-07-18 22:42:22 +01001001 queue_delayed_work(system_power_efficient_wq,
1002 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001003 msecs_to_jiffies(micd_timeout));
1004 }
Mark Brown939c5672013-04-01 19:17:34 +01001005
Mark Browna3e20782013-04-01 19:05:27 +01001006 goto out;
1007 }
1008 info->last_jackdet = val;
1009
1010 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001011 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +01001012 ret = extcon_set_cable_state_(&info->edev,
1013 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001014
1015 if (ret != 0)
1016 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1017 ret);
1018
Mark Browndd235ee2013-01-11 08:55:51 +09001019 if (!arizona->pdata.hpdet_acc_id) {
1020 info->detecting = true;
1021 info->mic = false;
1022 info->jack_flips = 0;
1023
1024 arizona_start_mic(info);
1025 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001026 queue_delayed_work(system_power_efficient_wq,
1027 &info->hpdet_work,
1028 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001029 }
Mark Brown4e616872013-01-15 22:09:20 +09001030
1031 regmap_update_bits(arizona->regmap,
1032 ARIZONA_JACK_DETECT_DEBOUNCE,
1033 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001034 } else {
1035 dev_dbg(arizona->dev, "Detected jack removal\n");
1036
1037 arizona_stop_mic(info);
1038
Mark Browndd235ee2013-01-11 08:55:51 +09001039 info->num_hpdet_res = 0;
1040 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1041 info->hpdet_res[i] = 0;
1042 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001043 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001044 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001045
Mark Brown6fed4d82013-04-01 22:03:06 +01001046 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001047 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001048 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001049 input_sync(info->input);
1050
Mark Brownf2c32a82012-06-24 12:09:45 +01001051 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
1052 if (ret != 0)
1053 dev_err(arizona->dev, "Removal report failed: %d\n",
1054 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001055
1056 regmap_update_bits(arizona->regmap,
1057 ARIZONA_JACK_DETECT_DEBOUNCE,
1058 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1059 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001060 }
1061
Mark Brown7abd4e22013-04-01 19:25:55 +01001062 if (arizona->pdata.micd_timeout)
1063 info->micd_timeout = arizona->pdata.micd_timeout;
1064 else
1065 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1066
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001067out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001068 /* Clear trig_sts to make sure DCVDD is not forced up */
1069 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1070 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1071 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1072 ARIZONA_JD1_FALL_TRIG_STS |
1073 ARIZONA_JD1_RISE_TRIG_STS);
1074
Mark Brownf2c32a82012-06-24 12:09:45 +01001075 mutex_unlock(&info->lock);
1076
1077 pm_runtime_mark_last_busy(info->dev);
1078 pm_runtime_put_autosuspend(info->dev);
1079
1080 return IRQ_HANDLED;
1081}
1082
Mark Brown6fed4d82013-04-01 22:03:06 +01001083/* Map a level onto a slot in the register bank */
1084static void arizona_micd_set_level(struct arizona *arizona, int index,
1085 unsigned int level)
1086{
1087 int reg;
1088 unsigned int mask;
1089
1090 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1091
1092 if (!(index % 2)) {
1093 mask = 0x3f00;
1094 level <<= 8;
1095 } else {
1096 mask = 0x3f;
1097 }
1098
1099 /* Program the level itself */
1100 regmap_update_bits(arizona->regmap, reg, mask, level);
1101}
1102
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001103static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001104{
1105 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001106 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001107 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001108 unsigned int val;
Mark Brown92a49872013-01-11 08:55:39 +09001109 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001110 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001111
Mark Brownbbbd46e2013-01-10 19:38:43 +00001112 if (!arizona->dapm || !arizona->dapm->card)
1113 return -EPROBE_DEFER;
1114
Mark Brownf2c32a82012-06-24 12:09:45 +01001115 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1116 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001117 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +01001118 ret = -ENOMEM;
1119 goto err;
1120 }
1121
1122 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1123 if (IS_ERR(info->micvdd)) {
1124 ret = PTR_ERR(info->micvdd);
1125 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
1126 goto err;
1127 }
1128
1129 mutex_init(&info->lock);
1130 info->arizona = arizona;
1131 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001132 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001133 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001134 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001135 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001136 platform_set_drvdata(pdev, info);
1137
1138 switch (arizona->type) {
1139 case WM5102:
1140 switch (arizona->rev) {
1141 case 0:
1142 info->micd_reva = true;
1143 break;
1144 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001145 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001146 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001147 break;
1148 }
1149 break;
1150 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");