blob: c18cf14067c661b90ec286a9c175ce960e74aeb0 [file] [log] [blame]
Mark Brownf2c32a82012-06-24 12:09:45 +01001/*
2 * extcon-arizona.c - Extcon driver Wolfson Arizona devices
3 *
4 * Copyright (C) 2012 Wolfson Microelectronics plc
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/i2c.h>
20#include <linux/slab.h>
21#include <linux/interrupt.h>
22#include <linux/err.h>
23#include <linux/gpio.h>
Mark Brown34efe4d2012-07-20 17:07:29 +010024#include <linux/input.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010025#include <linux/platform_device.h>
26#include <linux/pm_runtime.h>
27#include <linux/regulator/consumer.h>
28#include <linux/extcon.h>
29
Mark Brownbbbd46e2013-01-10 19:38:43 +000030#include <sound/soc.h>
31
Mark Brownf2c32a82012-06-24 12:09:45 +010032#include <linux/mfd/arizona/core.h>
33#include <linux/mfd/arizona/pdata.h>
34#include <linux/mfd/arizona/registers.h>
35
Mark Brown6fed4d82013-04-01 22:03:06 +010036#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010037
Mark Brown4f340332013-01-11 08:55:43 +090038#define ARIZONA_ACCDET_MODE_MIC 0
39#define ARIZONA_ACCDET_MODE_HPL 1
40#define ARIZONA_ACCDET_MODE_HPR 2
41
Mark Brown9dd5e532013-04-01 19:09:45 +010042#define ARIZONA_HPDET_MAX 10000
43
Mark Brown2643fd62013-04-01 19:07:28 +010044#define HPDET_DEBOUNCE 500
Mark Browna3e20782013-04-01 19:05:27 +010045
Mark Brownf2c32a82012-06-24 12:09:45 +010046struct arizona_extcon_info {
47 struct device *dev;
48 struct arizona *arizona;
49 struct mutex lock;
50 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010051 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010052
Mark Browna3e20782013-04-01 19:05:27 +010053 u16 last_jackdet;
54
Mark Brownf2c32a82012-06-24 12:09:45 +010055 int micd_mode;
56 const struct arizona_micd_config *micd_modes;
57 int micd_num_modes;
58
Mark Brown6fed4d82013-04-01 22:03:06 +010059 const struct arizona_micd_range *micd_ranges;
60 int num_micd_ranges;
61
Mark Brownf2c32a82012-06-24 12:09:45 +010062 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090063 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010064
Mark Brown0e27bd32013-02-05 21:00:15 +000065 struct delayed_work hpdet_work;
66
Mark Brown4f340332013-01-11 08:55:43 +090067 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000068 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010069 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090070
Mark Browndd235ee2013-01-11 08:55:51 +090071 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090072 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090073
Mark Brownf2c32a82012-06-24 12:09:45 +010074 bool mic;
75 bool detecting;
76 int jack_flips;
77
Mark Brown4f340332013-01-11 08:55:43 +090078 int hpdet_ip;
79
Mark Brownf2c32a82012-06-24 12:09:45 +010080 struct extcon_dev edev;
81};
82
83static const struct arizona_micd_config micd_default_modes[] = {
Mark Browndd235ee2013-01-11 08:55:51 +090084 { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
Mark Brown6fed4d82013-04-01 22:03:06 +010085 { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +010086};
87
Mark Brown6fed4d82013-04-01 22:03:06 +010088static const struct arizona_micd_range micd_default_ranges[] = {
89 { .max = 11, .key = BTN_0 },
90 { .max = 28, .key = BTN_1 },
91 { .max = 54, .key = BTN_2 },
92 { .max = 100, .key = BTN_3 },
93 { .max = 186, .key = BTN_4 },
94 { .max = 430, .key = BTN_5 },
95};
96
97static const int arizona_micd_levels[] = {
98 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
99 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
100 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
101 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
102 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100103};
104
Mark Brown325c6422012-06-28 13:08:30 +0100105#define ARIZONA_CABLE_MECHANICAL 0
106#define ARIZONA_CABLE_MICROPHONE 1
107#define ARIZONA_CABLE_HEADPHONE 2
Mark Brown4f340332013-01-11 08:55:43 +0900108#define ARIZONA_CABLE_LINEOUT 3
Mark Brownf2c32a82012-06-24 12:09:45 +0100109
110static const char *arizona_cable[] = {
Mark Brown325c6422012-06-28 13:08:30 +0100111 "Mechanical",
112 "Microphone",
113 "Headphone",
Mark Brown4f340332013-01-11 08:55:43 +0900114 "Line-out",
Mark Brownf2c32a82012-06-24 12:09:45 +0100115 NULL,
116};
117
Mark Brown9dd5e532013-04-01 19:09:45 +0100118static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
119
Mark Brown03409072013-02-12 13:00:31 +0000120static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
121 unsigned int magic)
122{
123 struct arizona *arizona = info->arizona;
Mark Brown03409072013-02-12 13:00:31 +0000124 int ret;
125
126 mutex_lock(&arizona->dapm->card->dapm_mutex);
127
Mark Browndf8c3db2013-02-22 18:38:03 +0000128 arizona->hpdet_magic = magic;
129
130 /* Keep the HP output stages disabled while doing the magic */
131 if (magic) {
132 ret = regmap_update_bits(arizona->regmap,
133 ARIZONA_OUTPUT_ENABLES_1,
134 ARIZONA_OUT1L_ENA |
135 ARIZONA_OUT1R_ENA, 0);
136 if (ret != 0)
137 dev_warn(arizona->dev,
138 "Failed to disable headphone outputs: %d\n",
139 ret);
Mark Brown03409072013-02-12 13:00:31 +0000140 }
141
Mark Browndf8c3db2013-02-22 18:38:03 +0000142 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
143 magic);
144 if (ret != 0)
145 dev_warn(arizona->dev, "Failed to do magic: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000146 ret);
147
Mark Browndf8c3db2013-02-22 18:38:03 +0000148 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
149 magic);
150 if (ret != 0)
151 dev_warn(arizona->dev, "Failed to do magic: %d\n",
152 ret);
153
154 /* Restore the desired state while not doing the magic */
155 if (!magic) {
156 ret = regmap_update_bits(arizona->regmap,
157 ARIZONA_OUTPUT_ENABLES_1,
158 ARIZONA_OUT1L_ENA |
159 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000160 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000161 dev_warn(arizona->dev,
162 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000163 ret);
164 }
165
166 mutex_unlock(&arizona->dapm->card->dapm_mutex);
167}
168
Mark Brownf2c32a82012-06-24 12:09:45 +0100169static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
170{
171 struct arizona *arizona = info->arizona;
172
Mark Brown6fed4d82013-04-01 22:03:06 +0100173 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800174
Mark Browncd74f7b2012-11-27 16:14:26 +0900175 if (arizona->pdata.micd_pol_gpio > 0)
176 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
177 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100178 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
179 ARIZONA_MICD_BIAS_SRC_MASK,
180 info->micd_modes[mode].bias);
181 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
182 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
183
184 info->micd_mode = mode;
185
186 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
187}
188
Mark Brownbbbd46e2013-01-10 19:38:43 +0000189static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
190{
191 switch (info->micd_modes[0].bias >> ARIZONA_MICD_BIAS_SRC_SHIFT) {
192 case 1:
193 return "MICBIAS1";
194 case 2:
195 return "MICBIAS2";
196 case 3:
197 return "MICBIAS3";
198 default:
199 return "MICVDD";
200 }
201}
202
203static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
204{
205 struct arizona *arizona = info->arizona;
206 const char *widget = arizona_extcon_get_micbias(info);
207 struct snd_soc_dapm_context *dapm = arizona->dapm;
208 int ret;
209
210 mutex_lock(&dapm->card->dapm_mutex);
211
212 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
213 if (ret != 0)
214 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
215 widget, ret);
216
217 mutex_unlock(&dapm->card->dapm_mutex);
218
219 snd_soc_dapm_sync(dapm);
220
221 if (!arizona->pdata.micd_force_micbias) {
222 mutex_lock(&dapm->card->dapm_mutex);
223
224 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
225 if (ret != 0)
226 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
227 widget, ret);
228
229 mutex_unlock(&dapm->card->dapm_mutex);
230
231 snd_soc_dapm_sync(dapm);
232 }
233}
234
Mark Brown9b1270c2013-01-11 08:55:46 +0900235static void arizona_start_mic(struct arizona_extcon_info *info)
236{
237 struct arizona *arizona = info->arizona;
238 bool change;
239 int ret;
240
Mark Brown9b1270c2013-01-11 08:55:46 +0900241 /* Microphone detection can't use idle mode */
242 pm_runtime_get(info->dev);
243
Mark Brownbbbd46e2013-01-10 19:38:43 +0000244 if (info->detecting) {
245 ret = regulator_allow_bypass(info->micvdd, false);
246 if (ret != 0) {
247 dev_err(arizona->dev,
248 "Failed to regulate MICVDD: %d\n",
249 ret);
250 }
251 }
252
Mark Brown9b1270c2013-01-11 08:55:46 +0900253 ret = regulator_enable(info->micvdd);
254 if (ret != 0) {
255 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
256 ret);
257 }
258
259 if (info->micd_reva) {
260 regmap_write(arizona->regmap, 0x80, 0x3);
261 regmap_write(arizona->regmap, 0x294, 0);
262 regmap_write(arizona->regmap, 0x80, 0x0);
263 }
264
265 regmap_update_bits(arizona->regmap,
266 ARIZONA_ACCESSORY_DETECT_MODE_1,
267 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
268
Mark Brownbbbd46e2013-01-10 19:38:43 +0000269 arizona_extcon_pulse_micbias(info);
270
Mark Brown9b1270c2013-01-11 08:55:46 +0900271 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
272 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
273 &change);
274 if (!change) {
275 regulator_disable(info->micvdd);
276 pm_runtime_put_autosuspend(info->dev);
277 }
278}
279
280static void arizona_stop_mic(struct arizona_extcon_info *info)
281{
282 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000283 const char *widget = arizona_extcon_get_micbias(info);
284 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900285 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000286 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900287
288 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
289 ARIZONA_MICD_ENA, 0,
290 &change);
291
Mark Brownbbbd46e2013-01-10 19:38:43 +0000292 mutex_lock(&dapm->card->dapm_mutex);
293
294 ret = snd_soc_dapm_disable_pin(dapm, widget);
295 if (ret != 0)
296 dev_warn(arizona->dev,
297 "Failed to disable %s: %d\n",
298 widget, ret);
299
300 mutex_unlock(&dapm->card->dapm_mutex);
301
302 snd_soc_dapm_sync(dapm);
303
Mark Brown9b1270c2013-01-11 08:55:46 +0900304 if (info->micd_reva) {
305 regmap_write(arizona->regmap, 0x80, 0x3);
306 regmap_write(arizona->regmap, 0x294, 2);
307 regmap_write(arizona->regmap, 0x80, 0x0);
308 }
309
Mark Brownbbbd46e2013-01-10 19:38:43 +0000310 ret = regulator_allow_bypass(info->micvdd, true);
311 if (ret != 0) {
312 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
313 ret);
314 }
315
Mark Brown9b1270c2013-01-11 08:55:46 +0900316 if (change) {
317 regulator_disable(info->micvdd);
318 pm_runtime_mark_last_busy(info->dev);
319 pm_runtime_put_autosuspend(info->dev);
320 }
321}
322
Mark Brown4f340332013-01-11 08:55:43 +0900323static struct {
324 unsigned int factor_a;
325 unsigned int factor_b;
326} arizona_hpdet_b_ranges[] = {
327 { 5528, 362464 },
328 { 11084, 6186851 },
329 { 11065, 65460395 },
330};
331
332static struct {
333 int min;
334 int max;
335} arizona_hpdet_c_ranges[] = {
336 { 0, 30 },
337 { 8, 100 },
338 { 100, 1000 },
339 { 1000, 10000 },
340};
341
342static int arizona_hpdet_read(struct arizona_extcon_info *info)
343{
344 struct arizona *arizona = info->arizona;
345 unsigned int val, range;
346 int ret;
347
348 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
349 if (ret != 0) {
350 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
351 ret);
352 return ret;
353 }
354
355 switch (info->hpdet_ip) {
356 case 0:
357 if (!(val & ARIZONA_HP_DONE)) {
358 dev_err(arizona->dev, "HPDET did not complete: %x\n",
359 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900360 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900361 }
362
363 val &= ARIZONA_HP_LVL_MASK;
364 break;
365
366 case 1:
367 if (!(val & ARIZONA_HP_DONE_B)) {
368 dev_err(arizona->dev, "HPDET did not complete: %x\n",
369 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900370 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900371 }
372
373 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
374 if (ret != 0) {
375 dev_err(arizona->dev, "Failed to read HP value: %d\n",
376 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900377 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900378 }
379
380 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
381 &range);
382 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
383 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
384
385 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
386 (val < 100 || val > 0x3fb)) {
387 range++;
388 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
389 range);
390 regmap_update_bits(arizona->regmap,
391 ARIZONA_HEADPHONE_DETECT_1,
392 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
393 range <<
394 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
395 return -EAGAIN;
396 }
397
398 /* If we go out of range report top of range */
399 if (val < 100 || val > 0x3fb) {
400 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100401 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900402 }
403
404 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
405 val, range);
406
407 val = arizona_hpdet_b_ranges[range].factor_b
408 / ((val * 100) -
409 arizona_hpdet_b_ranges[range].factor_a);
410 break;
411
412 default:
413 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
414 info->hpdet_ip);
415 case 2:
416 if (!(val & ARIZONA_HP_DONE_B)) {
417 dev_err(arizona->dev, "HPDET did not complete: %x\n",
418 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900419 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900420 }
421
422 val &= ARIZONA_HP_LVL_B_MASK;
423
424 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
425 &range);
426 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
427 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
428
429 /* Skip up or down a range? */
430 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
431 range--;
432 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
433 arizona_hpdet_c_ranges[range].min,
434 arizona_hpdet_c_ranges[range].max);
435 regmap_update_bits(arizona->regmap,
436 ARIZONA_HEADPHONE_DETECT_1,
437 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
438 range <<
439 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
440 return -EAGAIN;
441 }
442
443 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
444 (val >= arizona_hpdet_c_ranges[range].max)) {
445 range++;
446 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
447 arizona_hpdet_c_ranges[range].min,
448 arizona_hpdet_c_ranges[range].max);
449 regmap_update_bits(arizona->regmap,
450 ARIZONA_HEADPHONE_DETECT_1,
451 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
452 range <<
453 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
454 return -EAGAIN;
455 }
456 }
457
458 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
459 return val;
460}
461
Mark Browndd235ee2013-01-11 08:55:51 +0900462static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
463{
464 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900465 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900466
467 /*
468 * If we're using HPDET for accessory identification we need
469 * to take multiple measurements, step through them in sequence.
470 */
471 if (arizona->pdata.hpdet_acc_id) {
472 info->hpdet_res[info->num_hpdet_res++] = *reading;
473
474 /*
475 * If the impedence is too high don't measure the
476 * second ground.
477 */
478 if (info->num_hpdet_res == 1 && *reading >= 45) {
479 dev_dbg(arizona->dev, "Skipping ground flip\n");
480 info->hpdet_res[info->num_hpdet_res++] = *reading;
481 }
482
483 if (info->num_hpdet_res == 1) {
484 dev_dbg(arizona->dev, "Flipping ground\n");
485
486 regmap_update_bits(arizona->regmap,
487 ARIZONA_ACCESSORY_DETECT_MODE_1,
488 ARIZONA_ACCDET_SRC,
489 ~info->micd_modes[0].src);
Mark Brown1eda6aa2013-01-11 08:55:54 +0900490
Mark Browndd235ee2013-01-11 08:55:51 +0900491 regmap_update_bits(arizona->regmap,
492 ARIZONA_HEADPHONE_DETECT_1,
Mark Brown1eda6aa2013-01-11 08:55:54 +0900493 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
494 return -EAGAIN;
495 }
496
497 /* Only check the mic directly if we didn't already ID it */
498 if (id_gpio && info->num_hpdet_res == 2 &&
499 !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) {
500 dev_dbg(arizona->dev, "Measuring mic\n");
501
502 regmap_update_bits(arizona->regmap,
503 ARIZONA_ACCESSORY_DETECT_MODE_1,
504 ARIZONA_ACCDET_MODE_MASK |
505 ARIZONA_ACCDET_SRC,
506 ARIZONA_ACCDET_MODE_HPR |
507 info->micd_modes[0].src);
508
509 gpio_set_value_cansleep(id_gpio, 1);
510
Mark Browndd235ee2013-01-11 08:55:51 +0900511 regmap_update_bits(arizona->regmap,
512 ARIZONA_HEADPHONE_DETECT_1,
513 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
514 return -EAGAIN;
515 }
516
517 /* OK, got both. Now, compare... */
Mark Brown1eda6aa2013-01-11 08:55:54 +0900518 dev_dbg(arizona->dev, "HPDET measured %d %d %d\n",
519 info->hpdet_res[0], info->hpdet_res[1],
520 info->hpdet_res[2]);
Mark Browndd235ee2013-01-11 08:55:51 +0900521
Mark Brownc37b3872013-02-05 17:48:49 +0000522
523 /* Take the headphone impedance for the main report */
524 *reading = info->hpdet_res[0];
525
Mark Brown9dd5e532013-04-01 19:09:45 +0100526 /* Sometimes we get false readings due to slow insert */
527 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
528 dev_dbg(arizona->dev, "Retrying high impedance\n");
529 info->num_hpdet_res = 0;
530 info->hpdet_retried = true;
531 arizona_start_hpdet_acc_id(info);
532 pm_runtime_put(info->dev);
533 return -EAGAIN;
534 }
535
Mark Brown1eda6aa2013-01-11 08:55:54 +0900536 /*
537 * Either the two grounds measure differently or we
538 * measure the mic as high impedance.
539 */
540 if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) ||
Mark Brown82e2e0f2013-04-01 19:04:43 +0100541 (id_gpio && info->hpdet_res[2] > 1257)) {
Mark Browndd235ee2013-01-11 08:55:51 +0900542 dev_dbg(arizona->dev, "Detected mic\n");
543 info->mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000544 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900545 } else {
546 dev_dbg(arizona->dev, "Detected headphone\n");
547 }
548
549 /* Make sure everything is reset back to the real polarity */
550 regmap_update_bits(arizona->regmap,
551 ARIZONA_ACCESSORY_DETECT_MODE_1,
552 ARIZONA_ACCDET_SRC,
553 info->micd_modes[0].src);
554 }
555
556 return 0;
557}
558
Mark Brown4f340332013-01-11 08:55:43 +0900559static irqreturn_t arizona_hpdet_irq(int irq, void *data)
560{
561 struct arizona_extcon_info *info = data;
562 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900563 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900564 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900565 int ret, reading;
Mark Brown4f340332013-01-11 08:55:43 +0900566
567 mutex_lock(&info->lock);
568
569 /* If we got a spurious IRQ for some reason then ignore it */
570 if (!info->hpdet_active) {
571 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
572 mutex_unlock(&info->lock);
573 return IRQ_NONE;
574 }
575
576 /* If the cable was removed while measuring ignore the result */
577 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
578 if (ret < 0) {
579 dev_err(arizona->dev, "Failed to check cable state: %d\n",
580 ret);
581 goto out;
582 } else if (!ret) {
583 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
584 goto done;
585 }
586
587 ret = arizona_hpdet_read(info);
588 if (ret == -EAGAIN) {
589 goto out;
590 } else if (ret < 0) {
591 goto done;
592 }
Mark Browndd235ee2013-01-11 08:55:51 +0900593 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900594
595 /* Reset back to starting range */
596 regmap_update_bits(arizona->regmap,
597 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900598 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
599 0);
600
601 ret = arizona_hpdet_do_id(info, &reading);
602 if (ret == -EAGAIN) {
603 goto out;
604 } else if (ret < 0) {
605 goto done;
606 }
Mark Brown4f340332013-01-11 08:55:43 +0900607
608 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900609 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900610 report = ARIZONA_CABLE_LINEOUT;
611 else
612 report = ARIZONA_CABLE_HEADPHONE;
613
614 ret = extcon_set_cable_state_(&info->edev, report, true);
615 if (ret != 0)
616 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
617 ret);
618
Mark Brown03409072013-02-12 13:00:31 +0000619 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900620
621done:
Mark Brown1eda6aa2013-01-11 08:55:54 +0900622 if (id_gpio)
623 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900624
625 /* Revert back to MICDET mode */
626 regmap_update_bits(arizona->regmap,
627 ARIZONA_ACCESSORY_DETECT_MODE_1,
628 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
629
630 /* If we have a mic then reenable MICDET */
631 if (info->mic)
632 arizona_start_mic(info);
633
634 if (info->hpdet_active) {
635 pm_runtime_put_autosuspend(info->dev);
636 info->hpdet_active = false;
637 }
638
Mark Brownbf14ee52013-02-05 20:20:17 +0000639 info->hpdet_done = true;
640
Mark Brown4f340332013-01-11 08:55:43 +0900641out:
642 mutex_unlock(&info->lock);
643
644 return IRQ_HANDLED;
645}
646
647static void arizona_identify_headphone(struct arizona_extcon_info *info)
648{
649 struct arizona *arizona = info->arizona;
650 int ret;
651
Mark Brownbf14ee52013-02-05 20:20:17 +0000652 if (info->hpdet_done)
653 return;
654
Mark Brown4f340332013-01-11 08:55:43 +0900655 dev_dbg(arizona->dev, "Starting HPDET\n");
656
657 /* Make sure we keep the device enabled during the measurement */
658 pm_runtime_get(info->dev);
659
660 info->hpdet_active = true;
661
662 if (info->mic)
663 arizona_stop_mic(info);
664
Mark Brown03409072013-02-12 13:00:31 +0000665 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900666
667 ret = regmap_update_bits(arizona->regmap,
668 ARIZONA_ACCESSORY_DETECT_MODE_1,
669 ARIZONA_ACCDET_MODE_MASK,
670 ARIZONA_ACCDET_MODE_HPL);
671 if (ret != 0) {
672 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
673 goto err;
674 }
675
676 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
677 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
678 if (ret != 0) {
679 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
680 ret);
681 goto err;
682 }
683
684 return;
685
686err:
687 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
688 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
689
690 /* Just report headphone */
691 ret = extcon_update_state(&info->edev,
692 1 << ARIZONA_CABLE_HEADPHONE,
693 1 << ARIZONA_CABLE_HEADPHONE);
694 if (ret != 0)
695 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
696
697 if (info->mic)
698 arizona_start_mic(info);
699
700 info->hpdet_active = false;
701}
Mark Browndd235ee2013-01-11 08:55:51 +0900702
703static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
704{
705 struct arizona *arizona = info->arizona;
706 int ret;
707
708 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
709
710 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000711 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900712
713 info->hpdet_active = true;
714
Mark Brown03409072013-02-12 13:00:31 +0000715 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900716
717 ret = regmap_update_bits(arizona->regmap,
718 ARIZONA_ACCESSORY_DETECT_MODE_1,
719 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
720 info->micd_modes[0].src |
721 ARIZONA_ACCDET_MODE_HPL);
722 if (ret != 0) {
723 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
724 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900725 }
726
Mark Browndd235ee2013-01-11 08:55:51 +0900727 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
728 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
729 if (ret != 0) {
730 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
731 ret);
732 goto err;
733 }
734
735 return;
736
737err:
738 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
739 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
740
741 /* Just report headphone */
742 ret = extcon_update_state(&info->edev,
743 1 << ARIZONA_CABLE_HEADPHONE,
744 1 << ARIZONA_CABLE_HEADPHONE);
745 if (ret != 0)
746 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
747
Mark Brown4f340332013-01-11 08:55:43 +0900748 info->hpdet_active = false;
749}
750
Mark Brownf2c32a82012-06-24 12:09:45 +0100751static irqreturn_t arizona_micdet(int irq, void *data)
752{
753 struct arizona_extcon_info *info = data;
754 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100755 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100756 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100757
758 mutex_lock(&info->lock);
759
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100760 for (i = 0; i < 10 && !(val & 0x7fc); i++) {
761 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
762 if (ret != 0) {
763 dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
764 mutex_unlock(&info->lock);
765 return IRQ_NONE;
766 }
767
768 dev_dbg(arizona->dev, "MICDET: %x\n", val);
769
770 if (!(val & ARIZONA_MICD_VALID)) {
771 dev_warn(arizona->dev, "Microphone detection state invalid\n");
772 mutex_unlock(&info->lock);
773 return IRQ_NONE;
774 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100775 }
776
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100777 if (i == 10 && !(val & 0x7fc)) {
778 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100779 mutex_unlock(&info->lock);
780 return IRQ_NONE;
781 }
782
783 /* Due to jack detect this should never happen */
784 if (!(val & ARIZONA_MICD_STS)) {
785 dev_warn(arizona->dev, "Detected open circuit\n");
786 info->detecting = false;
787 goto handled;
788 }
789
790 /* If we got a high impedence we should have a headset, report it. */
791 if (info->detecting && (val & 0x400)) {
Mark Brown4f340332013-01-11 08:55:43 +0900792 arizona_identify_headphone(info);
793
Mark Brown325c6422012-06-28 13:08:30 +0100794 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900795 1 << ARIZONA_CABLE_MICROPHONE,
796 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100797
798 if (ret != 0)
799 dev_err(arizona->dev, "Headset report failed: %d\n",
800 ret);
801
Mark Brownbbbd46e2013-01-10 19:38:43 +0000802 /* Don't need to regulate for button detection */
803 ret = regulator_allow_bypass(info->micvdd, false);
804 if (ret != 0) {
805 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
806 ret);
807 }
808
Mark Brownf2c32a82012-06-24 12:09:45 +0100809 info->mic = true;
810 info->detecting = false;
811 goto handled;
812 }
813
814 /* If we detected a lower impedence during initial startup
815 * then we probably have the wrong polarity, flip it. Don't
816 * do this for the lowest impedences to speed up detection of
817 * plain headphones. If both polarities report a low
818 * impedence then give up and report headphones.
819 */
820 if (info->detecting && (val & 0x3f8)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800821 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900822 dev_dbg(arizona->dev, "Detected HP/line\n");
823 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100824
Mark Brown4f340332013-01-11 08:55:43 +0900825 info->detecting = false;
826
827 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100828 } else {
829 info->micd_mode++;
830 if (info->micd_mode == info->micd_num_modes)
831 info->micd_mode = 0;
832 arizona_extcon_set_mode(info, info->micd_mode);
833
834 info->jack_flips++;
835 }
836
837 goto handled;
838 }
839
840 /*
841 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100842 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100843 */
844 if (val & 0x3fc) {
845 if (info->mic) {
846 dev_dbg(arizona->dev, "Mic button detected\n");
847
Mark Brown34efe4d2012-07-20 17:07:29 +0100848 lvl = val & ARIZONA_MICD_LVL_MASK;
849 lvl >>= ARIZONA_MICD_LVL_SHIFT;
850
Mark Brown6fed4d82013-04-01 22:03:06 +0100851 WARN_ON(!lvl);
852 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
853 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
854 key = info->micd_ranges[ffs(lvl) - 1].key;
855 input_report_key(info->input, key, 1);
856 input_sync(info->input);
857 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100858
Mark Brownf2c32a82012-06-24 12:09:45 +0100859 } else if (info->detecting) {
860 dev_dbg(arizona->dev, "Headphone detected\n");
861 info->detecting = false;
862 arizona_stop_mic(info);
863
Mark Brown4f340332013-01-11 08:55:43 +0900864 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100865 } else {
866 dev_warn(arizona->dev, "Button with no mic: %x\n",
867 val);
868 }
869 } else {
870 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100871 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100872 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100873 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100874 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000875 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100876 }
877
878handled:
879 pm_runtime_mark_last_busy(info->dev);
880 mutex_unlock(&info->lock);
881
882 return IRQ_HANDLED;
883}
884
Mark Brown0e27bd32013-02-05 21:00:15 +0000885static void arizona_hpdet_work(struct work_struct *work)
886{
887 struct arizona_extcon_info *info = container_of(work,
888 struct arizona_extcon_info,
889 hpdet_work.work);
890
891 mutex_lock(&info->lock);
892 arizona_start_hpdet_acc_id(info);
893 mutex_unlock(&info->lock);
894}
895
Mark Brownf2c32a82012-06-24 12:09:45 +0100896static irqreturn_t arizona_jackdet(int irq, void *data)
897{
898 struct arizona_extcon_info *info = data;
899 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900900 unsigned int val, present, mask;
Mark Browna3e20782013-04-01 19:05:27 +0100901 bool cancelled;
Mark Brown34efe4d2012-07-20 17:07:29 +0100902 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100903
Mark Browna3e20782013-04-01 19:05:27 +0100904 cancelled = cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100905
Mark Browna3e20782013-04-01 19:05:27 +0100906 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000907
Mark Brownf2c32a82012-06-24 12:09:45 +0100908 mutex_lock(&info->lock);
909
Mark Brown92a49872013-01-11 08:55:39 +0900910 if (arizona->pdata.jd_gpio5) {
911 mask = ARIZONA_MICD_CLAMP_STS;
912 present = 0;
913 } else {
914 mask = ARIZONA_JD1_STS;
915 present = ARIZONA_JD1_STS;
916 }
917
Mark Brownf2c32a82012-06-24 12:09:45 +0100918 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
919 if (ret != 0) {
920 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
921 ret);
922 mutex_unlock(&info->lock);
923 pm_runtime_put_autosuspend(info->dev);
924 return IRQ_NONE;
925 }
926
Mark Browna3e20782013-04-01 19:05:27 +0100927 val &= mask;
928 if (val == info->last_jackdet) {
929 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
930 if (cancelled)
931 schedule_delayed_work(&info->hpdet_work,
932 msecs_to_jiffies(HPDET_DEBOUNCE));
933
934 goto out;
935 }
936 info->last_jackdet = val;
937
938 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100939 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +0100940 ret = extcon_set_cable_state_(&info->edev,
941 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100942
943 if (ret != 0)
944 dev_err(arizona->dev, "Mechanical report failed: %d\n",
945 ret);
946
Mark Browndd235ee2013-01-11 08:55:51 +0900947 if (!arizona->pdata.hpdet_acc_id) {
948 info->detecting = true;
949 info->mic = false;
950 info->jack_flips = 0;
951
952 arizona_start_mic(info);
953 } else {
Mark Brown0e27bd32013-02-05 21:00:15 +0000954 schedule_delayed_work(&info->hpdet_work,
Mark Browna3e20782013-04-01 19:05:27 +0100955 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +0900956 }
Mark Brown4e616872013-01-15 22:09:20 +0900957
958 regmap_update_bits(arizona->regmap,
959 ARIZONA_JACK_DETECT_DEBOUNCE,
960 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +0100961 } else {
962 dev_dbg(arizona->dev, "Detected jack removal\n");
963
964 arizona_stop_mic(info);
965
Mark Browndd235ee2013-01-11 08:55:51 +0900966 info->num_hpdet_res = 0;
967 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
968 info->hpdet_res[i] = 0;
969 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +0000970 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +0100971 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +0900972
Mark Brown6fed4d82013-04-01 22:03:06 +0100973 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100974 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100975 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100976 input_sync(info->input);
977
Mark Brownf2c32a82012-06-24 12:09:45 +0100978 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
979 if (ret != 0)
980 dev_err(arizona->dev, "Removal report failed: %d\n",
981 ret);
Mark Brown4e616872013-01-15 22:09:20 +0900982
983 regmap_update_bits(arizona->regmap,
984 ARIZONA_JACK_DETECT_DEBOUNCE,
985 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
986 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +0100987 }
988
Charles Keepax5d9ab702013-02-05 10:13:38 +0000989 /* Clear trig_sts to make sure DCVDD is not forced up */
990 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
991 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
992 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
993 ARIZONA_JD1_FALL_TRIG_STS |
994 ARIZONA_JD1_RISE_TRIG_STS);
995
Mark Browna3e20782013-04-01 19:05:27 +0100996out:
Mark Brownf2c32a82012-06-24 12:09:45 +0100997 mutex_unlock(&info->lock);
998
999 pm_runtime_mark_last_busy(info->dev);
1000 pm_runtime_put_autosuspend(info->dev);
1001
1002 return IRQ_HANDLED;
1003}
1004
Mark Brown6fed4d82013-04-01 22:03:06 +01001005/* Map a level onto a slot in the register bank */
1006static void arizona_micd_set_level(struct arizona *arizona, int index,
1007 unsigned int level)
1008{
1009 int reg;
1010 unsigned int mask;
1011
1012 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1013
1014 if (!(index % 2)) {
1015 mask = 0x3f00;
1016 level <<= 8;
1017 } else {
1018 mask = 0x3f;
1019 }
1020
1021 /* Program the level itself */
1022 regmap_update_bits(arizona->regmap, reg, mask, level);
1023}
1024
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001025static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001026{
1027 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
1028 struct arizona_pdata *pdata;
1029 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001030 unsigned int val;
Mark Brown92a49872013-01-11 08:55:39 +09001031 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001032 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001033
Mark Brownbbbd46e2013-01-10 19:38:43 +00001034 if (!arizona->dapm || !arizona->dapm->card)
1035 return -EPROBE_DEFER;
1036
Mark Brownf2c32a82012-06-24 12:09:45 +01001037 pdata = dev_get_platdata(arizona->dev);
1038
1039 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1040 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001041 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +01001042 ret = -ENOMEM;
1043 goto err;
1044 }
1045
1046 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1047 if (IS_ERR(info->micvdd)) {
1048 ret = PTR_ERR(info->micvdd);
1049 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
1050 goto err;
1051 }
1052
1053 mutex_init(&info->lock);
1054 info->arizona = arizona;
1055 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001056 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001057 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001058 platform_set_drvdata(pdev, info);
1059
1060 switch (arizona->type) {
1061 case WM5102:
1062 switch (arizona->rev) {
1063 case 0:
1064 info->micd_reva = true;
1065 break;
1066 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001067 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001068 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001069 break;
1070 }
1071 break;
1072 default:
1073 break;
1074 }
1075
1076 info->edev.name = "Headset Jack";
1077 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001078
1079 ret = extcon_dev_register(&info->edev, arizona->dev);
1080 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001081 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001082 ret);
1083 goto err;
1084 }
1085
Mark Brown6fed4d82013-04-01 22:03:06 +01001086 info->input = devm_input_allocate_device(&pdev->dev);
1087 if (!info->input) {
1088 dev_err(arizona->dev, "Can't allocate input dev\n");
1089 ret = -ENOMEM;
1090 goto err_register;
1091 }
1092
1093 info->input->name = "Headset";
1094 info->input->phys = "arizona/extcon";
1095 info->input->dev.parent = &pdev->dev;
1096
Mark Brownf2c32a82012-06-24 12:09:45 +01001097 if (pdata->num_micd_configs) {
1098 info->micd_modes = pdata->micd_configs;
1099 info->micd_num_modes = pdata->num_micd_configs;
1100 } else {
1101 info->micd_modes = micd_default_modes;
1102 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1103 }
1104
1105 if (arizona->pdata.micd_pol_gpio > 0) {
1106 if (info->micd_modes[0].gpio)
1107 mode = GPIOF_OUT_INIT_HIGH;
1108 else
1109 mode = GPIOF_OUT_INIT_LOW;
1110
1111 ret = devm_gpio_request_one(&pdev->dev,
1112 arizona->pdata.micd_pol_gpio,
1113 mode,
1114 "MICD polarity");
1115 if (ret != 0) {
1116 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1117 arizona->pdata.micd_pol_gpio, ret);
1118 goto err_register;
1119 }
1120 }
1121
Mark Brown1eda6aa2013-01-11 08:55:54 +09001122 if (arizona->pdata.hpdet_id_gpio > 0) {
1123 ret = devm_gpio_request_one(&pdev->dev,
1124 arizona->pdata.hpdet_id_gpio,
1125 GPIOF_OUT_INIT_LOW,
1126 "HPDET");
1127 if (ret != 0) {
1128 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1129 arizona->pdata.hpdet_id_gpio, ret);
1130 goto err_register;
1131 }
1132 }
1133
Mark Brownb17e5462013-01-11 08:55:24 +09001134 if (arizona->pdata.micd_bias_start_time)
1135 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1136 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1137 arizona->pdata.micd_bias_start_time
1138 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1139
Mark Brown2e033db2013-01-21 17:36:33 +09001140 if (arizona->pdata.micd_rate)
1141 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1142 ARIZONA_MICD_RATE_MASK,
1143 arizona->pdata.micd_rate
1144 << ARIZONA_MICD_RATE_SHIFT);
1145
1146 if (arizona->pdata.micd_dbtime)
1147 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1148 ARIZONA_MICD_DBTIME_MASK,
1149 arizona->pdata.micd_dbtime
1150 << ARIZONA_MICD_DBTIME_SHIFT);
1151
Mark Brown6fed4d82013-04-01 22:03:06 +01001152 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1153
1154 if (arizona->pdata.num_micd_ranges) {
1155 info->micd_ranges = pdata->micd_ranges;
1156 info->num_micd_ranges = pdata->num_micd_ranges;
1157 } else {
1158 info->micd_ranges = micd_default_ranges;
1159 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1160 }
1161
1162 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1163 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1164 arizona->pdata.num_micd_ranges);
1165 }
1166
1167 if (info->num_micd_ranges > 1) {
1168 for (i = 1; i < info->num_micd_ranges; i++) {
1169 if (info->micd_ranges[i - 1].max >
1170 info->micd_ranges[i].max) {
1171 dev_err(arizona->dev,
1172 "MICD ranges must be sorted\n");
1173 ret = -EINVAL;
1174 goto err_input;
1175 }
1176 }
1177 }
1178
1179 /* Disable all buttons by default */
1180 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1181 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1182
1183 /* Set up all the buttons the user specified */
1184 for (i = 0; i < info->num_micd_ranges; i++) {
1185 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1186 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1187 break;
1188
1189 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1190 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1191 info->micd_ranges[i].max);
1192 ret = -EINVAL;
1193 goto err_input;
1194 }
1195
1196 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1197 arizona_micd_levels[j], i);
1198
1199 arizona_micd_set_level(arizona, i, j);
1200 input_set_capability(info->input, EV_KEY,
1201 info->micd_ranges[i].key);
1202
1203 /* Enable reporting of that range */
1204 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1205 1 << i, 1 << i);
1206 }
1207
1208 /* Set all the remaining keys to a maximum */
1209 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1210 arizona_micd_set_level(arizona, i, 0x3f);
1211
Mark Browndab63eb2013-01-11 08:55:36 +09001212 /*
Mark Brown92a49872013-01-11 08:55:39 +09001213 * If we have a clamp use it, activating in conjunction with
1214 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001215 */
1216 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001217 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001218 /* Put the GPIO into input mode with optional pull */
1219 val = 0xc101;
1220 if (arizona->pdata.jd_gpio5_nopull)
1221 val &= ~ARIZONA_GPN_PU;
1222
Mark Brown92a49872013-01-11 08:55:39 +09001223 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001224 val);
Mark Brown92a49872013-01-11 08:55:39 +09001225
1226 regmap_update_bits(arizona->regmap,
1227 ARIZONA_MICD_CLAMP_CONTROL,
1228 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1229 } else {
1230 regmap_update_bits(arizona->regmap,
1231 ARIZONA_MICD_CLAMP_CONTROL,
1232 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1233 }
1234
Mark Browndab63eb2013-01-11 08:55:36 +09001235 regmap_update_bits(arizona->regmap,
1236 ARIZONA_JACK_DETECT_DEBOUNCE,
1237 ARIZONA_MICD_CLAMP_DB,
1238 ARIZONA_MICD_CLAMP_DB);
1239 }
1240
Mark Brownf2c32a82012-06-24 12:09:45 +01001241 arizona_extcon_set_mode(info, 0);
1242
1243 pm_runtime_enable(&pdev->dev);
1244 pm_runtime_idle(&pdev->dev);
1245 pm_runtime_get_sync(&pdev->dev);
1246
Mark Brown92a49872013-01-11 08:55:39 +09001247 if (arizona->pdata.jd_gpio5) {
1248 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1249 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1250 } else {
1251 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1252 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1253 }
1254
1255 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001256 "JACKDET rise", arizona_jackdet, info);
1257 if (ret != 0) {
1258 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1259 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001260 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001261 }
1262
Mark Brown92a49872013-01-11 08:55:39 +09001263 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001264 if (ret != 0) {
1265 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1266 ret);
1267 goto err_rise;
1268 }
1269
Mark Brown92a49872013-01-11 08:55:39 +09001270 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001271 "JACKDET fall", arizona_jackdet, info);
1272 if (ret != 0) {
1273 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1274 goto err_rise_wake;
1275 }
1276
Mark Brown92a49872013-01-11 08:55:39 +09001277 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001278 if (ret != 0) {
1279 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1280 ret);
1281 goto err_fall;
1282 }
1283
1284 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1285 "MICDET", arizona_micdet, info);
1286 if (ret != 0) {
1287 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1288 goto err_fall_wake;
1289 }
1290
Mark Brown4f340332013-01-11 08:55:43 +09001291 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1292 "HPDET", arizona_hpdet_irq, info);
1293 if (ret != 0) {
1294 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1295 goto err_micdet;
1296 }
1297
Mark Brownf2c32a82012-06-24 12:09:45 +01001298 arizona_clk32k_enable(arizona);
1299 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1300 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1301 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1302 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1303
Mark Brownb8575a12012-09-07 17:01:15 +08001304 ret = regulator_allow_bypass(info->micvdd, true);
1305 if (ret != 0)
1306 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1307 ret);
1308
Mark Brownf2c32a82012-06-24 12:09:45 +01001309 pm_runtime_put(&pdev->dev);
1310
Mark Brown34efe4d2012-07-20 17:07:29 +01001311 ret = input_register_device(info->input);
1312 if (ret) {
1313 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001314 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001315 }
1316
Mark Brownf2c32a82012-06-24 12:09:45 +01001317 return 0;
1318
Mark Brown4f340332013-01-11 08:55:43 +09001319err_hpdet:
1320 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001321err_micdet:
1322 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001323err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001324 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001325err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001326 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001327err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001328 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001329err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001330 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001331err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001332err_register:
1333 pm_runtime_disable(&pdev->dev);
1334 extcon_dev_unregister(&info->edev);
1335err:
1336 return ret;
1337}
1338
Bill Pemberton93ed0322012-11-19 13:25:49 -05001339static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001340{
1341 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1342 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001343 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001344
1345 pm_runtime_disable(&pdev->dev);
1346
Mark Browndab63eb2013-01-11 08:55:36 +09001347 regmap_update_bits(arizona->regmap,
1348 ARIZONA_MICD_CLAMP_CONTROL,
1349 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1350
Mark Brown92a49872013-01-11 08:55:39 +09001351 if (arizona->pdata.jd_gpio5) {
1352 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1353 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1354 } else {
1355 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1356 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1357 }
1358
1359 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1360 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1361 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001362 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001363 arizona_free_irq(arizona, jack_irq_rise, info);
1364 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001365 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001366 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1367 ARIZONA_JD1_ENA, 0);
1368 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001369 extcon_dev_unregister(&info->edev);
1370
1371 return 0;
1372}
1373
1374static struct platform_driver arizona_extcon_driver = {
1375 .driver = {
1376 .name = "arizona-extcon",
1377 .owner = THIS_MODULE,
1378 },
1379 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001380 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001381};
1382
1383module_platform_driver(arizona_extcon_driver);
1384
1385MODULE_DESCRIPTION("Arizona Extcon driver");
1386MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1387MODULE_LICENSE("GPL");
1388MODULE_ALIAS("platform:extcon-arizona");