blob: 896a923546e0cf53407cbf9f5c598ae34cf20ae7 [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 Brown34efe4d2012-07-20 17:07:29 +010036#define ARIZONA_NUM_BUTTONS 6
37
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 Brownf2c32a82012-06-24 12:09:45 +010042struct arizona_extcon_info {
43 struct device *dev;
44 struct arizona *arizona;
45 struct mutex lock;
46 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010047 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010048
49 int micd_mode;
50 const struct arizona_micd_config *micd_modes;
51 int micd_num_modes;
52
53 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090054 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010055
Mark Brown0e27bd32013-02-05 21:00:15 +000056 struct delayed_work hpdet_work;
57
Mark Brown4f340332013-01-11 08:55:43 +090058 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000059 bool hpdet_done;
Mark Brown4f340332013-01-11 08:55:43 +090060
Mark Browndd235ee2013-01-11 08:55:51 +090061 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090062 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090063
Mark Brownf2c32a82012-06-24 12:09:45 +010064 bool mic;
65 bool detecting;
66 int jack_flips;
67
Mark Brown4f340332013-01-11 08:55:43 +090068 int hpdet_ip;
69
Mark Brownf2c32a82012-06-24 12:09:45 +010070 struct extcon_dev edev;
71};
72
73static const struct arizona_micd_config micd_default_modes[] = {
Mark Brownf2c32a82012-06-24 12:09:45 +010074 { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
Mark Browndd235ee2013-01-11 08:55:51 +090075 { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
Mark Brownf2c32a82012-06-24 12:09:45 +010076};
77
Mark Brown34efe4d2012-07-20 17:07:29 +010078static struct {
79 u16 status;
80 int report;
81} arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = {
82 { 0x1, BTN_0 },
83 { 0x2, BTN_1 },
84 { 0x4, BTN_2 },
85 { 0x8, BTN_3 },
86 { 0x10, BTN_4 },
87 { 0x20, BTN_5 },
88};
89
Mark Brown325c6422012-06-28 13:08:30 +010090#define ARIZONA_CABLE_MECHANICAL 0
91#define ARIZONA_CABLE_MICROPHONE 1
92#define ARIZONA_CABLE_HEADPHONE 2
Mark Brown4f340332013-01-11 08:55:43 +090093#define ARIZONA_CABLE_LINEOUT 3
Mark Brownf2c32a82012-06-24 12:09:45 +010094
95static const char *arizona_cable[] = {
Mark Brown325c6422012-06-28 13:08:30 +010096 "Mechanical",
97 "Microphone",
98 "Headphone",
Mark Brown4f340332013-01-11 08:55:43 +090099 "Line-out",
Mark Brownf2c32a82012-06-24 12:09:45 +0100100 NULL,
101};
102
Mark Brown03409072013-02-12 13:00:31 +0000103static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
104 unsigned int magic)
105{
106 struct arizona *arizona = info->arizona;
107 unsigned int val;
108 int ret;
109
110 mutex_lock(&arizona->dapm->card->dapm_mutex);
111
112 ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
113 if (ret != 0) {
114 dev_err(arizona->dev, "Failed to read output enables: %d\n",
115 ret);
116 val = 0;
117 }
118
119 if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
120 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
121 magic);
122 if (ret != 0)
123 dev_warn(arizona->dev, "Failed to do magic: %d\n",
124 ret);
125
126 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
127 magic);
128 if (ret != 0)
129 dev_warn(arizona->dev, "Failed to do magic: %d\n",
130 ret);
131 }
132
133 mutex_unlock(&arizona->dapm->card->dapm_mutex);
134}
135
Mark Brownf2c32a82012-06-24 12:09:45 +0100136static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
137{
138 struct arizona *arizona = info->arizona;
139
Mark Browncd74f7b2012-11-27 16:14:26 +0900140 if (arizona->pdata.micd_pol_gpio > 0)
141 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
142 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100143 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
144 ARIZONA_MICD_BIAS_SRC_MASK,
145 info->micd_modes[mode].bias);
146 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
147 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
148
149 info->micd_mode = mode;
150
151 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
152}
153
Mark Brownbbbd46e2013-01-10 19:38:43 +0000154static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
155{
156 switch (info->micd_modes[0].bias >> ARIZONA_MICD_BIAS_SRC_SHIFT) {
157 case 1:
158 return "MICBIAS1";
159 case 2:
160 return "MICBIAS2";
161 case 3:
162 return "MICBIAS3";
163 default:
164 return "MICVDD";
165 }
166}
167
168static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
169{
170 struct arizona *arizona = info->arizona;
171 const char *widget = arizona_extcon_get_micbias(info);
172 struct snd_soc_dapm_context *dapm = arizona->dapm;
173 int ret;
174
175 mutex_lock(&dapm->card->dapm_mutex);
176
177 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
178 if (ret != 0)
179 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
180 widget, ret);
181
182 mutex_unlock(&dapm->card->dapm_mutex);
183
184 snd_soc_dapm_sync(dapm);
185
186 if (!arizona->pdata.micd_force_micbias) {
187 mutex_lock(&dapm->card->dapm_mutex);
188
189 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
190 if (ret != 0)
191 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
192 widget, ret);
193
194 mutex_unlock(&dapm->card->dapm_mutex);
195
196 snd_soc_dapm_sync(dapm);
197 }
198}
199
Mark Brown9b1270c2013-01-11 08:55:46 +0900200static void arizona_start_mic(struct arizona_extcon_info *info)
201{
202 struct arizona *arizona = info->arizona;
203 bool change;
204 int ret;
205
Mark Brown9b1270c2013-01-11 08:55:46 +0900206 /* Microphone detection can't use idle mode */
207 pm_runtime_get(info->dev);
208
Mark Brownbbbd46e2013-01-10 19:38:43 +0000209 if (info->detecting) {
210 ret = regulator_allow_bypass(info->micvdd, false);
211 if (ret != 0) {
212 dev_err(arizona->dev,
213 "Failed to regulate MICVDD: %d\n",
214 ret);
215 }
216 }
217
Mark Brown9b1270c2013-01-11 08:55:46 +0900218 ret = regulator_enable(info->micvdd);
219 if (ret != 0) {
220 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
221 ret);
222 }
223
224 if (info->micd_reva) {
225 regmap_write(arizona->regmap, 0x80, 0x3);
226 regmap_write(arizona->regmap, 0x294, 0);
227 regmap_write(arizona->regmap, 0x80, 0x0);
228 }
229
230 regmap_update_bits(arizona->regmap,
231 ARIZONA_ACCESSORY_DETECT_MODE_1,
232 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
233
Mark Brownbbbd46e2013-01-10 19:38:43 +0000234 arizona_extcon_pulse_micbias(info);
235
Mark Brown9b1270c2013-01-11 08:55:46 +0900236 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
237 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
238 &change);
239 if (!change) {
240 regulator_disable(info->micvdd);
241 pm_runtime_put_autosuspend(info->dev);
242 }
243}
244
245static void arizona_stop_mic(struct arizona_extcon_info *info)
246{
247 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000248 const char *widget = arizona_extcon_get_micbias(info);
249 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900250 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000251 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900252
253 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
254 ARIZONA_MICD_ENA, 0,
255 &change);
256
Mark Brownbbbd46e2013-01-10 19:38:43 +0000257 mutex_lock(&dapm->card->dapm_mutex);
258
259 ret = snd_soc_dapm_disable_pin(dapm, widget);
260 if (ret != 0)
261 dev_warn(arizona->dev,
262 "Failed to disable %s: %d\n",
263 widget, ret);
264
265 mutex_unlock(&dapm->card->dapm_mutex);
266
267 snd_soc_dapm_sync(dapm);
268
Mark Brown9b1270c2013-01-11 08:55:46 +0900269 if (info->micd_reva) {
270 regmap_write(arizona->regmap, 0x80, 0x3);
271 regmap_write(arizona->regmap, 0x294, 2);
272 regmap_write(arizona->regmap, 0x80, 0x0);
273 }
274
Mark Brownbbbd46e2013-01-10 19:38:43 +0000275 ret = regulator_allow_bypass(info->micvdd, true);
276 if (ret != 0) {
277 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
278 ret);
279 }
280
Mark Brown9b1270c2013-01-11 08:55:46 +0900281 if (change) {
282 regulator_disable(info->micvdd);
283 pm_runtime_mark_last_busy(info->dev);
284 pm_runtime_put_autosuspend(info->dev);
285 }
286}
287
Mark Brown4f340332013-01-11 08:55:43 +0900288static struct {
289 unsigned int factor_a;
290 unsigned int factor_b;
291} arizona_hpdet_b_ranges[] = {
292 { 5528, 362464 },
293 { 11084, 6186851 },
294 { 11065, 65460395 },
295};
296
297static struct {
298 int min;
299 int max;
300} arizona_hpdet_c_ranges[] = {
301 { 0, 30 },
302 { 8, 100 },
303 { 100, 1000 },
304 { 1000, 10000 },
305};
306
307static int arizona_hpdet_read(struct arizona_extcon_info *info)
308{
309 struct arizona *arizona = info->arizona;
310 unsigned int val, range;
311 int ret;
312
313 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
314 if (ret != 0) {
315 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
316 ret);
317 return ret;
318 }
319
320 switch (info->hpdet_ip) {
321 case 0:
322 if (!(val & ARIZONA_HP_DONE)) {
323 dev_err(arizona->dev, "HPDET did not complete: %x\n",
324 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900325 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900326 }
327
328 val &= ARIZONA_HP_LVL_MASK;
329 break;
330
331 case 1:
332 if (!(val & ARIZONA_HP_DONE_B)) {
333 dev_err(arizona->dev, "HPDET did not complete: %x\n",
334 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900335 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900336 }
337
338 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
339 if (ret != 0) {
340 dev_err(arizona->dev, "Failed to read HP value: %d\n",
341 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900342 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900343 }
344
345 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
346 &range);
347 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
348 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
349
350 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
351 (val < 100 || val > 0x3fb)) {
352 range++;
353 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
354 range);
355 regmap_update_bits(arizona->regmap,
356 ARIZONA_HEADPHONE_DETECT_1,
357 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
358 range <<
359 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
360 return -EAGAIN;
361 }
362
363 /* If we go out of range report top of range */
364 if (val < 100 || val > 0x3fb) {
365 dev_dbg(arizona->dev, "Measurement out of range\n");
366 return 10000;
367 }
368
369 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
370 val, range);
371
372 val = arizona_hpdet_b_ranges[range].factor_b
373 / ((val * 100) -
374 arizona_hpdet_b_ranges[range].factor_a);
375 break;
376
377 default:
378 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
379 info->hpdet_ip);
380 case 2:
381 if (!(val & ARIZONA_HP_DONE_B)) {
382 dev_err(arizona->dev, "HPDET did not complete: %x\n",
383 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900384 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900385 }
386
387 val &= ARIZONA_HP_LVL_B_MASK;
388
389 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
390 &range);
391 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
392 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
393
394 /* Skip up or down a range? */
395 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
396 range--;
397 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
398 arizona_hpdet_c_ranges[range].min,
399 arizona_hpdet_c_ranges[range].max);
400 regmap_update_bits(arizona->regmap,
401 ARIZONA_HEADPHONE_DETECT_1,
402 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
403 range <<
404 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
405 return -EAGAIN;
406 }
407
408 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
409 (val >= arizona_hpdet_c_ranges[range].max)) {
410 range++;
411 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
412 arizona_hpdet_c_ranges[range].min,
413 arizona_hpdet_c_ranges[range].max);
414 regmap_update_bits(arizona->regmap,
415 ARIZONA_HEADPHONE_DETECT_1,
416 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
417 range <<
418 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
419 return -EAGAIN;
420 }
421 }
422
423 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
424 return val;
425}
426
Mark Browndd235ee2013-01-11 08:55:51 +0900427static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
428{
429 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900430 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900431
432 /*
433 * If we're using HPDET for accessory identification we need
434 * to take multiple measurements, step through them in sequence.
435 */
436 if (arizona->pdata.hpdet_acc_id) {
437 info->hpdet_res[info->num_hpdet_res++] = *reading;
438
439 /*
440 * If the impedence is too high don't measure the
441 * second ground.
442 */
443 if (info->num_hpdet_res == 1 && *reading >= 45) {
444 dev_dbg(arizona->dev, "Skipping ground flip\n");
445 info->hpdet_res[info->num_hpdet_res++] = *reading;
446 }
447
448 if (info->num_hpdet_res == 1) {
449 dev_dbg(arizona->dev, "Flipping ground\n");
450
451 regmap_update_bits(arizona->regmap,
452 ARIZONA_ACCESSORY_DETECT_MODE_1,
453 ARIZONA_ACCDET_SRC,
454 ~info->micd_modes[0].src);
Mark Brown1eda6aa2013-01-11 08:55:54 +0900455
Mark Browndd235ee2013-01-11 08:55:51 +0900456 regmap_update_bits(arizona->regmap,
457 ARIZONA_HEADPHONE_DETECT_1,
Mark Brown1eda6aa2013-01-11 08:55:54 +0900458 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
459 return -EAGAIN;
460 }
461
462 /* Only check the mic directly if we didn't already ID it */
463 if (id_gpio && info->num_hpdet_res == 2 &&
464 !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) {
465 dev_dbg(arizona->dev, "Measuring mic\n");
466
467 regmap_update_bits(arizona->regmap,
468 ARIZONA_ACCESSORY_DETECT_MODE_1,
469 ARIZONA_ACCDET_MODE_MASK |
470 ARIZONA_ACCDET_SRC,
471 ARIZONA_ACCDET_MODE_HPR |
472 info->micd_modes[0].src);
473
474 gpio_set_value_cansleep(id_gpio, 1);
475
Mark Browndd235ee2013-01-11 08:55:51 +0900476 regmap_update_bits(arizona->regmap,
477 ARIZONA_HEADPHONE_DETECT_1,
478 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
479 return -EAGAIN;
480 }
481
482 /* OK, got both. Now, compare... */
Mark Brown1eda6aa2013-01-11 08:55:54 +0900483 dev_dbg(arizona->dev, "HPDET measured %d %d %d\n",
484 info->hpdet_res[0], info->hpdet_res[1],
485 info->hpdet_res[2]);
Mark Browndd235ee2013-01-11 08:55:51 +0900486
Mark Brownc37b3872013-02-05 17:48:49 +0000487
488 /* Take the headphone impedance for the main report */
489 *reading = info->hpdet_res[0];
490
Mark Brown1eda6aa2013-01-11 08:55:54 +0900491 /*
492 * Either the two grounds measure differently or we
493 * measure the mic as high impedance.
494 */
495 if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) ||
496 (id_gpio && info->hpdet_res[2] > 10)) {
Mark Browndd235ee2013-01-11 08:55:51 +0900497 dev_dbg(arizona->dev, "Detected mic\n");
498 info->mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000499 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900500 } else {
501 dev_dbg(arizona->dev, "Detected headphone\n");
502 }
503
504 /* Make sure everything is reset back to the real polarity */
505 regmap_update_bits(arizona->regmap,
506 ARIZONA_ACCESSORY_DETECT_MODE_1,
507 ARIZONA_ACCDET_SRC,
508 info->micd_modes[0].src);
509 }
510
511 return 0;
512}
513
Mark Brown4f340332013-01-11 08:55:43 +0900514static irqreturn_t arizona_hpdet_irq(int irq, void *data)
515{
516 struct arizona_extcon_info *info = data;
517 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900518 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900519 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900520 int ret, reading;
Mark Brown4f340332013-01-11 08:55:43 +0900521
522 mutex_lock(&info->lock);
523
524 /* If we got a spurious IRQ for some reason then ignore it */
525 if (!info->hpdet_active) {
526 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
527 mutex_unlock(&info->lock);
528 return IRQ_NONE;
529 }
530
531 /* If the cable was removed while measuring ignore the result */
532 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
533 if (ret < 0) {
534 dev_err(arizona->dev, "Failed to check cable state: %d\n",
535 ret);
536 goto out;
537 } else if (!ret) {
538 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
539 goto done;
540 }
541
542 ret = arizona_hpdet_read(info);
543 if (ret == -EAGAIN) {
544 goto out;
545 } else if (ret < 0) {
546 goto done;
547 }
Mark Browndd235ee2013-01-11 08:55:51 +0900548 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900549
550 /* Reset back to starting range */
551 regmap_update_bits(arizona->regmap,
552 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900553 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
554 0);
555
556 ret = arizona_hpdet_do_id(info, &reading);
557 if (ret == -EAGAIN) {
558 goto out;
559 } else if (ret < 0) {
560 goto done;
561 }
Mark Brown4f340332013-01-11 08:55:43 +0900562
563 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900564 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900565 report = ARIZONA_CABLE_LINEOUT;
566 else
567 report = ARIZONA_CABLE_HEADPHONE;
568
569 ret = extcon_set_cable_state_(&info->edev, report, true);
570 if (ret != 0)
571 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
572 ret);
573
Mark Brown03409072013-02-12 13:00:31 +0000574 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900575
576done:
Mark Brown1eda6aa2013-01-11 08:55:54 +0900577 if (id_gpio)
578 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900579
580 /* Revert back to MICDET mode */
581 regmap_update_bits(arizona->regmap,
582 ARIZONA_ACCESSORY_DETECT_MODE_1,
583 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
584
585 /* If we have a mic then reenable MICDET */
586 if (info->mic)
587 arizona_start_mic(info);
588
589 if (info->hpdet_active) {
590 pm_runtime_put_autosuspend(info->dev);
591 info->hpdet_active = false;
592 }
593
Mark Brownbf14ee52013-02-05 20:20:17 +0000594 info->hpdet_done = true;
595
Mark Brown4f340332013-01-11 08:55:43 +0900596out:
597 mutex_unlock(&info->lock);
598
599 return IRQ_HANDLED;
600}
601
602static void arizona_identify_headphone(struct arizona_extcon_info *info)
603{
604 struct arizona *arizona = info->arizona;
605 int ret;
606
Mark Brownbf14ee52013-02-05 20:20:17 +0000607 if (info->hpdet_done)
608 return;
609
Mark Brown4f340332013-01-11 08:55:43 +0900610 dev_dbg(arizona->dev, "Starting HPDET\n");
611
612 /* Make sure we keep the device enabled during the measurement */
613 pm_runtime_get(info->dev);
614
615 info->hpdet_active = true;
616
617 if (info->mic)
618 arizona_stop_mic(info);
619
Mark Brown03409072013-02-12 13:00:31 +0000620 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900621
622 ret = regmap_update_bits(arizona->regmap,
623 ARIZONA_ACCESSORY_DETECT_MODE_1,
624 ARIZONA_ACCDET_MODE_MASK,
625 ARIZONA_ACCDET_MODE_HPL);
626 if (ret != 0) {
627 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
628 goto err;
629 }
630
631 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
632 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
633 if (ret != 0) {
634 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
635 ret);
636 goto err;
637 }
638
639 return;
640
641err:
642 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
643 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
644
645 /* Just report headphone */
646 ret = extcon_update_state(&info->edev,
647 1 << ARIZONA_CABLE_HEADPHONE,
648 1 << ARIZONA_CABLE_HEADPHONE);
649 if (ret != 0)
650 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
651
652 if (info->mic)
653 arizona_start_mic(info);
654
655 info->hpdet_active = false;
656}
Mark Browndd235ee2013-01-11 08:55:51 +0900657
658static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
659{
660 struct arizona *arizona = info->arizona;
661 int ret;
662
663 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
664
665 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000666 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900667
668 info->hpdet_active = true;
669
Mark Brownbbbd46e2013-01-10 19:38:43 +0000670 arizona_extcon_pulse_micbias(info);
671
Mark Brown03409072013-02-12 13:00:31 +0000672 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900673
674 ret = regmap_update_bits(arizona->regmap,
675 ARIZONA_ACCESSORY_DETECT_MODE_1,
676 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
677 info->micd_modes[0].src |
678 ARIZONA_ACCDET_MODE_HPL);
679 if (ret != 0) {
680 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
681 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900682 }
683
Mark Browndd235ee2013-01-11 08:55:51 +0900684 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
685 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
686 if (ret != 0) {
687 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
688 ret);
689 goto err;
690 }
691
692 return;
693
694err:
695 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
696 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
697
698 /* Just report headphone */
699 ret = extcon_update_state(&info->edev,
700 1 << ARIZONA_CABLE_HEADPHONE,
701 1 << ARIZONA_CABLE_HEADPHONE);
702 if (ret != 0)
703 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
704
Mark Brown4f340332013-01-11 08:55:43 +0900705 info->hpdet_active = false;
706}
707
Mark Brownf2c32a82012-06-24 12:09:45 +0100708static irqreturn_t arizona_micdet(int irq, void *data)
709{
710 struct arizona_extcon_info *info = data;
711 struct arizona *arizona = info->arizona;
Mark Brown34efe4d2012-07-20 17:07:29 +0100712 unsigned int val, lvl;
713 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100714
715 mutex_lock(&info->lock);
716
717 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
718 if (ret != 0) {
719 dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
Alexey Khoroshilovbe31cc02012-11-05 17:11:41 +0900720 mutex_unlock(&info->lock);
Mark Brownf2c32a82012-06-24 12:09:45 +0100721 return IRQ_NONE;
722 }
723
724 dev_dbg(arizona->dev, "MICDET: %x\n", val);
725
726 if (!(val & ARIZONA_MICD_VALID)) {
727 dev_warn(arizona->dev, "Microphone detection state invalid\n");
728 mutex_unlock(&info->lock);
729 return IRQ_NONE;
730 }
731
732 /* Due to jack detect this should never happen */
733 if (!(val & ARIZONA_MICD_STS)) {
734 dev_warn(arizona->dev, "Detected open circuit\n");
735 info->detecting = false;
736 goto handled;
737 }
738
739 /* If we got a high impedence we should have a headset, report it. */
740 if (info->detecting && (val & 0x400)) {
Mark Brown4f340332013-01-11 08:55:43 +0900741 arizona_identify_headphone(info);
742
Mark Brown325c6422012-06-28 13:08:30 +0100743 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900744 1 << ARIZONA_CABLE_MICROPHONE,
745 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100746
747 if (ret != 0)
748 dev_err(arizona->dev, "Headset report failed: %d\n",
749 ret);
750
Mark Brownbbbd46e2013-01-10 19:38:43 +0000751 /* Don't need to regulate for button detection */
752 ret = regulator_allow_bypass(info->micvdd, false);
753 if (ret != 0) {
754 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
755 ret);
756 }
757
Mark Brownf2c32a82012-06-24 12:09:45 +0100758 info->mic = true;
759 info->detecting = false;
760 goto handled;
761 }
762
763 /* If we detected a lower impedence during initial startup
764 * then we probably have the wrong polarity, flip it. Don't
765 * do this for the lowest impedences to speed up detection of
766 * plain headphones. If both polarities report a low
767 * impedence then give up and report headphones.
768 */
769 if (info->detecting && (val & 0x3f8)) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100770 if (info->jack_flips >= info->micd_num_modes) {
Mark Brown4f340332013-01-11 08:55:43 +0900771 dev_dbg(arizona->dev, "Detected HP/line\n");
772 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100773
Mark Brown4f340332013-01-11 08:55:43 +0900774 info->detecting = false;
775
776 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100777 } else {
778 info->micd_mode++;
779 if (info->micd_mode == info->micd_num_modes)
780 info->micd_mode = 0;
781 arizona_extcon_set_mode(info, info->micd_mode);
782
783 info->jack_flips++;
784 }
785
786 goto handled;
787 }
788
789 /*
790 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100791 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100792 */
793 if (val & 0x3fc) {
794 if (info->mic) {
795 dev_dbg(arizona->dev, "Mic button detected\n");
796
Mark Brown34efe4d2012-07-20 17:07:29 +0100797 lvl = val & ARIZONA_MICD_LVL_MASK;
798 lvl >>= ARIZONA_MICD_LVL_SHIFT;
799
800 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
801 if (lvl & arizona_lvl_to_key[i].status)
802 input_report_key(info->input,
803 arizona_lvl_to_key[i].report,
804 1);
805 input_sync(info->input);
806
Mark Brownf2c32a82012-06-24 12:09:45 +0100807 } else if (info->detecting) {
808 dev_dbg(arizona->dev, "Headphone detected\n");
809 info->detecting = false;
810 arizona_stop_mic(info);
811
Mark Brown4f340332013-01-11 08:55:43 +0900812 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100813 } else {
814 dev_warn(arizona->dev, "Button with no mic: %x\n",
815 val);
816 }
817 } else {
818 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown34efe4d2012-07-20 17:07:29 +0100819 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
820 input_report_key(info->input,
821 arizona_lvl_to_key[i].report, 0);
822 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000823 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100824 }
825
826handled:
827 pm_runtime_mark_last_busy(info->dev);
828 mutex_unlock(&info->lock);
829
830 return IRQ_HANDLED;
831}
832
Mark Brown0e27bd32013-02-05 21:00:15 +0000833static void arizona_hpdet_work(struct work_struct *work)
834{
835 struct arizona_extcon_info *info = container_of(work,
836 struct arizona_extcon_info,
837 hpdet_work.work);
838
839 mutex_lock(&info->lock);
840 arizona_start_hpdet_acc_id(info);
841 mutex_unlock(&info->lock);
842}
843
Mark Brownf2c32a82012-06-24 12:09:45 +0100844static irqreturn_t arizona_jackdet(int irq, void *data)
845{
846 struct arizona_extcon_info *info = data;
847 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900848 unsigned int val, present, mask;
Mark Brown34efe4d2012-07-20 17:07:29 +0100849 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100850
851 pm_runtime_get_sync(info->dev);
852
Mark Brown0e27bd32013-02-05 21:00:15 +0000853 cancel_delayed_work_sync(&info->hpdet_work);
854
Mark Brownf2c32a82012-06-24 12:09:45 +0100855 mutex_lock(&info->lock);
856
Mark Brown92a49872013-01-11 08:55:39 +0900857 if (arizona->pdata.jd_gpio5) {
858 mask = ARIZONA_MICD_CLAMP_STS;
859 present = 0;
860 } else {
861 mask = ARIZONA_JD1_STS;
862 present = ARIZONA_JD1_STS;
863 }
864
Mark Brownf2c32a82012-06-24 12:09:45 +0100865 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
866 if (ret != 0) {
867 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
868 ret);
869 mutex_unlock(&info->lock);
870 pm_runtime_put_autosuspend(info->dev);
871 return IRQ_NONE;
872 }
873
Mark Brown92a49872013-01-11 08:55:39 +0900874 if ((val & mask) == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100875 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +0100876 ret = extcon_set_cable_state_(&info->edev,
877 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100878
879 if (ret != 0)
880 dev_err(arizona->dev, "Mechanical report failed: %d\n",
881 ret);
882
Mark Browndd235ee2013-01-11 08:55:51 +0900883 if (!arizona->pdata.hpdet_acc_id) {
884 info->detecting = true;
885 info->mic = false;
886 info->jack_flips = 0;
887
888 arizona_start_mic(info);
889 } else {
Mark Brown0e27bd32013-02-05 21:00:15 +0000890 schedule_delayed_work(&info->hpdet_work,
891 msecs_to_jiffies(250));
Mark Browndd235ee2013-01-11 08:55:51 +0900892 }
Mark Brown4e616872013-01-15 22:09:20 +0900893
894 regmap_update_bits(arizona->regmap,
895 ARIZONA_JACK_DETECT_DEBOUNCE,
896 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +0100897 } else {
898 dev_dbg(arizona->dev, "Detected jack removal\n");
899
900 arizona_stop_mic(info);
901
Mark Browndd235ee2013-01-11 08:55:51 +0900902 info->num_hpdet_res = 0;
903 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
904 info->hpdet_res[i] = 0;
905 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +0000906 info->hpdet_done = false;
Mark Brown92a49872013-01-11 08:55:39 +0900907
Mark Brown34efe4d2012-07-20 17:07:29 +0100908 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
909 input_report_key(info->input,
910 arizona_lvl_to_key[i].report, 0);
911 input_sync(info->input);
912
Mark Brownf2c32a82012-06-24 12:09:45 +0100913 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
914 if (ret != 0)
915 dev_err(arizona->dev, "Removal report failed: %d\n",
916 ret);
Mark Brown4e616872013-01-15 22:09:20 +0900917
918 regmap_update_bits(arizona->regmap,
919 ARIZONA_JACK_DETECT_DEBOUNCE,
920 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
921 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +0100922 }
923
Charles Keepax5d9ab702013-02-05 10:13:38 +0000924 /* Clear trig_sts to make sure DCVDD is not forced up */
925 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
926 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
927 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
928 ARIZONA_JD1_FALL_TRIG_STS |
929 ARIZONA_JD1_RISE_TRIG_STS);
930
Mark Brownf2c32a82012-06-24 12:09:45 +0100931 mutex_unlock(&info->lock);
932
933 pm_runtime_mark_last_busy(info->dev);
934 pm_runtime_put_autosuspend(info->dev);
935
936 return IRQ_HANDLED;
937}
938
Bill Pemberton44f34fd2012-11-19 13:23:21 -0500939static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +0100940{
941 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
942 struct arizona_pdata *pdata;
943 struct arizona_extcon_info *info;
Mark Brown92a49872013-01-11 08:55:39 +0900944 int jack_irq_fall, jack_irq_rise;
Mark Brown34efe4d2012-07-20 17:07:29 +0100945 int ret, mode, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100946
Mark Brownbbbd46e2013-01-10 19:38:43 +0000947 if (!arizona->dapm || !arizona->dapm->card)
948 return -EPROBE_DEFER;
949
Mark Brownf2c32a82012-06-24 12:09:45 +0100950 pdata = dev_get_platdata(arizona->dev);
951
952 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
953 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +0900954 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100955 ret = -ENOMEM;
956 goto err;
957 }
958
959 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
960 if (IS_ERR(info->micvdd)) {
961 ret = PTR_ERR(info->micvdd);
962 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
963 goto err;
964 }
965
966 mutex_init(&info->lock);
967 info->arizona = arizona;
968 info->dev = &pdev->dev;
Mark Brown0e27bd32013-02-05 21:00:15 +0000969 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100970 platform_set_drvdata(pdev, info);
971
972 switch (arizona->type) {
973 case WM5102:
974 switch (arizona->rev) {
975 case 0:
976 info->micd_reva = true;
977 break;
978 default:
Mark Browndab63eb2013-01-11 08:55:36 +0900979 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +0900980 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +0100981 break;
982 }
983 break;
984 default:
985 break;
986 }
987
988 info->edev.name = "Headset Jack";
989 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +0100990
991 ret = extcon_dev_register(&info->edev, arizona->dev);
992 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +0900993 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +0100994 ret);
995 goto err;
996 }
997
998 if (pdata->num_micd_configs) {
999 info->micd_modes = pdata->micd_configs;
1000 info->micd_num_modes = pdata->num_micd_configs;
1001 } else {
1002 info->micd_modes = micd_default_modes;
1003 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1004 }
1005
1006 if (arizona->pdata.micd_pol_gpio > 0) {
1007 if (info->micd_modes[0].gpio)
1008 mode = GPIOF_OUT_INIT_HIGH;
1009 else
1010 mode = GPIOF_OUT_INIT_LOW;
1011
1012 ret = devm_gpio_request_one(&pdev->dev,
1013 arizona->pdata.micd_pol_gpio,
1014 mode,
1015 "MICD polarity");
1016 if (ret != 0) {
1017 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1018 arizona->pdata.micd_pol_gpio, ret);
1019 goto err_register;
1020 }
1021 }
1022
Mark Brown1eda6aa2013-01-11 08:55:54 +09001023 if (arizona->pdata.hpdet_id_gpio > 0) {
1024 ret = devm_gpio_request_one(&pdev->dev,
1025 arizona->pdata.hpdet_id_gpio,
1026 GPIOF_OUT_INIT_LOW,
1027 "HPDET");
1028 if (ret != 0) {
1029 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1030 arizona->pdata.hpdet_id_gpio, ret);
1031 goto err_register;
1032 }
1033 }
1034
Mark Brownb17e5462013-01-11 08:55:24 +09001035 if (arizona->pdata.micd_bias_start_time)
1036 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1037 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1038 arizona->pdata.micd_bias_start_time
1039 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1040
Mark Brown2e033db2013-01-21 17:36:33 +09001041 if (arizona->pdata.micd_rate)
1042 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1043 ARIZONA_MICD_RATE_MASK,
1044 arizona->pdata.micd_rate
1045 << ARIZONA_MICD_RATE_SHIFT);
1046
1047 if (arizona->pdata.micd_dbtime)
1048 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1049 ARIZONA_MICD_DBTIME_MASK,
1050 arizona->pdata.micd_dbtime
1051 << ARIZONA_MICD_DBTIME_SHIFT);
1052
Mark Browndab63eb2013-01-11 08:55:36 +09001053 /*
Mark Brown92a49872013-01-11 08:55:39 +09001054 * If we have a clamp use it, activating in conjunction with
1055 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001056 */
1057 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001058 if (arizona->pdata.jd_gpio5) {
1059 /* Put the GPIO into input mode */
1060 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
1061 0xc101);
1062
1063 regmap_update_bits(arizona->regmap,
1064 ARIZONA_MICD_CLAMP_CONTROL,
1065 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1066 } else {
1067 regmap_update_bits(arizona->regmap,
1068 ARIZONA_MICD_CLAMP_CONTROL,
1069 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1070 }
1071
Mark Browndab63eb2013-01-11 08:55:36 +09001072 regmap_update_bits(arizona->regmap,
1073 ARIZONA_JACK_DETECT_DEBOUNCE,
1074 ARIZONA_MICD_CLAMP_DB,
1075 ARIZONA_MICD_CLAMP_DB);
1076 }
1077
Mark Brownf2c32a82012-06-24 12:09:45 +01001078 arizona_extcon_set_mode(info, 0);
1079
Mark Brown3d44ea12013-01-11 08:51:13 +09001080 info->input = devm_input_allocate_device(&pdev->dev);
Mark Brown34efe4d2012-07-20 17:07:29 +01001081 if (!info->input) {
1082 dev_err(arizona->dev, "Can't allocate input dev\n");
1083 ret = -ENOMEM;
1084 goto err_register;
1085 }
1086
1087 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
1088 input_set_capability(info->input, EV_KEY,
1089 arizona_lvl_to_key[i].report);
1090 info->input->name = "Headset";
1091 info->input->phys = "arizona/extcon";
1092 info->input->dev.parent = &pdev->dev;
1093
Mark Brownf2c32a82012-06-24 12:09:45 +01001094 pm_runtime_enable(&pdev->dev);
1095 pm_runtime_idle(&pdev->dev);
1096 pm_runtime_get_sync(&pdev->dev);
1097
Mark Brown92a49872013-01-11 08:55:39 +09001098 if (arizona->pdata.jd_gpio5) {
1099 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1100 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1101 } else {
1102 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1103 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1104 }
1105
1106 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001107 "JACKDET rise", arizona_jackdet, info);
1108 if (ret != 0) {
1109 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1110 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001111 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001112 }
1113
Mark Brown92a49872013-01-11 08:55:39 +09001114 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001115 if (ret != 0) {
1116 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1117 ret);
1118 goto err_rise;
1119 }
1120
Mark Brown92a49872013-01-11 08:55:39 +09001121 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001122 "JACKDET fall", arizona_jackdet, info);
1123 if (ret != 0) {
1124 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1125 goto err_rise_wake;
1126 }
1127
Mark Brown92a49872013-01-11 08:55:39 +09001128 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001129 if (ret != 0) {
1130 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1131 ret);
1132 goto err_fall;
1133 }
1134
1135 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1136 "MICDET", arizona_micdet, info);
1137 if (ret != 0) {
1138 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1139 goto err_fall_wake;
1140 }
1141
Mark Brown4f340332013-01-11 08:55:43 +09001142 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1143 "HPDET", arizona_hpdet_irq, info);
1144 if (ret != 0) {
1145 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1146 goto err_micdet;
1147 }
1148
Mark Brownf2c32a82012-06-24 12:09:45 +01001149 arizona_clk32k_enable(arizona);
1150 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1151 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1152 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1153 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1154
Mark Brownb8575a12012-09-07 17:01:15 +08001155 ret = regulator_allow_bypass(info->micvdd, true);
1156 if (ret != 0)
1157 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1158 ret);
1159
Mark Brownf2c32a82012-06-24 12:09:45 +01001160 pm_runtime_put(&pdev->dev);
1161
Mark Brown34efe4d2012-07-20 17:07:29 +01001162 ret = input_register_device(info->input);
1163 if (ret) {
1164 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001165 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001166 }
1167
Mark Brownf2c32a82012-06-24 12:09:45 +01001168 return 0;
1169
Mark Brown4f340332013-01-11 08:55:43 +09001170err_hpdet:
1171 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001172err_micdet:
1173 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001174err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001175 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001176err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001177 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001178err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001179 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001180err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001181 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001182err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001183err_register:
1184 pm_runtime_disable(&pdev->dev);
1185 extcon_dev_unregister(&info->edev);
1186err:
1187 return ret;
1188}
1189
Bill Pemberton93ed0322012-11-19 13:25:49 -05001190static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001191{
1192 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1193 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001194 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001195
1196 pm_runtime_disable(&pdev->dev);
1197
Mark Browndab63eb2013-01-11 08:55:36 +09001198 regmap_update_bits(arizona->regmap,
1199 ARIZONA_MICD_CLAMP_CONTROL,
1200 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1201
Mark Brown92a49872013-01-11 08:55:39 +09001202 if (arizona->pdata.jd_gpio5) {
1203 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1204 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1205 } else {
1206 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1207 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1208 }
1209
1210 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1211 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1212 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001213 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001214 arizona_free_irq(arizona, jack_irq_rise, info);
1215 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001216 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001217 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1218 ARIZONA_JD1_ENA, 0);
1219 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001220 extcon_dev_unregister(&info->edev);
1221
1222 return 0;
1223}
1224
1225static struct platform_driver arizona_extcon_driver = {
1226 .driver = {
1227 .name = "arizona-extcon",
1228 .owner = THIS_MODULE,
1229 },
1230 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001231 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001232};
1233
1234module_platform_driver(arizona_extcon_driver);
1235
1236MODULE_DESCRIPTION("Arizona Extcon driver");
1237MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1238MODULE_LICENSE("GPL");
1239MODULE_ALIAS("platform:extcon-arizona");