blob: b289279721280429406b2cdedb890e7f0bb21b92 [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;
Mark Brown03409072013-02-12 13:00:31 +0000107 int ret;
108
109 mutex_lock(&arizona->dapm->card->dapm_mutex);
110
Mark Browndf8c3db2013-02-22 18:38:03 +0000111 arizona->hpdet_magic = magic;
112
113 /* Keep the HP output stages disabled while doing the magic */
114 if (magic) {
115 ret = regmap_update_bits(arizona->regmap,
116 ARIZONA_OUTPUT_ENABLES_1,
117 ARIZONA_OUT1L_ENA |
118 ARIZONA_OUT1R_ENA, 0);
119 if (ret != 0)
120 dev_warn(arizona->dev,
121 "Failed to disable headphone outputs: %d\n",
122 ret);
Mark Brown03409072013-02-12 13:00:31 +0000123 }
124
Mark Browndf8c3db2013-02-22 18:38:03 +0000125 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
126 magic);
127 if (ret != 0)
128 dev_warn(arizona->dev, "Failed to do magic: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000129 ret);
130
Mark Browndf8c3db2013-02-22 18:38:03 +0000131 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
132 magic);
133 if (ret != 0)
134 dev_warn(arizona->dev, "Failed to do magic: %d\n",
135 ret);
136
137 /* Restore the desired state while not doing the magic */
138 if (!magic) {
139 ret = regmap_update_bits(arizona->regmap,
140 ARIZONA_OUTPUT_ENABLES_1,
141 ARIZONA_OUT1L_ENA |
142 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000143 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000144 dev_warn(arizona->dev,
145 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000146 ret);
147 }
148
149 mutex_unlock(&arizona->dapm->card->dapm_mutex);
150}
151
Mark Brownf2c32a82012-06-24 12:09:45 +0100152static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
153{
154 struct arizona *arizona = info->arizona;
155
Mark Browncd74f7b2012-11-27 16:14:26 +0900156 if (arizona->pdata.micd_pol_gpio > 0)
157 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
158 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100159 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
160 ARIZONA_MICD_BIAS_SRC_MASK,
161 info->micd_modes[mode].bias);
162 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
163 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
164
165 info->micd_mode = mode;
166
167 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
168}
169
Mark Brownbbbd46e2013-01-10 19:38:43 +0000170static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
171{
172 switch (info->micd_modes[0].bias >> ARIZONA_MICD_BIAS_SRC_SHIFT) {
173 case 1:
174 return "MICBIAS1";
175 case 2:
176 return "MICBIAS2";
177 case 3:
178 return "MICBIAS3";
179 default:
180 return "MICVDD";
181 }
182}
183
184static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
185{
186 struct arizona *arizona = info->arizona;
187 const char *widget = arizona_extcon_get_micbias(info);
188 struct snd_soc_dapm_context *dapm = arizona->dapm;
189 int ret;
190
191 mutex_lock(&dapm->card->dapm_mutex);
192
193 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
194 if (ret != 0)
195 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
196 widget, ret);
197
198 mutex_unlock(&dapm->card->dapm_mutex);
199
200 snd_soc_dapm_sync(dapm);
201
202 if (!arizona->pdata.micd_force_micbias) {
203 mutex_lock(&dapm->card->dapm_mutex);
204
205 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
206 if (ret != 0)
207 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
208 widget, ret);
209
210 mutex_unlock(&dapm->card->dapm_mutex);
211
212 snd_soc_dapm_sync(dapm);
213 }
214}
215
Mark Brown9b1270c2013-01-11 08:55:46 +0900216static void arizona_start_mic(struct arizona_extcon_info *info)
217{
218 struct arizona *arizona = info->arizona;
219 bool change;
220 int ret;
221
Mark Brown9b1270c2013-01-11 08:55:46 +0900222 /* Microphone detection can't use idle mode */
223 pm_runtime_get(info->dev);
224
Mark Brownbbbd46e2013-01-10 19:38:43 +0000225 if (info->detecting) {
226 ret = regulator_allow_bypass(info->micvdd, false);
227 if (ret != 0) {
228 dev_err(arizona->dev,
229 "Failed to regulate MICVDD: %d\n",
230 ret);
231 }
232 }
233
Mark Brown9b1270c2013-01-11 08:55:46 +0900234 ret = regulator_enable(info->micvdd);
235 if (ret != 0) {
236 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
237 ret);
238 }
239
240 if (info->micd_reva) {
241 regmap_write(arizona->regmap, 0x80, 0x3);
242 regmap_write(arizona->regmap, 0x294, 0);
243 regmap_write(arizona->regmap, 0x80, 0x0);
244 }
245
246 regmap_update_bits(arizona->regmap,
247 ARIZONA_ACCESSORY_DETECT_MODE_1,
248 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
249
Mark Brownbbbd46e2013-01-10 19:38:43 +0000250 arizona_extcon_pulse_micbias(info);
251
Mark Brown9b1270c2013-01-11 08:55:46 +0900252 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
253 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
254 &change);
255 if (!change) {
256 regulator_disable(info->micvdd);
257 pm_runtime_put_autosuspend(info->dev);
258 }
259}
260
261static void arizona_stop_mic(struct arizona_extcon_info *info)
262{
263 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000264 const char *widget = arizona_extcon_get_micbias(info);
265 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900266 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000267 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900268
269 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
270 ARIZONA_MICD_ENA, 0,
271 &change);
272
Mark Brownbbbd46e2013-01-10 19:38:43 +0000273 mutex_lock(&dapm->card->dapm_mutex);
274
275 ret = snd_soc_dapm_disable_pin(dapm, widget);
276 if (ret != 0)
277 dev_warn(arizona->dev,
278 "Failed to disable %s: %d\n",
279 widget, ret);
280
281 mutex_unlock(&dapm->card->dapm_mutex);
282
283 snd_soc_dapm_sync(dapm);
284
Mark Brown9b1270c2013-01-11 08:55:46 +0900285 if (info->micd_reva) {
286 regmap_write(arizona->regmap, 0x80, 0x3);
287 regmap_write(arizona->regmap, 0x294, 2);
288 regmap_write(arizona->regmap, 0x80, 0x0);
289 }
290
Mark Brownbbbd46e2013-01-10 19:38:43 +0000291 ret = regulator_allow_bypass(info->micvdd, true);
292 if (ret != 0) {
293 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
294 ret);
295 }
296
Mark Brown9b1270c2013-01-11 08:55:46 +0900297 if (change) {
298 regulator_disable(info->micvdd);
299 pm_runtime_mark_last_busy(info->dev);
300 pm_runtime_put_autosuspend(info->dev);
301 }
302}
303
Mark Brown4f340332013-01-11 08:55:43 +0900304static struct {
305 unsigned int factor_a;
306 unsigned int factor_b;
307} arizona_hpdet_b_ranges[] = {
308 { 5528, 362464 },
309 { 11084, 6186851 },
310 { 11065, 65460395 },
311};
312
313static struct {
314 int min;
315 int max;
316} arizona_hpdet_c_ranges[] = {
317 { 0, 30 },
318 { 8, 100 },
319 { 100, 1000 },
320 { 1000, 10000 },
321};
322
323static int arizona_hpdet_read(struct arizona_extcon_info *info)
324{
325 struct arizona *arizona = info->arizona;
326 unsigned int val, range;
327 int ret;
328
329 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
330 if (ret != 0) {
331 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
332 ret);
333 return ret;
334 }
335
336 switch (info->hpdet_ip) {
337 case 0:
338 if (!(val & ARIZONA_HP_DONE)) {
339 dev_err(arizona->dev, "HPDET did not complete: %x\n",
340 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900341 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900342 }
343
344 val &= ARIZONA_HP_LVL_MASK;
345 break;
346
347 case 1:
348 if (!(val & ARIZONA_HP_DONE_B)) {
349 dev_err(arizona->dev, "HPDET did not complete: %x\n",
350 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900351 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900352 }
353
354 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
355 if (ret != 0) {
356 dev_err(arizona->dev, "Failed to read HP value: %d\n",
357 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900358 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900359 }
360
361 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
362 &range);
363 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
364 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
365
366 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
367 (val < 100 || val > 0x3fb)) {
368 range++;
369 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
370 range);
371 regmap_update_bits(arizona->regmap,
372 ARIZONA_HEADPHONE_DETECT_1,
373 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
374 range <<
375 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
376 return -EAGAIN;
377 }
378
379 /* If we go out of range report top of range */
380 if (val < 100 || val > 0x3fb) {
381 dev_dbg(arizona->dev, "Measurement out of range\n");
382 return 10000;
383 }
384
385 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
386 val, range);
387
388 val = arizona_hpdet_b_ranges[range].factor_b
389 / ((val * 100) -
390 arizona_hpdet_b_ranges[range].factor_a);
391 break;
392
393 default:
394 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
395 info->hpdet_ip);
396 case 2:
397 if (!(val & ARIZONA_HP_DONE_B)) {
398 dev_err(arizona->dev, "HPDET did not complete: %x\n",
399 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900400 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900401 }
402
403 val &= ARIZONA_HP_LVL_B_MASK;
404
405 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
406 &range);
407 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
408 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
409
410 /* Skip up or down a range? */
411 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
412 range--;
413 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
414 arizona_hpdet_c_ranges[range].min,
415 arizona_hpdet_c_ranges[range].max);
416 regmap_update_bits(arizona->regmap,
417 ARIZONA_HEADPHONE_DETECT_1,
418 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
419 range <<
420 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
421 return -EAGAIN;
422 }
423
424 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
425 (val >= arizona_hpdet_c_ranges[range].max)) {
426 range++;
427 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
428 arizona_hpdet_c_ranges[range].min,
429 arizona_hpdet_c_ranges[range].max);
430 regmap_update_bits(arizona->regmap,
431 ARIZONA_HEADPHONE_DETECT_1,
432 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
433 range <<
434 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
435 return -EAGAIN;
436 }
437 }
438
439 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
440 return val;
441}
442
Mark Browndd235ee2013-01-11 08:55:51 +0900443static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
444{
445 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900446 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900447
448 /*
449 * If we're using HPDET for accessory identification we need
450 * to take multiple measurements, step through them in sequence.
451 */
452 if (arizona->pdata.hpdet_acc_id) {
453 info->hpdet_res[info->num_hpdet_res++] = *reading;
454
455 /*
456 * If the impedence is too high don't measure the
457 * second ground.
458 */
459 if (info->num_hpdet_res == 1 && *reading >= 45) {
460 dev_dbg(arizona->dev, "Skipping ground flip\n");
461 info->hpdet_res[info->num_hpdet_res++] = *reading;
462 }
463
464 if (info->num_hpdet_res == 1) {
465 dev_dbg(arizona->dev, "Flipping ground\n");
466
467 regmap_update_bits(arizona->regmap,
468 ARIZONA_ACCESSORY_DETECT_MODE_1,
469 ARIZONA_ACCDET_SRC,
470 ~info->micd_modes[0].src);
Mark Brown1eda6aa2013-01-11 08:55:54 +0900471
Mark Browndd235ee2013-01-11 08:55:51 +0900472 regmap_update_bits(arizona->regmap,
473 ARIZONA_HEADPHONE_DETECT_1,
Mark Brown1eda6aa2013-01-11 08:55:54 +0900474 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
475 return -EAGAIN;
476 }
477
478 /* Only check the mic directly if we didn't already ID it */
479 if (id_gpio && info->num_hpdet_res == 2 &&
480 !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) {
481 dev_dbg(arizona->dev, "Measuring mic\n");
482
483 regmap_update_bits(arizona->regmap,
484 ARIZONA_ACCESSORY_DETECT_MODE_1,
485 ARIZONA_ACCDET_MODE_MASK |
486 ARIZONA_ACCDET_SRC,
487 ARIZONA_ACCDET_MODE_HPR |
488 info->micd_modes[0].src);
489
490 gpio_set_value_cansleep(id_gpio, 1);
491
Mark Browndd235ee2013-01-11 08:55:51 +0900492 regmap_update_bits(arizona->regmap,
493 ARIZONA_HEADPHONE_DETECT_1,
494 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
495 return -EAGAIN;
496 }
497
498 /* OK, got both. Now, compare... */
Mark Brown1eda6aa2013-01-11 08:55:54 +0900499 dev_dbg(arizona->dev, "HPDET measured %d %d %d\n",
500 info->hpdet_res[0], info->hpdet_res[1],
501 info->hpdet_res[2]);
Mark Browndd235ee2013-01-11 08:55:51 +0900502
Mark Brownc37b3872013-02-05 17:48:49 +0000503
504 /* Take the headphone impedance for the main report */
505 *reading = info->hpdet_res[0];
506
Mark Brown1eda6aa2013-01-11 08:55:54 +0900507 /*
508 * Either the two grounds measure differently or we
509 * measure the mic as high impedance.
510 */
511 if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) ||
512 (id_gpio && info->hpdet_res[2] > 10)) {
Mark Browndd235ee2013-01-11 08:55:51 +0900513 dev_dbg(arizona->dev, "Detected mic\n");
514 info->mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000515 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900516 } else {
517 dev_dbg(arizona->dev, "Detected headphone\n");
518 }
519
520 /* Make sure everything is reset back to the real polarity */
521 regmap_update_bits(arizona->regmap,
522 ARIZONA_ACCESSORY_DETECT_MODE_1,
523 ARIZONA_ACCDET_SRC,
524 info->micd_modes[0].src);
525 }
526
527 return 0;
528}
529
Mark Brown4f340332013-01-11 08:55:43 +0900530static irqreturn_t arizona_hpdet_irq(int irq, void *data)
531{
532 struct arizona_extcon_info *info = data;
533 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900534 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900535 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900536 int ret, reading;
Mark Brown4f340332013-01-11 08:55:43 +0900537
538 mutex_lock(&info->lock);
539
540 /* If we got a spurious IRQ for some reason then ignore it */
541 if (!info->hpdet_active) {
542 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
543 mutex_unlock(&info->lock);
544 return IRQ_NONE;
545 }
546
547 /* If the cable was removed while measuring ignore the result */
548 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
549 if (ret < 0) {
550 dev_err(arizona->dev, "Failed to check cable state: %d\n",
551 ret);
552 goto out;
553 } else if (!ret) {
554 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
555 goto done;
556 }
557
558 ret = arizona_hpdet_read(info);
559 if (ret == -EAGAIN) {
560 goto out;
561 } else if (ret < 0) {
562 goto done;
563 }
Mark Browndd235ee2013-01-11 08:55:51 +0900564 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900565
566 /* Reset back to starting range */
567 regmap_update_bits(arizona->regmap,
568 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900569 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
570 0);
571
572 ret = arizona_hpdet_do_id(info, &reading);
573 if (ret == -EAGAIN) {
574 goto out;
575 } else if (ret < 0) {
576 goto done;
577 }
Mark Brown4f340332013-01-11 08:55:43 +0900578
579 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900580 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900581 report = ARIZONA_CABLE_LINEOUT;
582 else
583 report = ARIZONA_CABLE_HEADPHONE;
584
585 ret = extcon_set_cable_state_(&info->edev, report, true);
586 if (ret != 0)
587 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
588 ret);
589
Mark Brown03409072013-02-12 13:00:31 +0000590 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900591
592done:
Mark Brown1eda6aa2013-01-11 08:55:54 +0900593 if (id_gpio)
594 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900595
596 /* Revert back to MICDET mode */
597 regmap_update_bits(arizona->regmap,
598 ARIZONA_ACCESSORY_DETECT_MODE_1,
599 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
600
601 /* If we have a mic then reenable MICDET */
602 if (info->mic)
603 arizona_start_mic(info);
604
605 if (info->hpdet_active) {
606 pm_runtime_put_autosuspend(info->dev);
607 info->hpdet_active = false;
608 }
609
Mark Brownbf14ee52013-02-05 20:20:17 +0000610 info->hpdet_done = true;
611
Mark Brown4f340332013-01-11 08:55:43 +0900612out:
613 mutex_unlock(&info->lock);
614
615 return IRQ_HANDLED;
616}
617
618static void arizona_identify_headphone(struct arizona_extcon_info *info)
619{
620 struct arizona *arizona = info->arizona;
621 int ret;
622
Mark Brownbf14ee52013-02-05 20:20:17 +0000623 if (info->hpdet_done)
624 return;
625
Mark Brown4f340332013-01-11 08:55:43 +0900626 dev_dbg(arizona->dev, "Starting HPDET\n");
627
628 /* Make sure we keep the device enabled during the measurement */
629 pm_runtime_get(info->dev);
630
631 info->hpdet_active = true;
632
633 if (info->mic)
634 arizona_stop_mic(info);
635
Mark Brown03409072013-02-12 13:00:31 +0000636 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900637
638 ret = regmap_update_bits(arizona->regmap,
639 ARIZONA_ACCESSORY_DETECT_MODE_1,
640 ARIZONA_ACCDET_MODE_MASK,
641 ARIZONA_ACCDET_MODE_HPL);
642 if (ret != 0) {
643 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
644 goto err;
645 }
646
647 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
648 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
649 if (ret != 0) {
650 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
651 ret);
652 goto err;
653 }
654
655 return;
656
657err:
658 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
659 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
660
661 /* Just report headphone */
662 ret = extcon_update_state(&info->edev,
663 1 << ARIZONA_CABLE_HEADPHONE,
664 1 << ARIZONA_CABLE_HEADPHONE);
665 if (ret != 0)
666 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
667
668 if (info->mic)
669 arizona_start_mic(info);
670
671 info->hpdet_active = false;
672}
Mark Browndd235ee2013-01-11 08:55:51 +0900673
674static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
675{
676 struct arizona *arizona = info->arizona;
677 int ret;
678
679 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
680
681 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000682 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900683
684 info->hpdet_active = true;
685
Mark Brownbbbd46e2013-01-10 19:38:43 +0000686 arizona_extcon_pulse_micbias(info);
687
Mark Brown03409072013-02-12 13:00:31 +0000688 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900689
690 ret = regmap_update_bits(arizona->regmap,
691 ARIZONA_ACCESSORY_DETECT_MODE_1,
692 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
693 info->micd_modes[0].src |
694 ARIZONA_ACCDET_MODE_HPL);
695 if (ret != 0) {
696 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
697 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900698 }
699
Mark Browndd235ee2013-01-11 08:55:51 +0900700 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
701 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
702 if (ret != 0) {
703 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
704 ret);
705 goto err;
706 }
707
708 return;
709
710err:
711 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
712 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
713
714 /* Just report headphone */
715 ret = extcon_update_state(&info->edev,
716 1 << ARIZONA_CABLE_HEADPHONE,
717 1 << ARIZONA_CABLE_HEADPHONE);
718 if (ret != 0)
719 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
720
Mark Brown4f340332013-01-11 08:55:43 +0900721 info->hpdet_active = false;
722}
723
Mark Brownf2c32a82012-06-24 12:09:45 +0100724static irqreturn_t arizona_micdet(int irq, void *data)
725{
726 struct arizona_extcon_info *info = data;
727 struct arizona *arizona = info->arizona;
Mark Brown34efe4d2012-07-20 17:07:29 +0100728 unsigned int val, lvl;
729 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100730
731 mutex_lock(&info->lock);
732
733 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
734 if (ret != 0) {
735 dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
Alexey Khoroshilovbe31cc02012-11-05 17:11:41 +0900736 mutex_unlock(&info->lock);
Mark Brownf2c32a82012-06-24 12:09:45 +0100737 return IRQ_NONE;
738 }
739
740 dev_dbg(arizona->dev, "MICDET: %x\n", val);
741
742 if (!(val & ARIZONA_MICD_VALID)) {
743 dev_warn(arizona->dev, "Microphone detection state invalid\n");
744 mutex_unlock(&info->lock);
745 return IRQ_NONE;
746 }
747
748 /* Due to jack detect this should never happen */
749 if (!(val & ARIZONA_MICD_STS)) {
750 dev_warn(arizona->dev, "Detected open circuit\n");
751 info->detecting = false;
752 goto handled;
753 }
754
755 /* If we got a high impedence we should have a headset, report it. */
756 if (info->detecting && (val & 0x400)) {
Mark Brown4f340332013-01-11 08:55:43 +0900757 arizona_identify_headphone(info);
758
Mark Brown325c6422012-06-28 13:08:30 +0100759 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900760 1 << ARIZONA_CABLE_MICROPHONE,
761 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100762
763 if (ret != 0)
764 dev_err(arizona->dev, "Headset report failed: %d\n",
765 ret);
766
Mark Brownbbbd46e2013-01-10 19:38:43 +0000767 /* Don't need to regulate for button detection */
768 ret = regulator_allow_bypass(info->micvdd, false);
769 if (ret != 0) {
770 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
771 ret);
772 }
773
Mark Brownf2c32a82012-06-24 12:09:45 +0100774 info->mic = true;
775 info->detecting = false;
776 goto handled;
777 }
778
779 /* If we detected a lower impedence during initial startup
780 * then we probably have the wrong polarity, flip it. Don't
781 * do this for the lowest impedences to speed up detection of
782 * plain headphones. If both polarities report a low
783 * impedence then give up and report headphones.
784 */
785 if (info->detecting && (val & 0x3f8)) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100786 if (info->jack_flips >= info->micd_num_modes) {
Mark Brown4f340332013-01-11 08:55:43 +0900787 dev_dbg(arizona->dev, "Detected HP/line\n");
788 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100789
Mark Brown4f340332013-01-11 08:55:43 +0900790 info->detecting = false;
791
792 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100793 } else {
794 info->micd_mode++;
795 if (info->micd_mode == info->micd_num_modes)
796 info->micd_mode = 0;
797 arizona_extcon_set_mode(info, info->micd_mode);
798
799 info->jack_flips++;
800 }
801
802 goto handled;
803 }
804
805 /*
806 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100807 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100808 */
809 if (val & 0x3fc) {
810 if (info->mic) {
811 dev_dbg(arizona->dev, "Mic button detected\n");
812
Mark Brown34efe4d2012-07-20 17:07:29 +0100813 lvl = val & ARIZONA_MICD_LVL_MASK;
814 lvl >>= ARIZONA_MICD_LVL_SHIFT;
815
816 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
817 if (lvl & arizona_lvl_to_key[i].status)
818 input_report_key(info->input,
819 arizona_lvl_to_key[i].report,
820 1);
821 input_sync(info->input);
822
Mark Brownf2c32a82012-06-24 12:09:45 +0100823 } else if (info->detecting) {
824 dev_dbg(arizona->dev, "Headphone detected\n");
825 info->detecting = false;
826 arizona_stop_mic(info);
827
Mark Brown4f340332013-01-11 08:55:43 +0900828 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100829 } else {
830 dev_warn(arizona->dev, "Button with no mic: %x\n",
831 val);
832 }
833 } else {
834 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown34efe4d2012-07-20 17:07:29 +0100835 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
836 input_report_key(info->input,
837 arizona_lvl_to_key[i].report, 0);
838 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000839 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100840 }
841
842handled:
843 pm_runtime_mark_last_busy(info->dev);
844 mutex_unlock(&info->lock);
845
846 return IRQ_HANDLED;
847}
848
Mark Brown0e27bd32013-02-05 21:00:15 +0000849static void arizona_hpdet_work(struct work_struct *work)
850{
851 struct arizona_extcon_info *info = container_of(work,
852 struct arizona_extcon_info,
853 hpdet_work.work);
854
855 mutex_lock(&info->lock);
856 arizona_start_hpdet_acc_id(info);
857 mutex_unlock(&info->lock);
858}
859
Mark Brownf2c32a82012-06-24 12:09:45 +0100860static irqreturn_t arizona_jackdet(int irq, void *data)
861{
862 struct arizona_extcon_info *info = data;
863 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900864 unsigned int val, present, mask;
Mark Brown34efe4d2012-07-20 17:07:29 +0100865 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100866
867 pm_runtime_get_sync(info->dev);
868
Mark Brown0e27bd32013-02-05 21:00:15 +0000869 cancel_delayed_work_sync(&info->hpdet_work);
870
Mark Brownf2c32a82012-06-24 12:09:45 +0100871 mutex_lock(&info->lock);
872
Mark Brown92a49872013-01-11 08:55:39 +0900873 if (arizona->pdata.jd_gpio5) {
874 mask = ARIZONA_MICD_CLAMP_STS;
875 present = 0;
876 } else {
877 mask = ARIZONA_JD1_STS;
878 present = ARIZONA_JD1_STS;
879 }
880
Mark Brownf2c32a82012-06-24 12:09:45 +0100881 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
882 if (ret != 0) {
883 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
884 ret);
885 mutex_unlock(&info->lock);
886 pm_runtime_put_autosuspend(info->dev);
887 return IRQ_NONE;
888 }
889
Mark Brown92a49872013-01-11 08:55:39 +0900890 if ((val & mask) == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100891 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +0100892 ret = extcon_set_cable_state_(&info->edev,
893 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100894
895 if (ret != 0)
896 dev_err(arizona->dev, "Mechanical report failed: %d\n",
897 ret);
898
Mark Browndd235ee2013-01-11 08:55:51 +0900899 if (!arizona->pdata.hpdet_acc_id) {
900 info->detecting = true;
901 info->mic = false;
902 info->jack_flips = 0;
903
904 arizona_start_mic(info);
905 } else {
Mark Brown0e27bd32013-02-05 21:00:15 +0000906 schedule_delayed_work(&info->hpdet_work,
907 msecs_to_jiffies(250));
Mark Browndd235ee2013-01-11 08:55:51 +0900908 }
Mark Brown4e616872013-01-15 22:09:20 +0900909
910 regmap_update_bits(arizona->regmap,
911 ARIZONA_JACK_DETECT_DEBOUNCE,
912 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +0100913 } else {
914 dev_dbg(arizona->dev, "Detected jack removal\n");
915
916 arizona_stop_mic(info);
917
Mark Browndd235ee2013-01-11 08:55:51 +0900918 info->num_hpdet_res = 0;
919 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
920 info->hpdet_res[i] = 0;
921 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +0000922 info->hpdet_done = false;
Mark Brown92a49872013-01-11 08:55:39 +0900923
Mark Brown34efe4d2012-07-20 17:07:29 +0100924 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
925 input_report_key(info->input,
926 arizona_lvl_to_key[i].report, 0);
927 input_sync(info->input);
928
Mark Brownf2c32a82012-06-24 12:09:45 +0100929 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
930 if (ret != 0)
931 dev_err(arizona->dev, "Removal report failed: %d\n",
932 ret);
Mark Brown4e616872013-01-15 22:09:20 +0900933
934 regmap_update_bits(arizona->regmap,
935 ARIZONA_JACK_DETECT_DEBOUNCE,
936 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
937 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +0100938 }
939
Charles Keepax5d9ab702013-02-05 10:13:38 +0000940 /* Clear trig_sts to make sure DCVDD is not forced up */
941 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
942 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
943 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
944 ARIZONA_JD1_FALL_TRIG_STS |
945 ARIZONA_JD1_RISE_TRIG_STS);
946
Mark Brownf2c32a82012-06-24 12:09:45 +0100947 mutex_unlock(&info->lock);
948
949 pm_runtime_mark_last_busy(info->dev);
950 pm_runtime_put_autosuspend(info->dev);
951
952 return IRQ_HANDLED;
953}
954
Bill Pemberton44f34fd2012-11-19 13:23:21 -0500955static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +0100956{
957 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
958 struct arizona_pdata *pdata;
959 struct arizona_extcon_info *info;
Mark Brown92a49872013-01-11 08:55:39 +0900960 int jack_irq_fall, jack_irq_rise;
Mark Brown34efe4d2012-07-20 17:07:29 +0100961 int ret, mode, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100962
Mark Brownbbbd46e2013-01-10 19:38:43 +0000963 if (!arizona->dapm || !arizona->dapm->card)
964 return -EPROBE_DEFER;
965
Mark Brownf2c32a82012-06-24 12:09:45 +0100966 pdata = dev_get_platdata(arizona->dev);
967
968 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
969 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +0900970 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100971 ret = -ENOMEM;
972 goto err;
973 }
974
975 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
976 if (IS_ERR(info->micvdd)) {
977 ret = PTR_ERR(info->micvdd);
978 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
979 goto err;
980 }
981
982 mutex_init(&info->lock);
983 info->arizona = arizona;
984 info->dev = &pdev->dev;
Mark Brown0e27bd32013-02-05 21:00:15 +0000985 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100986 platform_set_drvdata(pdev, info);
987
988 switch (arizona->type) {
989 case WM5102:
990 switch (arizona->rev) {
991 case 0:
992 info->micd_reva = true;
993 break;
994 default:
Mark Browndab63eb2013-01-11 08:55:36 +0900995 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +0900996 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +0100997 break;
998 }
999 break;
1000 default:
1001 break;
1002 }
1003
1004 info->edev.name = "Headset Jack";
1005 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001006
1007 ret = extcon_dev_register(&info->edev, arizona->dev);
1008 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001009 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001010 ret);
1011 goto err;
1012 }
1013
1014 if (pdata->num_micd_configs) {
1015 info->micd_modes = pdata->micd_configs;
1016 info->micd_num_modes = pdata->num_micd_configs;
1017 } else {
1018 info->micd_modes = micd_default_modes;
1019 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1020 }
1021
1022 if (arizona->pdata.micd_pol_gpio > 0) {
1023 if (info->micd_modes[0].gpio)
1024 mode = GPIOF_OUT_INIT_HIGH;
1025 else
1026 mode = GPIOF_OUT_INIT_LOW;
1027
1028 ret = devm_gpio_request_one(&pdev->dev,
1029 arizona->pdata.micd_pol_gpio,
1030 mode,
1031 "MICD polarity");
1032 if (ret != 0) {
1033 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1034 arizona->pdata.micd_pol_gpio, ret);
1035 goto err_register;
1036 }
1037 }
1038
Mark Brown1eda6aa2013-01-11 08:55:54 +09001039 if (arizona->pdata.hpdet_id_gpio > 0) {
1040 ret = devm_gpio_request_one(&pdev->dev,
1041 arizona->pdata.hpdet_id_gpio,
1042 GPIOF_OUT_INIT_LOW,
1043 "HPDET");
1044 if (ret != 0) {
1045 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1046 arizona->pdata.hpdet_id_gpio, ret);
1047 goto err_register;
1048 }
1049 }
1050
Mark Brownb17e5462013-01-11 08:55:24 +09001051 if (arizona->pdata.micd_bias_start_time)
1052 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1053 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1054 arizona->pdata.micd_bias_start_time
1055 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1056
Mark Brown2e033db2013-01-21 17:36:33 +09001057 if (arizona->pdata.micd_rate)
1058 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1059 ARIZONA_MICD_RATE_MASK,
1060 arizona->pdata.micd_rate
1061 << ARIZONA_MICD_RATE_SHIFT);
1062
1063 if (arizona->pdata.micd_dbtime)
1064 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1065 ARIZONA_MICD_DBTIME_MASK,
1066 arizona->pdata.micd_dbtime
1067 << ARIZONA_MICD_DBTIME_SHIFT);
1068
Mark Browndab63eb2013-01-11 08:55:36 +09001069 /*
Mark Brown92a49872013-01-11 08:55:39 +09001070 * If we have a clamp use it, activating in conjunction with
1071 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001072 */
1073 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001074 if (arizona->pdata.jd_gpio5) {
1075 /* Put the GPIO into input mode */
1076 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
1077 0xc101);
1078
1079 regmap_update_bits(arizona->regmap,
1080 ARIZONA_MICD_CLAMP_CONTROL,
1081 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1082 } else {
1083 regmap_update_bits(arizona->regmap,
1084 ARIZONA_MICD_CLAMP_CONTROL,
1085 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1086 }
1087
Mark Browndab63eb2013-01-11 08:55:36 +09001088 regmap_update_bits(arizona->regmap,
1089 ARIZONA_JACK_DETECT_DEBOUNCE,
1090 ARIZONA_MICD_CLAMP_DB,
1091 ARIZONA_MICD_CLAMP_DB);
1092 }
1093
Mark Brownf2c32a82012-06-24 12:09:45 +01001094 arizona_extcon_set_mode(info, 0);
1095
Mark Brown3d44ea12013-01-11 08:51:13 +09001096 info->input = devm_input_allocate_device(&pdev->dev);
Mark Brown34efe4d2012-07-20 17:07:29 +01001097 if (!info->input) {
1098 dev_err(arizona->dev, "Can't allocate input dev\n");
1099 ret = -ENOMEM;
1100 goto err_register;
1101 }
1102
1103 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
1104 input_set_capability(info->input, EV_KEY,
1105 arizona_lvl_to_key[i].report);
1106 info->input->name = "Headset";
1107 info->input->phys = "arizona/extcon";
1108 info->input->dev.parent = &pdev->dev;
1109
Mark Brownf2c32a82012-06-24 12:09:45 +01001110 pm_runtime_enable(&pdev->dev);
1111 pm_runtime_idle(&pdev->dev);
1112 pm_runtime_get_sync(&pdev->dev);
1113
Mark Brown92a49872013-01-11 08:55:39 +09001114 if (arizona->pdata.jd_gpio5) {
1115 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1116 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1117 } else {
1118 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1119 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1120 }
1121
1122 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001123 "JACKDET rise", arizona_jackdet, info);
1124 if (ret != 0) {
1125 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1126 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001127 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001128 }
1129
Mark Brown92a49872013-01-11 08:55:39 +09001130 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001131 if (ret != 0) {
1132 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1133 ret);
1134 goto err_rise;
1135 }
1136
Mark Brown92a49872013-01-11 08:55:39 +09001137 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001138 "JACKDET fall", arizona_jackdet, info);
1139 if (ret != 0) {
1140 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1141 goto err_rise_wake;
1142 }
1143
Mark Brown92a49872013-01-11 08:55:39 +09001144 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001145 if (ret != 0) {
1146 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1147 ret);
1148 goto err_fall;
1149 }
1150
1151 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1152 "MICDET", arizona_micdet, info);
1153 if (ret != 0) {
1154 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1155 goto err_fall_wake;
1156 }
1157
Mark Brown4f340332013-01-11 08:55:43 +09001158 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1159 "HPDET", arizona_hpdet_irq, info);
1160 if (ret != 0) {
1161 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1162 goto err_micdet;
1163 }
1164
Mark Brownf2c32a82012-06-24 12:09:45 +01001165 arizona_clk32k_enable(arizona);
1166 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1167 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1168 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1169 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1170
Mark Brownb8575a12012-09-07 17:01:15 +08001171 ret = regulator_allow_bypass(info->micvdd, true);
1172 if (ret != 0)
1173 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1174 ret);
1175
Mark Brownf2c32a82012-06-24 12:09:45 +01001176 pm_runtime_put(&pdev->dev);
1177
Mark Brown34efe4d2012-07-20 17:07:29 +01001178 ret = input_register_device(info->input);
1179 if (ret) {
1180 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001181 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001182 }
1183
Mark Brownf2c32a82012-06-24 12:09:45 +01001184 return 0;
1185
Mark Brown4f340332013-01-11 08:55:43 +09001186err_hpdet:
1187 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001188err_micdet:
1189 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001190err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001191 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001192err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001193 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001194err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001195 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001196err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001197 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001198err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001199err_register:
1200 pm_runtime_disable(&pdev->dev);
1201 extcon_dev_unregister(&info->edev);
1202err:
1203 return ret;
1204}
1205
Bill Pemberton93ed0322012-11-19 13:25:49 -05001206static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001207{
1208 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1209 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001210 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001211
1212 pm_runtime_disable(&pdev->dev);
1213
Mark Browndab63eb2013-01-11 08:55:36 +09001214 regmap_update_bits(arizona->regmap,
1215 ARIZONA_MICD_CLAMP_CONTROL,
1216 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1217
Mark Brown92a49872013-01-11 08:55:39 +09001218 if (arizona->pdata.jd_gpio5) {
1219 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1220 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1221 } else {
1222 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1223 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1224 }
1225
1226 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1227 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1228 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001229 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001230 arizona_free_irq(arizona, jack_irq_rise, info);
1231 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001232 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001233 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1234 ARIZONA_JD1_ENA, 0);
1235 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001236 extcon_dev_unregister(&info->edev);
1237
1238 return 0;
1239}
1240
1241static struct platform_driver arizona_extcon_driver = {
1242 .driver = {
1243 .name = "arizona-extcon",
1244 .owner = THIS_MODULE,
1245 },
1246 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001247 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001248};
1249
1250module_platform_driver(arizona_extcon_driver);
1251
1252MODULE_DESCRIPTION("Arizona Extcon driver");
1253MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1254MODULE_LICENSE("GPL");
1255MODULE_ALIAS("platform:extcon-arizona");