blob: 7a1b4a7791baf9e1fb3f0932903736014582559d [file] [log] [blame]
Mark Brownf2c32a82012-06-24 12:09:45 +01001/*
2 * extcon-arizona.c - Extcon driver Wolfson Arizona devices
3 *
4 * Copyright (C) 2012 Wolfson Microelectronics plc
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/i2c.h>
20#include <linux/slab.h>
21#include <linux/interrupt.h>
22#include <linux/err.h>
23#include <linux/gpio.h>
Mark Brown34efe4d2012-07-20 17:07:29 +010024#include <linux/input.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010025#include <linux/platform_device.h>
26#include <linux/pm_runtime.h>
27#include <linux/regulator/consumer.h>
28#include <linux/extcon.h>
29
Mark Brownbbbd46e2013-01-10 19:38:43 +000030#include <sound/soc.h>
31
Mark Brownf2c32a82012-06-24 12:09:45 +010032#include <linux/mfd/arizona/core.h>
33#include <linux/mfd/arizona/pdata.h>
34#include <linux/mfd/arizona/registers.h>
35
Mark Brown6fed4d82013-04-01 22:03:06 +010036#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010037
Mark Brown4f340332013-01-11 08:55:43 +090038#define ARIZONA_ACCDET_MODE_MIC 0
39#define ARIZONA_ACCDET_MODE_HPL 1
40#define ARIZONA_ACCDET_MODE_HPR 2
41
Mark Brown9dd5e532013-04-01 19:09:45 +010042#define ARIZONA_HPDET_MAX 10000
43
Mark Brown2643fd62013-04-01 19:07:28 +010044#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010045#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010046
Mark Brownf2c32a82012-06-24 12:09:45 +010047struct arizona_extcon_info {
48 struct device *dev;
49 struct arizona *arizona;
50 struct mutex lock;
51 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010052 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010053
Mark Browna3e20782013-04-01 19:05:27 +010054 u16 last_jackdet;
55
Mark Brownf2c32a82012-06-24 12:09:45 +010056 int micd_mode;
57 const struct arizona_micd_config *micd_modes;
58 int micd_num_modes;
59
Mark Brown6fed4d82013-04-01 22:03:06 +010060 const struct arizona_micd_range *micd_ranges;
61 int num_micd_ranges;
62
Mark Brown7abd4e22013-04-01 19:25:55 +010063 int micd_timeout;
64
Mark Brownf2c32a82012-06-24 12:09:45 +010065 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090066 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010067
Mark Brown0e27bd32013-02-05 21:00:15 +000068 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010069 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010070 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000071
Mark Brown4f340332013-01-11 08:55:43 +090072 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000073 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010074 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090075
Mark Browndd235ee2013-01-11 08:55:51 +090076 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090077 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090078
Mark Brownf2c32a82012-06-24 12:09:45 +010079 bool mic;
80 bool detecting;
81 int jack_flips;
82
Mark Brown4f340332013-01-11 08:55:43 +090083 int hpdet_ip;
84
Mark Brownf2c32a82012-06-24 12:09:45 +010085 struct extcon_dev edev;
86};
87
88static const struct arizona_micd_config micd_default_modes[] = {
Mark Browndd235ee2013-01-11 08:55:51 +090089 { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
Mark Brown6fed4d82013-04-01 22:03:06 +010090 { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +010091};
92
Mark Brown6fed4d82013-04-01 22:03:06 +010093static const struct arizona_micd_range micd_default_ranges[] = {
94 { .max = 11, .key = BTN_0 },
95 { .max = 28, .key = BTN_1 },
96 { .max = 54, .key = BTN_2 },
97 { .max = 100, .key = BTN_3 },
98 { .max = 186, .key = BTN_4 },
99 { .max = 430, .key = BTN_5 },
100};
101
102static const int arizona_micd_levels[] = {
103 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
104 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
105 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
106 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
107 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100108};
109
Mark Brown325c6422012-06-28 13:08:30 +0100110#define ARIZONA_CABLE_MECHANICAL 0
111#define ARIZONA_CABLE_MICROPHONE 1
112#define ARIZONA_CABLE_HEADPHONE 2
Mark Brown4f340332013-01-11 08:55:43 +0900113#define ARIZONA_CABLE_LINEOUT 3
Mark Brownf2c32a82012-06-24 12:09:45 +0100114
115static const char *arizona_cable[] = {
Mark Brown325c6422012-06-28 13:08:30 +0100116 "Mechanical",
117 "Microphone",
118 "Headphone",
Mark Brown4f340332013-01-11 08:55:43 +0900119 "Line-out",
Mark Brownf2c32a82012-06-24 12:09:45 +0100120 NULL,
121};
122
Mark Brown9dd5e532013-04-01 19:09:45 +0100123static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
124
Mark Brown03409072013-02-12 13:00:31 +0000125static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
126 unsigned int magic)
127{
128 struct arizona *arizona = info->arizona;
Mark Brown03409072013-02-12 13:00:31 +0000129 int ret;
130
131 mutex_lock(&arizona->dapm->card->dapm_mutex);
132
Mark Browndf8c3db2013-02-22 18:38:03 +0000133 arizona->hpdet_magic = magic;
134
135 /* Keep the HP output stages disabled while doing the magic */
136 if (magic) {
137 ret = regmap_update_bits(arizona->regmap,
138 ARIZONA_OUTPUT_ENABLES_1,
139 ARIZONA_OUT1L_ENA |
140 ARIZONA_OUT1R_ENA, 0);
141 if (ret != 0)
142 dev_warn(arizona->dev,
143 "Failed to disable headphone outputs: %d\n",
144 ret);
Mark Brown03409072013-02-12 13:00:31 +0000145 }
146
Mark Browndf8c3db2013-02-22 18:38:03 +0000147 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
148 magic);
149 if (ret != 0)
150 dev_warn(arizona->dev, "Failed to do magic: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000151 ret);
152
Mark Browndf8c3db2013-02-22 18:38:03 +0000153 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
154 magic);
155 if (ret != 0)
156 dev_warn(arizona->dev, "Failed to do magic: %d\n",
157 ret);
158
159 /* Restore the desired state while not doing the magic */
160 if (!magic) {
161 ret = regmap_update_bits(arizona->regmap,
162 ARIZONA_OUTPUT_ENABLES_1,
163 ARIZONA_OUT1L_ENA |
164 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000165 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000166 dev_warn(arizona->dev,
167 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000168 ret);
169 }
170
171 mutex_unlock(&arizona->dapm->card->dapm_mutex);
172}
173
Mark Brownf2c32a82012-06-24 12:09:45 +0100174static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
175{
176 struct arizona *arizona = info->arizona;
177
Mark Brown6fed4d82013-04-01 22:03:06 +0100178 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800179
Mark Browncd74f7b2012-11-27 16:14:26 +0900180 if (arizona->pdata.micd_pol_gpio > 0)
181 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
182 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100183 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
184 ARIZONA_MICD_BIAS_SRC_MASK,
185 info->micd_modes[mode].bias);
186 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
187 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
188
189 info->micd_mode = mode;
190
191 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
192}
193
Mark Brownbbbd46e2013-01-10 19:38:43 +0000194static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
195{
196 switch (info->micd_modes[0].bias >> ARIZONA_MICD_BIAS_SRC_SHIFT) {
197 case 1:
198 return "MICBIAS1";
199 case 2:
200 return "MICBIAS2";
201 case 3:
202 return "MICBIAS3";
203 default:
204 return "MICVDD";
205 }
206}
207
208static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
209{
210 struct arizona *arizona = info->arizona;
211 const char *widget = arizona_extcon_get_micbias(info);
212 struct snd_soc_dapm_context *dapm = arizona->dapm;
213 int ret;
214
215 mutex_lock(&dapm->card->dapm_mutex);
216
217 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
218 if (ret != 0)
219 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
220 widget, ret);
221
222 mutex_unlock(&dapm->card->dapm_mutex);
223
224 snd_soc_dapm_sync(dapm);
225
226 if (!arizona->pdata.micd_force_micbias) {
227 mutex_lock(&dapm->card->dapm_mutex);
228
229 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
230 if (ret != 0)
231 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
232 widget, ret);
233
234 mutex_unlock(&dapm->card->dapm_mutex);
235
236 snd_soc_dapm_sync(dapm);
237 }
238}
239
Mark Brown9b1270c2013-01-11 08:55:46 +0900240static void arizona_start_mic(struct arizona_extcon_info *info)
241{
242 struct arizona *arizona = info->arizona;
243 bool change;
244 int ret;
245
Mark Brown9b1270c2013-01-11 08:55:46 +0900246 /* Microphone detection can't use idle mode */
247 pm_runtime_get(info->dev);
248
Mark Brownbbbd46e2013-01-10 19:38:43 +0000249 if (info->detecting) {
250 ret = regulator_allow_bypass(info->micvdd, false);
251 if (ret != 0) {
252 dev_err(arizona->dev,
253 "Failed to regulate MICVDD: %d\n",
254 ret);
255 }
256 }
257
Mark Brown9b1270c2013-01-11 08:55:46 +0900258 ret = regulator_enable(info->micvdd);
259 if (ret != 0) {
260 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
261 ret);
262 }
263
264 if (info->micd_reva) {
265 regmap_write(arizona->regmap, 0x80, 0x3);
266 regmap_write(arizona->regmap, 0x294, 0);
267 regmap_write(arizona->regmap, 0x80, 0x0);
268 }
269
270 regmap_update_bits(arizona->regmap,
271 ARIZONA_ACCESSORY_DETECT_MODE_1,
272 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
273
Mark Brownbbbd46e2013-01-10 19:38:43 +0000274 arizona_extcon_pulse_micbias(info);
275
Mark Brown9b1270c2013-01-11 08:55:46 +0900276 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
277 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
278 &change);
279 if (!change) {
280 regulator_disable(info->micvdd);
281 pm_runtime_put_autosuspend(info->dev);
282 }
283}
284
285static void arizona_stop_mic(struct arizona_extcon_info *info)
286{
287 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000288 const char *widget = arizona_extcon_get_micbias(info);
289 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900290 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000291 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900292
293 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
294 ARIZONA_MICD_ENA, 0,
295 &change);
296
Mark Brownbbbd46e2013-01-10 19:38:43 +0000297 mutex_lock(&dapm->card->dapm_mutex);
298
299 ret = snd_soc_dapm_disable_pin(dapm, widget);
300 if (ret != 0)
301 dev_warn(arizona->dev,
302 "Failed to disable %s: %d\n",
303 widget, ret);
304
305 mutex_unlock(&dapm->card->dapm_mutex);
306
307 snd_soc_dapm_sync(dapm);
308
Mark Brown9b1270c2013-01-11 08:55:46 +0900309 if (info->micd_reva) {
310 regmap_write(arizona->regmap, 0x80, 0x3);
311 regmap_write(arizona->regmap, 0x294, 2);
312 regmap_write(arizona->regmap, 0x80, 0x0);
313 }
314
Mark Brownbbbd46e2013-01-10 19:38:43 +0000315 ret = regulator_allow_bypass(info->micvdd, true);
316 if (ret != 0) {
317 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
318 ret);
319 }
320
Mark Brown9b1270c2013-01-11 08:55:46 +0900321 if (change) {
322 regulator_disable(info->micvdd);
323 pm_runtime_mark_last_busy(info->dev);
324 pm_runtime_put_autosuspend(info->dev);
325 }
326}
327
Mark Brown4f340332013-01-11 08:55:43 +0900328static struct {
329 unsigned int factor_a;
330 unsigned int factor_b;
331} arizona_hpdet_b_ranges[] = {
332 { 5528, 362464 },
333 { 11084, 6186851 },
334 { 11065, 65460395 },
335};
336
337static struct {
338 int min;
339 int max;
340} arizona_hpdet_c_ranges[] = {
341 { 0, 30 },
342 { 8, 100 },
343 { 100, 1000 },
344 { 1000, 10000 },
345};
346
347static int arizona_hpdet_read(struct arizona_extcon_info *info)
348{
349 struct arizona *arizona = info->arizona;
350 unsigned int val, range;
351 int ret;
352
353 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
354 if (ret != 0) {
355 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
356 ret);
357 return ret;
358 }
359
360 switch (info->hpdet_ip) {
361 case 0:
362 if (!(val & ARIZONA_HP_DONE)) {
363 dev_err(arizona->dev, "HPDET did not complete: %x\n",
364 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900365 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900366 }
367
368 val &= ARIZONA_HP_LVL_MASK;
369 break;
370
371 case 1:
372 if (!(val & ARIZONA_HP_DONE_B)) {
373 dev_err(arizona->dev, "HPDET did not complete: %x\n",
374 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900375 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900376 }
377
378 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
379 if (ret != 0) {
380 dev_err(arizona->dev, "Failed to read HP value: %d\n",
381 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900382 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900383 }
384
385 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
386 &range);
387 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
388 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
389
390 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
391 (val < 100 || val > 0x3fb)) {
392 range++;
393 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
394 range);
395 regmap_update_bits(arizona->regmap,
396 ARIZONA_HEADPHONE_DETECT_1,
397 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
398 range <<
399 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
400 return -EAGAIN;
401 }
402
403 /* If we go out of range report top of range */
404 if (val < 100 || val > 0x3fb) {
405 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100406 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900407 }
408
409 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
410 val, range);
411
412 val = arizona_hpdet_b_ranges[range].factor_b
413 / ((val * 100) -
414 arizona_hpdet_b_ranges[range].factor_a);
415 break;
416
417 default:
418 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
419 info->hpdet_ip);
420 case 2:
421 if (!(val & ARIZONA_HP_DONE_B)) {
422 dev_err(arizona->dev, "HPDET did not complete: %x\n",
423 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900424 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900425 }
426
427 val &= ARIZONA_HP_LVL_B_MASK;
428
429 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
430 &range);
431 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
432 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
433
434 /* Skip up or down a range? */
435 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
436 range--;
437 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
438 arizona_hpdet_c_ranges[range].min,
439 arizona_hpdet_c_ranges[range].max);
440 regmap_update_bits(arizona->regmap,
441 ARIZONA_HEADPHONE_DETECT_1,
442 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
443 range <<
444 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
445 return -EAGAIN;
446 }
447
448 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
449 (val >= arizona_hpdet_c_ranges[range].max)) {
450 range++;
451 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
452 arizona_hpdet_c_ranges[range].min,
453 arizona_hpdet_c_ranges[range].max);
454 regmap_update_bits(arizona->regmap,
455 ARIZONA_HEADPHONE_DETECT_1,
456 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
457 range <<
458 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
459 return -EAGAIN;
460 }
461 }
462
463 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
464 return val;
465}
466
Mark Brown9c2ba272013-02-25 23:42:31 +0000467static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
468 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900469{
470 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900471 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900472
473 /*
474 * If we're using HPDET for accessory identification we need
475 * to take multiple measurements, step through them in sequence.
476 */
477 if (arizona->pdata.hpdet_acc_id) {
478 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900479
480 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000481 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900482 dev_dbg(arizona->dev, "Measuring mic\n");
483
484 regmap_update_bits(arizona->regmap,
485 ARIZONA_ACCESSORY_DETECT_MODE_1,
486 ARIZONA_ACCDET_MODE_MASK |
487 ARIZONA_ACCDET_SRC,
488 ARIZONA_ACCDET_MODE_HPR |
489 info->micd_modes[0].src);
490
491 gpio_set_value_cansleep(id_gpio, 1);
492
Mark Browndd235ee2013-01-11 08:55:51 +0900493 regmap_update_bits(arizona->regmap,
494 ARIZONA_HEADPHONE_DETECT_1,
495 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
496 return -EAGAIN;
497 }
498
499 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000500 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
501 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000502
503 /* Take the headphone impedance for the main report */
504 *reading = info->hpdet_res[0];
505
Mark Brown9dd5e532013-04-01 19:09:45 +0100506 /* Sometimes we get false readings due to slow insert */
507 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
508 dev_dbg(arizona->dev, "Retrying high impedance\n");
509 info->num_hpdet_res = 0;
510 info->hpdet_retried = true;
511 arizona_start_hpdet_acc_id(info);
512 pm_runtime_put(info->dev);
513 return -EAGAIN;
514 }
515
Mark Brown1eda6aa2013-01-11 08:55:54 +0900516 /*
Mark Brown9c2ba272013-02-25 23:42:31 +0000517 * If we measure the mic as
Mark Brown1eda6aa2013-01-11 08:55:54 +0900518 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000519 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900520 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000521 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000522 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900523 } else {
524 dev_dbg(arizona->dev, "Detected headphone\n");
525 }
526
527 /* Make sure everything is reset back to the real polarity */
528 regmap_update_bits(arizona->regmap,
529 ARIZONA_ACCESSORY_DETECT_MODE_1,
530 ARIZONA_ACCDET_SRC,
531 info->micd_modes[0].src);
532 }
533
534 return 0;
535}
536
Mark Brown4f340332013-01-11 08:55:43 +0900537static irqreturn_t arizona_hpdet_irq(int irq, void *data)
538{
539 struct arizona_extcon_info *info = data;
540 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900541 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900542 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900543 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000544 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900545
546 mutex_lock(&info->lock);
547
548 /* If we got a spurious IRQ for some reason then ignore it */
549 if (!info->hpdet_active) {
550 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
551 mutex_unlock(&info->lock);
552 return IRQ_NONE;
553 }
554
555 /* If the cable was removed while measuring ignore the result */
556 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
557 if (ret < 0) {
558 dev_err(arizona->dev, "Failed to check cable state: %d\n",
559 ret);
560 goto out;
561 } else if (!ret) {
562 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
563 goto done;
564 }
565
566 ret = arizona_hpdet_read(info);
567 if (ret == -EAGAIN) {
568 goto out;
569 } else if (ret < 0) {
570 goto done;
571 }
Mark Browndd235ee2013-01-11 08:55:51 +0900572 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900573
574 /* Reset back to starting range */
575 regmap_update_bits(arizona->regmap,
576 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900577 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
578 0);
579
Mark Brown9c2ba272013-02-25 23:42:31 +0000580 ret = arizona_hpdet_do_id(info, &reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900581 if (ret == -EAGAIN) {
582 goto out;
583 } else if (ret < 0) {
584 goto done;
585 }
Mark Brown4f340332013-01-11 08:55:43 +0900586
587 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900588 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900589 report = ARIZONA_CABLE_LINEOUT;
590 else
591 report = ARIZONA_CABLE_HEADPHONE;
592
593 ret = extcon_set_cable_state_(&info->edev, report, true);
594 if (ret != 0)
595 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
596 ret);
597
Mark Brown03409072013-02-12 13:00:31 +0000598 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900599
600done:
Mark Brown1eda6aa2013-01-11 08:55:54 +0900601 if (id_gpio)
602 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900603
604 /* Revert back to MICDET mode */
605 regmap_update_bits(arizona->regmap,
606 ARIZONA_ACCESSORY_DETECT_MODE_1,
607 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
608
609 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000610 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900611 arizona_start_mic(info);
612
613 if (info->hpdet_active) {
614 pm_runtime_put_autosuspend(info->dev);
615 info->hpdet_active = false;
616 }
617
Mark Brownbf14ee52013-02-05 20:20:17 +0000618 info->hpdet_done = true;
619
Mark Brown4f340332013-01-11 08:55:43 +0900620out:
621 mutex_unlock(&info->lock);
622
623 return IRQ_HANDLED;
624}
625
626static void arizona_identify_headphone(struct arizona_extcon_info *info)
627{
628 struct arizona *arizona = info->arizona;
629 int ret;
630
Mark Brownbf14ee52013-02-05 20:20:17 +0000631 if (info->hpdet_done)
632 return;
633
Mark Brown4f340332013-01-11 08:55:43 +0900634 dev_dbg(arizona->dev, "Starting HPDET\n");
635
636 /* Make sure we keep the device enabled during the measurement */
637 pm_runtime_get(info->dev);
638
639 info->hpdet_active = true;
640
641 if (info->mic)
642 arizona_stop_mic(info);
643
Mark Brown03409072013-02-12 13:00:31 +0000644 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900645
646 ret = regmap_update_bits(arizona->regmap,
647 ARIZONA_ACCESSORY_DETECT_MODE_1,
648 ARIZONA_ACCDET_MODE_MASK,
649 ARIZONA_ACCDET_MODE_HPL);
650 if (ret != 0) {
651 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
652 goto err;
653 }
654
655 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
656 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
657 if (ret != 0) {
658 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
659 ret);
660 goto err;
661 }
662
663 return;
664
665err:
666 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
667 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
668
669 /* Just report headphone */
670 ret = extcon_update_state(&info->edev,
671 1 << ARIZONA_CABLE_HEADPHONE,
672 1 << ARIZONA_CABLE_HEADPHONE);
673 if (ret != 0)
674 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
675
676 if (info->mic)
677 arizona_start_mic(info);
678
679 info->hpdet_active = false;
680}
Mark Browndd235ee2013-01-11 08:55:51 +0900681
682static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
683{
684 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000685 int hp_reading = 32;
686 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900687 int ret;
688
689 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
690
691 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000692 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900693
694 info->hpdet_active = true;
695
Mark Brown03409072013-02-12 13:00:31 +0000696 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900697
698 ret = regmap_update_bits(arizona->regmap,
699 ARIZONA_ACCESSORY_DETECT_MODE_1,
700 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
701 info->micd_modes[0].src |
702 ARIZONA_ACCDET_MODE_HPL);
703 if (ret != 0) {
704 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
705 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900706 }
707
Mark Brown9c2ba272013-02-25 23:42:31 +0000708 if (arizona->pdata.hpdet_acc_id_line) {
709 ret = regmap_update_bits(arizona->regmap,
710 ARIZONA_HEADPHONE_DETECT_1,
711 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
712 if (ret != 0) {
713 dev_err(arizona->dev,
714 "Can't start HPDETL measurement: %d\n",
715 ret);
716 goto err;
717 }
718 } else {
719 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900720 }
721
722 return;
723
724err:
725 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
726 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
727
728 /* Just report headphone */
729 ret = extcon_update_state(&info->edev,
730 1 << ARIZONA_CABLE_HEADPHONE,
731 1 << ARIZONA_CABLE_HEADPHONE);
732 if (ret != 0)
733 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
734
Mark Brown4f340332013-01-11 08:55:43 +0900735 info->hpdet_active = false;
736}
737
Mark Brown939c5672013-04-01 19:17:34 +0100738static void arizona_micd_timeout_work(struct work_struct *work)
739{
740 struct arizona_extcon_info *info = container_of(work,
741 struct arizona_extcon_info,
742 micd_timeout_work.work);
743
744 mutex_lock(&info->lock);
745
746 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
747 arizona_identify_headphone(info);
748
749 info->detecting = false;
750
751 arizona_stop_mic(info);
752
753 mutex_unlock(&info->lock);
754}
755
Mark Browncd59e792013-04-01 19:21:48 +0100756static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100757{
Mark Browncd59e792013-04-01 19:21:48 +0100758 struct arizona_extcon_info *info = container_of(work,
759 struct arizona_extcon_info,
760 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100761 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100762 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100763 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100764
Mark Brown939c5672013-04-01 19:17:34 +0100765 cancel_delayed_work_sync(&info->micd_timeout_work);
766
Mark Brownf2c32a82012-06-24 12:09:45 +0100767 mutex_lock(&info->lock);
768
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100769 for (i = 0; i < 10 && !(val & 0x7fc); i++) {
770 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
771 if (ret != 0) {
772 dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
773 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100774 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100775 }
776
777 dev_dbg(arizona->dev, "MICDET: %x\n", val);
778
779 if (!(val & ARIZONA_MICD_VALID)) {
780 dev_warn(arizona->dev, "Microphone detection state invalid\n");
781 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100782 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100783 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100784 }
785
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100786 if (i == 10 && !(val & 0x7fc)) {
787 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100788 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100789 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100790 }
791
792 /* Due to jack detect this should never happen */
793 if (!(val & ARIZONA_MICD_STS)) {
794 dev_warn(arizona->dev, "Detected open circuit\n");
795 info->detecting = false;
796 goto handled;
797 }
798
799 /* If we got a high impedence we should have a headset, report it. */
800 if (info->detecting && (val & 0x400)) {
Mark Brown4f340332013-01-11 08:55:43 +0900801 arizona_identify_headphone(info);
802
Mark Brown325c6422012-06-28 13:08:30 +0100803 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900804 1 << ARIZONA_CABLE_MICROPHONE,
805 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100806
807 if (ret != 0)
808 dev_err(arizona->dev, "Headset report failed: %d\n",
809 ret);
810
Mark Brownbbbd46e2013-01-10 19:38:43 +0000811 /* Don't need to regulate for button detection */
812 ret = regulator_allow_bypass(info->micvdd, false);
813 if (ret != 0) {
814 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
815 ret);
816 }
817
Mark Brownf2c32a82012-06-24 12:09:45 +0100818 info->mic = true;
819 info->detecting = false;
820 goto handled;
821 }
822
823 /* If we detected a lower impedence during initial startup
824 * then we probably have the wrong polarity, flip it. Don't
825 * do this for the lowest impedences to speed up detection of
826 * plain headphones. If both polarities report a low
827 * impedence then give up and report headphones.
828 */
829 if (info->detecting && (val & 0x3f8)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800830 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900831 dev_dbg(arizona->dev, "Detected HP/line\n");
832 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100833
Mark Brown4f340332013-01-11 08:55:43 +0900834 info->detecting = false;
835
836 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100837 } else {
838 info->micd_mode++;
839 if (info->micd_mode == info->micd_num_modes)
840 info->micd_mode = 0;
841 arizona_extcon_set_mode(info, info->micd_mode);
842
843 info->jack_flips++;
844 }
845
846 goto handled;
847 }
848
849 /*
850 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100851 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100852 */
853 if (val & 0x3fc) {
854 if (info->mic) {
855 dev_dbg(arizona->dev, "Mic button detected\n");
856
Mark Brown34efe4d2012-07-20 17:07:29 +0100857 lvl = val & ARIZONA_MICD_LVL_MASK;
858 lvl >>= ARIZONA_MICD_LVL_SHIFT;
859
Mark Brown41a57852013-04-01 19:18:18 +0100860 for (i = 0; i < info->num_micd_ranges; i++)
861 input_report_key(info->input,
862 info->micd_ranges[i].key, 0);
863
Mark Brown6fed4d82013-04-01 22:03:06 +0100864 WARN_ON(!lvl);
865 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
866 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
867 key = info->micd_ranges[ffs(lvl) - 1].key;
868 input_report_key(info->input, key, 1);
869 input_sync(info->input);
870 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100871
Mark Brownf2c32a82012-06-24 12:09:45 +0100872 } else if (info->detecting) {
873 dev_dbg(arizona->dev, "Headphone detected\n");
874 info->detecting = false;
875 arizona_stop_mic(info);
876
Mark Brown4f340332013-01-11 08:55:43 +0900877 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100878 } else {
879 dev_warn(arizona->dev, "Button with no mic: %x\n",
880 val);
881 }
882 } else {
883 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100884 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100885 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100886 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100887 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000888 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100889 }
890
891handled:
Mark Brown939c5672013-04-01 19:17:34 +0100892 if (info->detecting)
893 schedule_delayed_work(&info->micd_timeout_work,
Mark Brown7abd4e22013-04-01 19:25:55 +0100894 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100895
Mark Brownf2c32a82012-06-24 12:09:45 +0100896 pm_runtime_mark_last_busy(info->dev);
897 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100898}
899
900static irqreturn_t arizona_micdet(int irq, void *data)
901{
902 struct arizona_extcon_info *info = data;
903 struct arizona *arizona = info->arizona;
904 int debounce = arizona->pdata.micd_detect_debounce;
905
906 cancel_delayed_work_sync(&info->micd_detect_work);
907 cancel_delayed_work_sync(&info->micd_timeout_work);
908
909 mutex_lock(&info->lock);
910 if (!info->detecting)
911 debounce = 0;
912 mutex_unlock(&info->lock);
913
914 if (debounce)
915 schedule_delayed_work(&info->micd_detect_work,
916 msecs_to_jiffies(debounce));
917 else
918 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100919
920 return IRQ_HANDLED;
921}
922
Mark Brown0e27bd32013-02-05 21:00:15 +0000923static void arizona_hpdet_work(struct work_struct *work)
924{
925 struct arizona_extcon_info *info = container_of(work,
926 struct arizona_extcon_info,
927 hpdet_work.work);
928
929 mutex_lock(&info->lock);
930 arizona_start_hpdet_acc_id(info);
931 mutex_unlock(&info->lock);
932}
933
Mark Brownf2c32a82012-06-24 12:09:45 +0100934static irqreturn_t arizona_jackdet(int irq, void *data)
935{
936 struct arizona_extcon_info *info = data;
937 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900938 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100939 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100940 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100941
Mark Brown939c5672013-04-01 19:17:34 +0100942 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
943 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100944
Mark Browna3e20782013-04-01 19:05:27 +0100945 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000946
Mark Brownf2c32a82012-06-24 12:09:45 +0100947 mutex_lock(&info->lock);
948
Mark Brown92a49872013-01-11 08:55:39 +0900949 if (arizona->pdata.jd_gpio5) {
950 mask = ARIZONA_MICD_CLAMP_STS;
951 present = 0;
952 } else {
953 mask = ARIZONA_JD1_STS;
954 present = ARIZONA_JD1_STS;
955 }
956
Mark Brownf2c32a82012-06-24 12:09:45 +0100957 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
958 if (ret != 0) {
959 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
960 ret);
961 mutex_unlock(&info->lock);
962 pm_runtime_put_autosuspend(info->dev);
963 return IRQ_NONE;
964 }
965
Mark Browna3e20782013-04-01 19:05:27 +0100966 val &= mask;
967 if (val == info->last_jackdet) {
968 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +0100969 if (cancelled_hp)
Mark Browna3e20782013-04-01 19:05:27 +0100970 schedule_delayed_work(&info->hpdet_work,
971 msecs_to_jiffies(HPDET_DEBOUNCE));
972
Mark Brown939c5672013-04-01 19:17:34 +0100973 if (cancelled_mic)
974 schedule_delayed_work(&info->micd_timeout_work,
Mark Brown7abd4e22013-04-01 19:25:55 +0100975 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100976
Mark Browna3e20782013-04-01 19:05:27 +0100977 goto out;
978 }
979 info->last_jackdet = val;
980
981 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100982 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +0100983 ret = extcon_set_cable_state_(&info->edev,
984 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100985
986 if (ret != 0)
987 dev_err(arizona->dev, "Mechanical report failed: %d\n",
988 ret);
989
Mark Browndd235ee2013-01-11 08:55:51 +0900990 if (!arizona->pdata.hpdet_acc_id) {
991 info->detecting = true;
992 info->mic = false;
993 info->jack_flips = 0;
994
995 arizona_start_mic(info);
996 } else {
Mark Brown0e27bd32013-02-05 21:00:15 +0000997 schedule_delayed_work(&info->hpdet_work,
Mark Browna3e20782013-04-01 19:05:27 +0100998 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +0900999 }
Mark Brown4e616872013-01-15 22:09:20 +09001000
1001 regmap_update_bits(arizona->regmap,
1002 ARIZONA_JACK_DETECT_DEBOUNCE,
1003 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001004 } else {
1005 dev_dbg(arizona->dev, "Detected jack removal\n");
1006
1007 arizona_stop_mic(info);
1008
Mark Browndd235ee2013-01-11 08:55:51 +09001009 info->num_hpdet_res = 0;
1010 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1011 info->hpdet_res[i] = 0;
1012 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001013 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001014 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001015
Mark Brown6fed4d82013-04-01 22:03:06 +01001016 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001017 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001018 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001019 input_sync(info->input);
1020
Mark Brownf2c32a82012-06-24 12:09:45 +01001021 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
1022 if (ret != 0)
1023 dev_err(arizona->dev, "Removal report failed: %d\n",
1024 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001025
1026 regmap_update_bits(arizona->regmap,
1027 ARIZONA_JACK_DETECT_DEBOUNCE,
1028 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1029 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001030 }
1031
Mark Brown7abd4e22013-04-01 19:25:55 +01001032 if (arizona->pdata.micd_timeout)
1033 info->micd_timeout = arizona->pdata.micd_timeout;
1034 else
1035 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1036
Charles Keepax5d9ab702013-02-05 10:13:38 +00001037 /* Clear trig_sts to make sure DCVDD is not forced up */
1038 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1039 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1040 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1041 ARIZONA_JD1_FALL_TRIG_STS |
1042 ARIZONA_JD1_RISE_TRIG_STS);
1043
Mark Browna3e20782013-04-01 19:05:27 +01001044out:
Mark Brownf2c32a82012-06-24 12:09:45 +01001045 mutex_unlock(&info->lock);
1046
1047 pm_runtime_mark_last_busy(info->dev);
1048 pm_runtime_put_autosuspend(info->dev);
1049
1050 return IRQ_HANDLED;
1051}
1052
Mark Brown6fed4d82013-04-01 22:03:06 +01001053/* Map a level onto a slot in the register bank */
1054static void arizona_micd_set_level(struct arizona *arizona, int index,
1055 unsigned int level)
1056{
1057 int reg;
1058 unsigned int mask;
1059
1060 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1061
1062 if (!(index % 2)) {
1063 mask = 0x3f00;
1064 level <<= 8;
1065 } else {
1066 mask = 0x3f;
1067 }
1068
1069 /* Program the level itself */
1070 regmap_update_bits(arizona->regmap, reg, mask, level);
1071}
1072
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001073static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001074{
1075 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
1076 struct arizona_pdata *pdata;
1077 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001078 unsigned int val;
Mark Brown92a49872013-01-11 08:55:39 +09001079 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001080 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001081
Mark Brownbbbd46e2013-01-10 19:38:43 +00001082 if (!arizona->dapm || !arizona->dapm->card)
1083 return -EPROBE_DEFER;
1084
Mark Brownf2c32a82012-06-24 12:09:45 +01001085 pdata = dev_get_platdata(arizona->dev);
1086
1087 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1088 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001089 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +01001090 ret = -ENOMEM;
1091 goto err;
1092 }
1093
1094 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1095 if (IS_ERR(info->micvdd)) {
1096 ret = PTR_ERR(info->micvdd);
1097 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
1098 goto err;
1099 }
1100
1101 mutex_init(&info->lock);
1102 info->arizona = arizona;
1103 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001104 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001105 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001106 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001107 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001108 platform_set_drvdata(pdev, info);
1109
1110 switch (arizona->type) {
1111 case WM5102:
1112 switch (arizona->rev) {
1113 case 0:
1114 info->micd_reva = true;
1115 break;
1116 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001117 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001118 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001119 break;
1120 }
1121 break;
1122 default:
1123 break;
1124 }
1125
1126 info->edev.name = "Headset Jack";
1127 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001128
1129 ret = extcon_dev_register(&info->edev, arizona->dev);
1130 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001131 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001132 ret);
1133 goto err;
1134 }
1135
Mark Brown6fed4d82013-04-01 22:03:06 +01001136 info->input = devm_input_allocate_device(&pdev->dev);
1137 if (!info->input) {
1138 dev_err(arizona->dev, "Can't allocate input dev\n");
1139 ret = -ENOMEM;
1140 goto err_register;
1141 }
1142
1143 info->input->name = "Headset";
1144 info->input->phys = "arizona/extcon";
1145 info->input->dev.parent = &pdev->dev;
1146
Mark Brownf2c32a82012-06-24 12:09:45 +01001147 if (pdata->num_micd_configs) {
1148 info->micd_modes = pdata->micd_configs;
1149 info->micd_num_modes = pdata->num_micd_configs;
1150 } else {
1151 info->micd_modes = micd_default_modes;
1152 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1153 }
1154
1155 if (arizona->pdata.micd_pol_gpio > 0) {
1156 if (info->micd_modes[0].gpio)
1157 mode = GPIOF_OUT_INIT_HIGH;
1158 else
1159 mode = GPIOF_OUT_INIT_LOW;
1160
1161 ret = devm_gpio_request_one(&pdev->dev,
1162 arizona->pdata.micd_pol_gpio,
1163 mode,
1164 "MICD polarity");
1165 if (ret != 0) {
1166 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1167 arizona->pdata.micd_pol_gpio, ret);
1168 goto err_register;
1169 }
1170 }
1171
Mark Brown1eda6aa2013-01-11 08:55:54 +09001172 if (arizona->pdata.hpdet_id_gpio > 0) {
1173 ret = devm_gpio_request_one(&pdev->dev,
1174 arizona->pdata.hpdet_id_gpio,
1175 GPIOF_OUT_INIT_LOW,
1176 "HPDET");
1177 if (ret != 0) {
1178 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1179 arizona->pdata.hpdet_id_gpio, ret);
1180 goto err_register;
1181 }
1182 }
1183
Mark Brownb17e5462013-01-11 08:55:24 +09001184 if (arizona->pdata.micd_bias_start_time)
1185 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1186 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1187 arizona->pdata.micd_bias_start_time
1188 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1189
Mark Brown2e033db2013-01-21 17:36:33 +09001190 if (arizona->pdata.micd_rate)
1191 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1192 ARIZONA_MICD_RATE_MASK,
1193 arizona->pdata.micd_rate
1194 << ARIZONA_MICD_RATE_SHIFT);
1195
1196 if (arizona->pdata.micd_dbtime)
1197 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1198 ARIZONA_MICD_DBTIME_MASK,
1199 arizona->pdata.micd_dbtime
1200 << ARIZONA_MICD_DBTIME_SHIFT);
1201
Mark Brown6fed4d82013-04-01 22:03:06 +01001202 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1203
1204 if (arizona->pdata.num_micd_ranges) {
1205 info->micd_ranges = pdata->micd_ranges;
1206 info->num_micd_ranges = pdata->num_micd_ranges;
1207 } else {
1208 info->micd_ranges = micd_default_ranges;
1209 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1210 }
1211
1212 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1213 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1214 arizona->pdata.num_micd_ranges);
1215 }
1216
1217 if (info->num_micd_ranges > 1) {
1218 for (i = 1; i < info->num_micd_ranges; i++) {
1219 if (info->micd_ranges[i - 1].max >
1220 info->micd_ranges[i].max) {
1221 dev_err(arizona->dev,
1222 "MICD ranges must be sorted\n");
1223 ret = -EINVAL;
1224 goto err_input;
1225 }
1226 }
1227 }
1228
1229 /* Disable all buttons by default */
1230 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1231 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1232
1233 /* Set up all the buttons the user specified */
1234 for (i = 0; i < info->num_micd_ranges; i++) {
1235 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1236 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1237 break;
1238
1239 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1240 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1241 info->micd_ranges[i].max);
1242 ret = -EINVAL;
1243 goto err_input;
1244 }
1245
1246 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1247 arizona_micd_levels[j], i);
1248
1249 arizona_micd_set_level(arizona, i, j);
1250 input_set_capability(info->input, EV_KEY,
1251 info->micd_ranges[i].key);
1252
1253 /* Enable reporting of that range */
1254 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1255 1 << i, 1 << i);
1256 }
1257
1258 /* Set all the remaining keys to a maximum */
1259 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1260 arizona_micd_set_level(arizona, i, 0x3f);
1261
Mark Browndab63eb2013-01-11 08:55:36 +09001262 /*
Mark Brown92a49872013-01-11 08:55:39 +09001263 * If we have a clamp use it, activating in conjunction with
1264 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001265 */
1266 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001267 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001268 /* Put the GPIO into input mode with optional pull */
1269 val = 0xc101;
1270 if (arizona->pdata.jd_gpio5_nopull)
1271 val &= ~ARIZONA_GPN_PU;
1272
Mark Brown92a49872013-01-11 08:55:39 +09001273 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001274 val);
Mark Brown92a49872013-01-11 08:55:39 +09001275
1276 regmap_update_bits(arizona->regmap,
1277 ARIZONA_MICD_CLAMP_CONTROL,
1278 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1279 } else {
1280 regmap_update_bits(arizona->regmap,
1281 ARIZONA_MICD_CLAMP_CONTROL,
1282 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1283 }
1284
Mark Browndab63eb2013-01-11 08:55:36 +09001285 regmap_update_bits(arizona->regmap,
1286 ARIZONA_JACK_DETECT_DEBOUNCE,
1287 ARIZONA_MICD_CLAMP_DB,
1288 ARIZONA_MICD_CLAMP_DB);
1289 }
1290
Mark Brownf2c32a82012-06-24 12:09:45 +01001291 arizona_extcon_set_mode(info, 0);
1292
1293 pm_runtime_enable(&pdev->dev);
1294 pm_runtime_idle(&pdev->dev);
1295 pm_runtime_get_sync(&pdev->dev);
1296
Mark Brown92a49872013-01-11 08:55:39 +09001297 if (arizona->pdata.jd_gpio5) {
1298 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1299 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1300 } else {
1301 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1302 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1303 }
1304
1305 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001306 "JACKDET rise", arizona_jackdet, info);
1307 if (ret != 0) {
1308 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1309 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001310 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001311 }
1312
Mark Brown92a49872013-01-11 08:55:39 +09001313 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001314 if (ret != 0) {
1315 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1316 ret);
1317 goto err_rise;
1318 }
1319
Mark Brown92a49872013-01-11 08:55:39 +09001320 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001321 "JACKDET fall", arizona_jackdet, info);
1322 if (ret != 0) {
1323 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1324 goto err_rise_wake;
1325 }
1326
Mark Brown92a49872013-01-11 08:55:39 +09001327 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001328 if (ret != 0) {
1329 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1330 ret);
1331 goto err_fall;
1332 }
1333
1334 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1335 "MICDET", arizona_micdet, info);
1336 if (ret != 0) {
1337 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1338 goto err_fall_wake;
1339 }
1340
Mark Brown4f340332013-01-11 08:55:43 +09001341 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1342 "HPDET", arizona_hpdet_irq, info);
1343 if (ret != 0) {
1344 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1345 goto err_micdet;
1346 }
1347
Mark Brownf2c32a82012-06-24 12:09:45 +01001348 arizona_clk32k_enable(arizona);
1349 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1350 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1351 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1352 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1353
Mark Brownb8575a12012-09-07 17:01:15 +08001354 ret = regulator_allow_bypass(info->micvdd, true);
1355 if (ret != 0)
1356 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1357 ret);
1358
Mark Brownf2c32a82012-06-24 12:09:45 +01001359 pm_runtime_put(&pdev->dev);
1360
Mark Brown34efe4d2012-07-20 17:07:29 +01001361 ret = input_register_device(info->input);
1362 if (ret) {
1363 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001364 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001365 }
1366
Mark Brownf2c32a82012-06-24 12:09:45 +01001367 return 0;
1368
Mark Brown4f340332013-01-11 08:55:43 +09001369err_hpdet:
1370 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001371err_micdet:
1372 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001373err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001374 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001375err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001376 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001377err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001378 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001379err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001380 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001381err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001382err_register:
1383 pm_runtime_disable(&pdev->dev);
1384 extcon_dev_unregister(&info->edev);
1385err:
1386 return ret;
1387}
1388
Bill Pemberton93ed0322012-11-19 13:25:49 -05001389static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001390{
1391 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1392 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001393 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001394
1395 pm_runtime_disable(&pdev->dev);
1396
Mark Browndab63eb2013-01-11 08:55:36 +09001397 regmap_update_bits(arizona->regmap,
1398 ARIZONA_MICD_CLAMP_CONTROL,
1399 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1400
Mark Brown92a49872013-01-11 08:55:39 +09001401 if (arizona->pdata.jd_gpio5) {
1402 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1403 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1404 } else {
1405 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1406 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1407 }
1408
1409 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1410 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1411 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001412 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001413 arizona_free_irq(arizona, jack_irq_rise, info);
1414 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001415 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001416 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1417 ARIZONA_JD1_ENA, 0);
1418 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001419 extcon_dev_unregister(&info->edev);
1420
1421 return 0;
1422}
1423
1424static struct platform_driver arizona_extcon_driver = {
1425 .driver = {
1426 .name = "arizona-extcon",
1427 .owner = THIS_MODULE,
1428 },
1429 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001430 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001431};
1432
1433module_platform_driver(arizona_extcon_driver);
1434
1435MODULE_DESCRIPTION("Arizona Extcon driver");
1436MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1437MODULE_LICENSE("GPL");
1438MODULE_ALIAS("platform:extcon-arizona");