extcon: arizona: Enable basic headphone identification
[deliverable/linux.git] / drivers / extcon / extcon-arizona.c
CommitLineData
f2c32a88
MB
1/*
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>
34efe4dc 24#include <linux/input.h>
f2c32a88
MB
25#include <linux/platform_device.h>
26#include <linux/pm_runtime.h>
27#include <linux/regulator/consumer.h>
28#include <linux/extcon.h>
29
30#include <linux/mfd/arizona/core.h>
31#include <linux/mfd/arizona/pdata.h>
32#include <linux/mfd/arizona/registers.h>
33
4f340333
MB
34#define ARIZONA_DEFAULT_HP 32
35
34efe4dc
MB
36#define ARIZONA_NUM_BUTTONS 6
37
4f340333
MB
38#define ARIZONA_ACCDET_MODE_MIC 0
39#define ARIZONA_ACCDET_MODE_HPL 1
40#define ARIZONA_ACCDET_MODE_HPR 2
41
f2c32a88
MB
42struct arizona_extcon_info {
43 struct device *dev;
44 struct arizona *arizona;
45 struct mutex lock;
46 struct regulator *micvdd;
34efe4dc 47 struct input_dev *input;
f2c32a88
MB
48
49 int micd_mode;
50 const struct arizona_micd_config *micd_modes;
51 int micd_num_modes;
52
53 bool micd_reva;
dab63eb2 54 bool micd_clamp;
f2c32a88 55
4f340333
MB
56 bool hpdet_active;
57
f2c32a88
MB
58 bool mic;
59 bool detecting;
60 int jack_flips;
61
4f340333
MB
62 int hpdet_ip;
63
f2c32a88
MB
64 struct extcon_dev edev;
65};
66
67static const struct arizona_micd_config micd_default_modes[] = {
68 { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
69 { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
70};
71
34efe4dc
MB
72static struct {
73 u16 status;
74 int report;
75} arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = {
76 { 0x1, BTN_0 },
77 { 0x2, BTN_1 },
78 { 0x4, BTN_2 },
79 { 0x8, BTN_3 },
80 { 0x10, BTN_4 },
81 { 0x20, BTN_5 },
82};
83
325c6423
MB
84#define ARIZONA_CABLE_MECHANICAL 0
85#define ARIZONA_CABLE_MICROPHONE 1
86#define ARIZONA_CABLE_HEADPHONE 2
4f340333 87#define ARIZONA_CABLE_LINEOUT 3
f2c32a88
MB
88
89static const char *arizona_cable[] = {
325c6423
MB
90 "Mechanical",
91 "Microphone",
92 "Headphone",
4f340333 93 "Line-out",
f2c32a88
MB
94 NULL,
95};
96
f2c32a88
MB
97static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
98{
99 struct arizona *arizona = info->arizona;
100
cd74f7b3
MB
101 if (arizona->pdata.micd_pol_gpio > 0)
102 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
103 info->micd_modes[mode].gpio);
f2c32a88
MB
104 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
105 ARIZONA_MICD_BIAS_SRC_MASK,
106 info->micd_modes[mode].bias);
107 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
108 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
109
110 info->micd_mode = mode;
111
112 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
113}
114
4f340333
MB
115static struct {
116 unsigned int factor_a;
117 unsigned int factor_b;
118} arizona_hpdet_b_ranges[] = {
119 { 5528, 362464 },
120 { 11084, 6186851 },
121 { 11065, 65460395 },
122};
123
124static struct {
125 int min;
126 int max;
127} arizona_hpdet_c_ranges[] = {
128 { 0, 30 },
129 { 8, 100 },
130 { 100, 1000 },
131 { 1000, 10000 },
132};
133
134static int arizona_hpdet_read(struct arizona_extcon_info *info)
135{
136 struct arizona *arizona = info->arizona;
137 unsigned int val, range;
138 int ret;
139
140 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
141 if (ret != 0) {
142 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
143 ret);
144 return ret;
145 }
146
147 switch (info->hpdet_ip) {
148 case 0:
149 if (!(val & ARIZONA_HP_DONE)) {
150 dev_err(arizona->dev, "HPDET did not complete: %x\n",
151 val);
152 val = ARIZONA_DEFAULT_HP;
153 }
154
155 val &= ARIZONA_HP_LVL_MASK;
156 break;
157
158 case 1:
159 if (!(val & ARIZONA_HP_DONE_B)) {
160 dev_err(arizona->dev, "HPDET did not complete: %x\n",
161 val);
162 return ARIZONA_DEFAULT_HP;
163 }
164
165 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
166 if (ret != 0) {
167 dev_err(arizona->dev, "Failed to read HP value: %d\n",
168 ret);
169 return ARIZONA_DEFAULT_HP;
170 }
171
172 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
173 &range);
174 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
175 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
176
177 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
178 (val < 100 || val > 0x3fb)) {
179 range++;
180 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
181 range);
182 regmap_update_bits(arizona->regmap,
183 ARIZONA_HEADPHONE_DETECT_1,
184 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
185 range <<
186 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
187 return -EAGAIN;
188 }
189
190 /* If we go out of range report top of range */
191 if (val < 100 || val > 0x3fb) {
192 dev_dbg(arizona->dev, "Measurement out of range\n");
193 return 10000;
194 }
195
196 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
197 val, range);
198
199 val = arizona_hpdet_b_ranges[range].factor_b
200 / ((val * 100) -
201 arizona_hpdet_b_ranges[range].factor_a);
202 break;
203
204 default:
205 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
206 info->hpdet_ip);
207 case 2:
208 if (!(val & ARIZONA_HP_DONE_B)) {
209 dev_err(arizona->dev, "HPDET did not complete: %x\n",
210 val);
211 return ARIZONA_DEFAULT_HP;
212 }
213
214 val &= ARIZONA_HP_LVL_B_MASK;
215
216 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
217 &range);
218 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
219 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
220
221 /* Skip up or down a range? */
222 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
223 range--;
224 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
225 arizona_hpdet_c_ranges[range].min,
226 arizona_hpdet_c_ranges[range].max);
227 regmap_update_bits(arizona->regmap,
228 ARIZONA_HEADPHONE_DETECT_1,
229 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
230 range <<
231 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
232 return -EAGAIN;
233 }
234
235 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
236 (val >= arizona_hpdet_c_ranges[range].max)) {
237 range++;
238 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
239 arizona_hpdet_c_ranges[range].min,
240 arizona_hpdet_c_ranges[range].max);
241 regmap_update_bits(arizona->regmap,
242 ARIZONA_HEADPHONE_DETECT_1,
243 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
244 range <<
245 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
246 return -EAGAIN;
247 }
248 }
249
250 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
251 return val;
252}
253
254static irqreturn_t arizona_hpdet_irq(int irq, void *data)
255{
256 struct arizona_extcon_info *info = data;
257 struct arizona *arizona = info->arizona;
258 int report = ARIZONA_CABLE_HEADPHONE;
259 int ret;
260
261 mutex_lock(&info->lock);
262
263 /* If we got a spurious IRQ for some reason then ignore it */
264 if (!info->hpdet_active) {
265 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
266 mutex_unlock(&info->lock);
267 return IRQ_NONE;
268 }
269
270 /* If the cable was removed while measuring ignore the result */
271 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
272 if (ret < 0) {
273 dev_err(arizona->dev, "Failed to check cable state: %d\n",
274 ret);
275 goto out;
276 } else if (!ret) {
277 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
278 goto done;
279 }
280
281 ret = arizona_hpdet_read(info);
282 if (ret == -EAGAIN) {
283 goto out;
284 } else if (ret < 0) {
285 goto done;
286 }
287
288 /* Reset back to starting range */
289 regmap_update_bits(arizona->regmap,
290 ARIZONA_HEADPHONE_DETECT_1,
291 ARIZONA_HP_IMPEDANCE_RANGE_MASK, 0);
292
293 /* Report high impedence cables as line outputs */
294 if (ret >= 5000)
295 report = ARIZONA_CABLE_LINEOUT;
296 else
297 report = ARIZONA_CABLE_HEADPHONE;
298
299 ret = extcon_set_cable_state_(&info->edev, report, true);
300 if (ret != 0)
301 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
302 ret);
303
304 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0);
305 if (ret != 0)
306 dev_warn(arizona->dev, "Failed to undo magic: %d\n", ret);
307
308 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0);
309 if (ret != 0)
310 dev_warn(arizona->dev, "Failed to undo magic: %d\n", ret);
311
312done:
313 regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
314 ARIZONA_HP_POLL, 0);
315
316 /* Revert back to MICDET mode */
317 regmap_update_bits(arizona->regmap,
318 ARIZONA_ACCESSORY_DETECT_MODE_1,
319 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
320
321 /* If we have a mic then reenable MICDET */
322 if (info->mic)
323 arizona_start_mic(info);
324
325 if (info->hpdet_active) {
326 pm_runtime_put_autosuspend(info->dev);
327 info->hpdet_active = false;
328 }
329
330out:
331 mutex_unlock(&info->lock);
332
333 return IRQ_HANDLED;
334}
335
336static void arizona_identify_headphone(struct arizona_extcon_info *info)
337{
338 struct arizona *arizona = info->arizona;
339 int ret;
340
341 dev_dbg(arizona->dev, "Starting HPDET\n");
342
343 /* Make sure we keep the device enabled during the measurement */
344 pm_runtime_get(info->dev);
345
346 info->hpdet_active = true;
347
348 if (info->mic)
349 arizona_stop_mic(info);
350
351 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000);
352 if (ret != 0)
353 dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
354
355 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000);
356 if (ret != 0)
357 dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
358
359 ret = regmap_update_bits(arizona->regmap,
360 ARIZONA_ACCESSORY_DETECT_MODE_1,
361 ARIZONA_ACCDET_MODE_MASK,
362 ARIZONA_ACCDET_MODE_HPL);
363 if (ret != 0) {
364 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
365 goto err;
366 }
367
368 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
369 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
370 if (ret != 0) {
371 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
372 ret);
373 goto err;
374 }
375
376 return;
377
378err:
379 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
380 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
381
382 /* Just report headphone */
383 ret = extcon_update_state(&info->edev,
384 1 << ARIZONA_CABLE_HEADPHONE,
385 1 << ARIZONA_CABLE_HEADPHONE);
386 if (ret != 0)
387 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
388
389 if (info->mic)
390 arizona_start_mic(info);
391
392 info->hpdet_active = false;
393}
394 }
395
396 info->hpdet_active = false;
397}
398
f2c32a88
MB
399static void arizona_start_mic(struct arizona_extcon_info *info)
400{
401 struct arizona *arizona = info->arizona;
402 bool change;
403 int ret;
404
405 info->detecting = true;
406 info->mic = false;
407 info->jack_flips = 0;
408
409 /* Microphone detection can't use idle mode */
410 pm_runtime_get(info->dev);
411
412 ret = regulator_enable(info->micvdd);
413 if (ret != 0) {
414 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
415 ret);
416 }
417
418 if (info->micd_reva) {
419 regmap_write(arizona->regmap, 0x80, 0x3);
420 regmap_write(arizona->regmap, 0x294, 0);
421 regmap_write(arizona->regmap, 0x80, 0x0);
422 }
423
4f340333
MB
424 regmap_update_bits(arizona->regmap,
425 ARIZONA_ACCESSORY_DETECT_MODE_1,
426 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
427
f2c32a88
MB
428 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
429 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
430 &change);
431 if (!change) {
432 regulator_disable(info->micvdd);
433 pm_runtime_put_autosuspend(info->dev);
434 }
435}
436
437static void arizona_stop_mic(struct arizona_extcon_info *info)
438{
439 struct arizona *arizona = info->arizona;
440 bool change;
441
442 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
443 ARIZONA_MICD_ENA, 0,
444 &change);
445
446 if (info->micd_reva) {
447 regmap_write(arizona->regmap, 0x80, 0x3);
448 regmap_write(arizona->regmap, 0x294, 2);
449 regmap_write(arizona->regmap, 0x80, 0x0);
450 }
451
452 if (change) {
453 regulator_disable(info->micvdd);
34efe4dc 454 pm_runtime_mark_last_busy(info->dev);
f2c32a88
MB
455 pm_runtime_put_autosuspend(info->dev);
456 }
457}
458
459static irqreturn_t arizona_micdet(int irq, void *data)
460{
461 struct arizona_extcon_info *info = data;
462 struct arizona *arizona = info->arizona;
34efe4dc
MB
463 unsigned int val, lvl;
464 int ret, i;
f2c32a88
MB
465
466 mutex_lock(&info->lock);
467
468 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
469 if (ret != 0) {
470 dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
be31cc0b 471 mutex_unlock(&info->lock);
f2c32a88
MB
472 return IRQ_NONE;
473 }
474
475 dev_dbg(arizona->dev, "MICDET: %x\n", val);
476
477 if (!(val & ARIZONA_MICD_VALID)) {
478 dev_warn(arizona->dev, "Microphone detection state invalid\n");
479 mutex_unlock(&info->lock);
480 return IRQ_NONE;
481 }
482
483 /* Due to jack detect this should never happen */
484 if (!(val & ARIZONA_MICD_STS)) {
485 dev_warn(arizona->dev, "Detected open circuit\n");
486 info->detecting = false;
487 goto handled;
488 }
489
490 /* If we got a high impedence we should have a headset, report it. */
491 if (info->detecting && (val & 0x400)) {
4f340333
MB
492 arizona_identify_headphone(info);
493
325c6423 494 ret = extcon_update_state(&info->edev,
4f340333
MB
495 1 << ARIZONA_CABLE_MICROPHONE,
496 1 << ARIZONA_CABLE_MICROPHONE);
f2c32a88
MB
497
498 if (ret != 0)
499 dev_err(arizona->dev, "Headset report failed: %d\n",
500 ret);
501
502 info->mic = true;
503 info->detecting = false;
504 goto handled;
505 }
506
507 /* If we detected a lower impedence during initial startup
508 * then we probably have the wrong polarity, flip it. Don't
509 * do this for the lowest impedences to speed up detection of
510 * plain headphones. If both polarities report a low
511 * impedence then give up and report headphones.
512 */
513 if (info->detecting && (val & 0x3f8)) {
514 info->jack_flips++;
515
516 if (info->jack_flips >= info->micd_num_modes) {
4f340333
MB
517 dev_dbg(arizona->dev, "Detected HP/line\n");
518 arizona_identify_headphone(info);
519
f2c32a88 520 info->detecting = false;
9ef2224d 521
4f340333 522 arizona_stop_mic(info);
f2c32a88
MB
523 } else {
524 info->micd_mode++;
525 if (info->micd_mode == info->micd_num_modes)
526 info->micd_mode = 0;
527 arizona_extcon_set_mode(info, info->micd_mode);
528
529 info->jack_flips++;
530 }
531
532 goto handled;
533 }
534
535 /*
536 * If we're still detecting and we detect a short then we've
34efe4dc 537 * got a headphone. Otherwise it's a button press.
f2c32a88
MB
538 */
539 if (val & 0x3fc) {
540 if (info->mic) {
541 dev_dbg(arizona->dev, "Mic button detected\n");
542
34efe4dc
MB
543 lvl = val & ARIZONA_MICD_LVL_MASK;
544 lvl >>= ARIZONA_MICD_LVL_SHIFT;
545
546 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
547 if (lvl & arizona_lvl_to_key[i].status)
548 input_report_key(info->input,
549 arizona_lvl_to_key[i].report,
550 1);
551 input_sync(info->input);
552
f2c32a88
MB
553 } else if (info->detecting) {
554 dev_dbg(arizona->dev, "Headphone detected\n");
555 info->detecting = false;
556 arizona_stop_mic(info);
557
4f340333 558 arizona_identify_headphone(info);
f2c32a88
MB
559 } else {
560 dev_warn(arizona->dev, "Button with no mic: %x\n",
561 val);
562 }
563 } else {
564 dev_dbg(arizona->dev, "Mic button released\n");
34efe4dc
MB
565 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
566 input_report_key(info->input,
567 arizona_lvl_to_key[i].report, 0);
568 input_sync(info->input);
f2c32a88
MB
569 }
570
571handled:
572 pm_runtime_mark_last_busy(info->dev);
573 mutex_unlock(&info->lock);
574
575 return IRQ_HANDLED;
576}
577
578static irqreturn_t arizona_jackdet(int irq, void *data)
579{
580 struct arizona_extcon_info *info = data;
581 struct arizona *arizona = info->arizona;
92a49871 582 unsigned int val, present, mask;
34efe4dc 583 int ret, i;
f2c32a88
MB
584
585 pm_runtime_get_sync(info->dev);
586
587 mutex_lock(&info->lock);
588
92a49871
MB
589 if (arizona->pdata.jd_gpio5) {
590 mask = ARIZONA_MICD_CLAMP_STS;
591 present = 0;
592 } else {
593 mask = ARIZONA_JD1_STS;
594 present = ARIZONA_JD1_STS;
595 }
596
f2c32a88
MB
597 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
598 if (ret != 0) {
599 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
600 ret);
601 mutex_unlock(&info->lock);
602 pm_runtime_put_autosuspend(info->dev);
603 return IRQ_NONE;
604 }
605
92a49871 606 if ((val & mask) == present) {
f2c32a88 607 dev_dbg(arizona->dev, "Detected jack\n");
325c6423
MB
608 ret = extcon_set_cable_state_(&info->edev,
609 ARIZONA_CABLE_MECHANICAL, true);
f2c32a88
MB
610
611 if (ret != 0)
612 dev_err(arizona->dev, "Mechanical report failed: %d\n",
613 ret);
614
615 arizona_start_mic(info);
616 } else {
617 dev_dbg(arizona->dev, "Detected jack removal\n");
618
619 arizona_stop_mic(info);
620
92a49871 621
34efe4dc
MB
622 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
623 input_report_key(info->input,
624 arizona_lvl_to_key[i].report, 0);
625 input_sync(info->input);
626
f2c32a88
MB
627 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
628 if (ret != 0)
629 dev_err(arizona->dev, "Removal report failed: %d\n",
630 ret);
631 }
632
633 mutex_unlock(&info->lock);
634
635 pm_runtime_mark_last_busy(info->dev);
636 pm_runtime_put_autosuspend(info->dev);
637
638 return IRQ_HANDLED;
639}
640
44f34fd4 641static int arizona_extcon_probe(struct platform_device *pdev)
f2c32a88
MB
642{
643 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
644 struct arizona_pdata *pdata;
645 struct arizona_extcon_info *info;
92a49871 646 int jack_irq_fall, jack_irq_rise;
34efe4dc 647 int ret, mode, i;
f2c32a88
MB
648
649 pdata = dev_get_platdata(arizona->dev);
650
651 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
652 if (!info) {
8e5f5018 653 dev_err(&pdev->dev, "Failed to allocate memory\n");
f2c32a88
MB
654 ret = -ENOMEM;
655 goto err;
656 }
657
658 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
659 if (IS_ERR(info->micvdd)) {
660 ret = PTR_ERR(info->micvdd);
661 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
662 goto err;
663 }
664
665 mutex_init(&info->lock);
666 info->arizona = arizona;
667 info->dev = &pdev->dev;
668 info->detecting = true;
669 platform_set_drvdata(pdev, info);
670
671 switch (arizona->type) {
672 case WM5102:
673 switch (arizona->rev) {
674 case 0:
675 info->micd_reva = true;
676 break;
677 default:
dab63eb2 678 info->micd_clamp = true;
4f340333 679 info->hpdet_ip = 1;
f2c32a88
MB
680 break;
681 }
682 break;
683 default:
684 break;
685 }
686
687 info->edev.name = "Headset Jack";
688 info->edev.supported_cable = arizona_cable;
f2c32a88
MB
689
690 ret = extcon_dev_register(&info->edev, arizona->dev);
691 if (ret < 0) {
8e5f5018 692 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
f2c32a88
MB
693 ret);
694 goto err;
695 }
696
697 if (pdata->num_micd_configs) {
698 info->micd_modes = pdata->micd_configs;
699 info->micd_num_modes = pdata->num_micd_configs;
700 } else {
701 info->micd_modes = micd_default_modes;
702 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
703 }
704
705 if (arizona->pdata.micd_pol_gpio > 0) {
706 if (info->micd_modes[0].gpio)
707 mode = GPIOF_OUT_INIT_HIGH;
708 else
709 mode = GPIOF_OUT_INIT_LOW;
710
711 ret = devm_gpio_request_one(&pdev->dev,
712 arizona->pdata.micd_pol_gpio,
713 mode,
714 "MICD polarity");
715 if (ret != 0) {
716 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
717 arizona->pdata.micd_pol_gpio, ret);
718 goto err_register;
719 }
720 }
721
b17e5462
MB
722 if (arizona->pdata.micd_bias_start_time)
723 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
724 ARIZONA_MICD_BIAS_STARTTIME_MASK,
725 arizona->pdata.micd_bias_start_time
726 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
727
dab63eb2 728 /*
92a49871
MB
729 * If we have a clamp use it, activating in conjunction with
730 * GPIO5 if that is connected for jack detect operation.
dab63eb2
MB
731 */
732 if (info->micd_clamp) {
92a49871
MB
733 if (arizona->pdata.jd_gpio5) {
734 /* Put the GPIO into input mode */
735 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
736 0xc101);
737
738 regmap_update_bits(arizona->regmap,
739 ARIZONA_MICD_CLAMP_CONTROL,
740 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
741 } else {
742 regmap_update_bits(arizona->regmap,
743 ARIZONA_MICD_CLAMP_CONTROL,
744 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
745 }
746
dab63eb2
MB
747 regmap_update_bits(arizona->regmap,
748 ARIZONA_JACK_DETECT_DEBOUNCE,
749 ARIZONA_MICD_CLAMP_DB,
750 ARIZONA_MICD_CLAMP_DB);
751 }
752
f2c32a88
MB
753 arizona_extcon_set_mode(info, 0);
754
3d44ea1c 755 info->input = devm_input_allocate_device(&pdev->dev);
34efe4dc
MB
756 if (!info->input) {
757 dev_err(arizona->dev, "Can't allocate input dev\n");
758 ret = -ENOMEM;
759 goto err_register;
760 }
761
762 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
763 input_set_capability(info->input, EV_KEY,
764 arizona_lvl_to_key[i].report);
765 info->input->name = "Headset";
766 info->input->phys = "arizona/extcon";
767 info->input->dev.parent = &pdev->dev;
768
f2c32a88
MB
769 pm_runtime_enable(&pdev->dev);
770 pm_runtime_idle(&pdev->dev);
771 pm_runtime_get_sync(&pdev->dev);
772
92a49871
MB
773 if (arizona->pdata.jd_gpio5) {
774 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
775 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
776 } else {
777 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
778 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
779 }
780
781 ret = arizona_request_irq(arizona, jack_irq_rise,
f2c32a88
MB
782 "JACKDET rise", arizona_jackdet, info);
783 if (ret != 0) {
784 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
785 ret);
34efe4dc 786 goto err_input;
f2c32a88
MB
787 }
788
92a49871 789 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
f2c32a88
MB
790 if (ret != 0) {
791 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
792 ret);
793 goto err_rise;
794 }
795
92a49871 796 ret = arizona_request_irq(arizona, jack_irq_fall,
f2c32a88
MB
797 "JACKDET fall", arizona_jackdet, info);
798 if (ret != 0) {
799 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
800 goto err_rise_wake;
801 }
802
92a49871 803 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
f2c32a88
MB
804 if (ret != 0) {
805 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
806 ret);
807 goto err_fall;
808 }
809
810 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
811 "MICDET", arizona_micdet, info);
812 if (ret != 0) {
813 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
814 goto err_fall_wake;
815 }
816
4f340333
MB
817 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
818 "HPDET", arizona_hpdet_irq, info);
819 if (ret != 0) {
820 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
821 goto err_micdet;
822 }
823
f2c32a88 824 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
f2c32a88 825 ARIZONA_MICD_RATE_MASK,
f2c32a88
MB
826 8 << ARIZONA_MICD_RATE_SHIFT);
827
828 arizona_clk32k_enable(arizona);
829 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
830 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
831 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
832 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
833
b8575a11
MB
834 ret = regulator_allow_bypass(info->micvdd, true);
835 if (ret != 0)
836 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
837 ret);
838
f2c32a88
MB
839 pm_runtime_put(&pdev->dev);
840
34efe4dc
MB
841 ret = input_register_device(info->input);
842 if (ret) {
843 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
4f340333 844 goto err_hpdet;
34efe4dc
MB
845 }
846
f2c32a88
MB
847 return 0;
848
4f340333
MB
849err_hpdet:
850 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
80732cc1
MB
851err_micdet:
852 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
f2c32a88 853err_fall_wake:
92a49871 854 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
f2c32a88 855err_fall:
92a49871 856 arizona_free_irq(arizona, jack_irq_fall, info);
f2c32a88 857err_rise_wake:
92a49871 858 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
f2c32a88 859err_rise:
92a49871 860 arizona_free_irq(arizona, jack_irq_rise, info);
34efe4dc 861err_input:
f2c32a88
MB
862err_register:
863 pm_runtime_disable(&pdev->dev);
864 extcon_dev_unregister(&info->edev);
865err:
866 return ret;
867}
868
93ed0327 869static int arizona_extcon_remove(struct platform_device *pdev)
f2c32a88
MB
870{
871 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
872 struct arizona *arizona = info->arizona;
92a49871 873 int jack_irq_rise, jack_irq_fall;
f2c32a88
MB
874
875 pm_runtime_disable(&pdev->dev);
876
dab63eb2
MB
877 regmap_update_bits(arizona->regmap,
878 ARIZONA_MICD_CLAMP_CONTROL,
879 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
880
92a49871
MB
881 if (arizona->pdata.jd_gpio5) {
882 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
883 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
884 } else {
885 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
886 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
887 }
888
889 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
890 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
891 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
f2c32a88 892 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
92a49871
MB
893 arizona_free_irq(arizona, jack_irq_rise, info);
894 arizona_free_irq(arizona, jack_irq_fall, info);
f2c32a88
MB
895 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
896 ARIZONA_JD1_ENA, 0);
897 arizona_clk32k_disable(arizona);
898 extcon_dev_unregister(&info->edev);
899
900 return 0;
901}
902
903static struct platform_driver arizona_extcon_driver = {
904 .driver = {
905 .name = "arizona-extcon",
906 .owner = THIS_MODULE,
907 },
908 .probe = arizona_extcon_probe,
5f7e2228 909 .remove = arizona_extcon_remove,
f2c32a88
MB
910};
911
912module_platform_driver(arizona_extcon_driver);
913
914MODULE_DESCRIPTION("Arizona Extcon driver");
915MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
916MODULE_LICENSE("GPL");
917MODULE_ALIAS("platform:extcon-arizona");
This page took 0.0909180000000001 seconds and 5 git commands to generate.