blob: ba51588cc00054bfcf55b76782e3390daa470434 [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
Richard Fitzgeralda288d642014-05-23 12:54:57 +010042#define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
43#define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
44#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
45#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
46
Mark Brown9dd5e532013-04-01 19:09:45 +010047#define ARIZONA_HPDET_MAX 10000
48
Mark Brown2643fd62013-04-01 19:07:28 +010049#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010050#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010051
Charles Keepaxffae24f2013-11-14 16:18:21 +000052#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
53 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
54 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
55 ARIZONA_MICD_LVL_7)
56
57#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
58
59#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
60
Mark Brownf2c32a82012-06-24 12:09:45 +010061struct arizona_extcon_info {
62 struct device *dev;
63 struct arizona *arizona;
64 struct mutex lock;
65 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010066 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010067
Mark Browna3e20782013-04-01 19:05:27 +010068 u16 last_jackdet;
69
Mark Brownf2c32a82012-06-24 12:09:45 +010070 int micd_mode;
71 const struct arizona_micd_config *micd_modes;
72 int micd_num_modes;
73
Mark Brown6fed4d82013-04-01 22:03:06 +010074 const struct arizona_micd_range *micd_ranges;
75 int num_micd_ranges;
76
Mark Brown7abd4e22013-04-01 19:25:55 +010077 int micd_timeout;
78
Mark Brownf2c32a82012-06-24 12:09:45 +010079 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090080 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010081
Mark Brown0e27bd32013-02-05 21:00:15 +000082 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010083 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010084 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000085
Mark Brown4f340332013-01-11 08:55:43 +090086 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000087 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010088 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090089
Mark Browndd235ee2013-01-11 08:55:51 +090090 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090091 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090092
Mark Brownf2c32a82012-06-24 12:09:45 +010093 bool mic;
94 bool detecting;
95 int jack_flips;
96
Mark Brown4f340332013-01-11 08:55:43 +090097 int hpdet_ip;
98
Chanwoo Choief70a212014-04-21 20:47:31 +090099 struct extcon_dev *edev;
Mark Brownf2c32a82012-06-24 12:09:45 +0100100};
101
102static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +0100103 { ARIZONA_ACCDET_SRC, 1, 0 },
104 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100105};
106
Mark Brown6fed4d82013-04-01 22:03:06 +0100107static const struct arizona_micd_range micd_default_ranges[] = {
108 { .max = 11, .key = BTN_0 },
109 { .max = 28, .key = BTN_1 },
110 { .max = 54, .key = BTN_2 },
111 { .max = 100, .key = BTN_3 },
112 { .max = 186, .key = BTN_4 },
113 { .max = 430, .key = BTN_5 },
114};
115
116static const int arizona_micd_levels[] = {
117 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
118 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
119 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
120 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
121 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100122};
123
Mark Brown325c6422012-06-28 13:08:30 +0100124#define ARIZONA_CABLE_MECHANICAL 0
125#define ARIZONA_CABLE_MICROPHONE 1
126#define ARIZONA_CABLE_HEADPHONE 2
Mark Brown4f340332013-01-11 08:55:43 +0900127#define ARIZONA_CABLE_LINEOUT 3
Mark Brownf2c32a82012-06-24 12:09:45 +0100128
129static const char *arizona_cable[] = {
Mark Brown325c6422012-06-28 13:08:30 +0100130 "Mechanical",
131 "Microphone",
132 "Headphone",
Mark Brown4f340332013-01-11 08:55:43 +0900133 "Line-out",
Mark Brownf2c32a82012-06-24 12:09:45 +0100134 NULL,
135};
136
Mark Brown9dd5e532013-04-01 19:09:45 +0100137static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
138
Mark Brown03409072013-02-12 13:00:31 +0000139static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
140 unsigned int magic)
141{
142 struct arizona *arizona = info->arizona;
Mark Brown03409072013-02-12 13:00:31 +0000143 int ret;
144
145 mutex_lock(&arizona->dapm->card->dapm_mutex);
146
Mark Browndf8c3db2013-02-22 18:38:03 +0000147 arizona->hpdet_magic = magic;
148
149 /* Keep the HP output stages disabled while doing the magic */
150 if (magic) {
151 ret = regmap_update_bits(arizona->regmap,
152 ARIZONA_OUTPUT_ENABLES_1,
153 ARIZONA_OUT1L_ENA |
154 ARIZONA_OUT1R_ENA, 0);
155 if (ret != 0)
156 dev_warn(arizona->dev,
157 "Failed to disable headphone outputs: %d\n",
158 ret);
Mark Brown03409072013-02-12 13:00:31 +0000159 }
160
Mark Browndf8c3db2013-02-22 18:38:03 +0000161 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
162 magic);
163 if (ret != 0)
164 dev_warn(arizona->dev, "Failed to do magic: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000165 ret);
166
Mark Browndf8c3db2013-02-22 18:38:03 +0000167 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
168 magic);
169 if (ret != 0)
170 dev_warn(arizona->dev, "Failed to do magic: %d\n",
171 ret);
172
173 /* Restore the desired state while not doing the magic */
174 if (!magic) {
175 ret = regmap_update_bits(arizona->regmap,
176 ARIZONA_OUTPUT_ENABLES_1,
177 ARIZONA_OUT1L_ENA |
178 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000179 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000180 dev_warn(arizona->dev,
181 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000182 ret);
183 }
184
185 mutex_unlock(&arizona->dapm->card->dapm_mutex);
186}
187
Mark Brownf2c32a82012-06-24 12:09:45 +0100188static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
189{
190 struct arizona *arizona = info->arizona;
191
Mark Brown6fed4d82013-04-01 22:03:06 +0100192 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800193
Mark Browncd74f7b2012-11-27 16:14:26 +0900194 if (arizona->pdata.micd_pol_gpio > 0)
195 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
196 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100197 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
198 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100199 info->micd_modes[mode].bias <<
200 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100201 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
202 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
203
204 info->micd_mode = mode;
205
206 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
207}
208
Mark Brownbbbd46e2013-01-10 19:38:43 +0000209static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
210{
Charles Keepax41024242013-09-23 14:33:59 +0100211 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000212 case 1:
213 return "MICBIAS1";
214 case 2:
215 return "MICBIAS2";
216 case 3:
217 return "MICBIAS3";
218 default:
219 return "MICVDD";
220 }
221}
222
223static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
224{
225 struct arizona *arizona = info->arizona;
226 const char *widget = arizona_extcon_get_micbias(info);
227 struct snd_soc_dapm_context *dapm = arizona->dapm;
228 int ret;
229
Mark Brownbbbd46e2013-01-10 19:38:43 +0000230 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
231 if (ret != 0)
232 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
233 widget, ret);
234
Mark Brownbbbd46e2013-01-10 19:38:43 +0000235 snd_soc_dapm_sync(dapm);
236
237 if (!arizona->pdata.micd_force_micbias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000238 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
239 if (ret != 0)
240 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
241 widget, ret);
242
Mark Brownbbbd46e2013-01-10 19:38:43 +0000243 snd_soc_dapm_sync(dapm);
244 }
245}
246
Mark Brown9b1270c2013-01-11 08:55:46 +0900247static void arizona_start_mic(struct arizona_extcon_info *info)
248{
249 struct arizona *arizona = info->arizona;
250 bool change;
251 int ret;
252
Mark Brown9b1270c2013-01-11 08:55:46 +0900253 /* Microphone detection can't use idle mode */
254 pm_runtime_get(info->dev);
255
Mark Brownbbbd46e2013-01-10 19:38:43 +0000256 if (info->detecting) {
257 ret = regulator_allow_bypass(info->micvdd, false);
258 if (ret != 0) {
259 dev_err(arizona->dev,
260 "Failed to regulate MICVDD: %d\n",
261 ret);
262 }
263 }
264
Mark Brown9b1270c2013-01-11 08:55:46 +0900265 ret = regulator_enable(info->micvdd);
266 if (ret != 0) {
267 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
268 ret);
269 }
270
271 if (info->micd_reva) {
272 regmap_write(arizona->regmap, 0x80, 0x3);
273 regmap_write(arizona->regmap, 0x294, 0);
274 regmap_write(arizona->regmap, 0x80, 0x0);
275 }
276
277 regmap_update_bits(arizona->regmap,
278 ARIZONA_ACCESSORY_DETECT_MODE_1,
279 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
280
Mark Brownbbbd46e2013-01-10 19:38:43 +0000281 arizona_extcon_pulse_micbias(info);
282
Mark Brown9b1270c2013-01-11 08:55:46 +0900283 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
284 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
285 &change);
286 if (!change) {
287 regulator_disable(info->micvdd);
288 pm_runtime_put_autosuspend(info->dev);
289 }
290}
291
292static void arizona_stop_mic(struct arizona_extcon_info *info)
293{
294 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000295 const char *widget = arizona_extcon_get_micbias(info);
296 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900297 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000298 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900299
300 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
301 ARIZONA_MICD_ENA, 0,
302 &change);
303
Mark Brownbbbd46e2013-01-10 19:38:43 +0000304 ret = snd_soc_dapm_disable_pin(dapm, widget);
305 if (ret != 0)
306 dev_warn(arizona->dev,
307 "Failed to disable %s: %d\n",
308 widget, ret);
309
Mark Brownbbbd46e2013-01-10 19:38:43 +0000310 snd_soc_dapm_sync(dapm);
311
Mark Brown9b1270c2013-01-11 08:55:46 +0900312 if (info->micd_reva) {
313 regmap_write(arizona->regmap, 0x80, 0x3);
314 regmap_write(arizona->regmap, 0x294, 2);
315 regmap_write(arizona->regmap, 0x80, 0x0);
316 }
317
Mark Brownbbbd46e2013-01-10 19:38:43 +0000318 ret = regulator_allow_bypass(info->micvdd, true);
319 if (ret != 0) {
320 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
321 ret);
322 }
323
Mark Brown9b1270c2013-01-11 08:55:46 +0900324 if (change) {
325 regulator_disable(info->micvdd);
326 pm_runtime_mark_last_busy(info->dev);
327 pm_runtime_put_autosuspend(info->dev);
328 }
329}
330
Mark Brown4f340332013-01-11 08:55:43 +0900331static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100332 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900333 unsigned int factor_a;
334 unsigned int factor_b;
335} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100336 { 100, 5528, 362464 },
337 { 169, 11084, 6186851 },
338 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900339};
340
Charles Keepax24a279b2014-05-30 13:19:17 +0100341#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
342
Mark Brown4f340332013-01-11 08:55:43 +0900343static struct {
344 int min;
345 int max;
346} arizona_hpdet_c_ranges[] = {
347 { 0, 30 },
348 { 8, 100 },
349 { 100, 1000 },
350 { 1000, 10000 },
351};
352
353static int arizona_hpdet_read(struct arizona_extcon_info *info)
354{
355 struct arizona *arizona = info->arizona;
356 unsigned int val, range;
357 int ret;
358
359 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
360 if (ret != 0) {
361 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
362 ret);
363 return ret;
364 }
365
366 switch (info->hpdet_ip) {
367 case 0:
368 if (!(val & ARIZONA_HP_DONE)) {
369 dev_err(arizona->dev, "HPDET did not complete: %x\n",
370 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900371 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900372 }
373
374 val &= ARIZONA_HP_LVL_MASK;
375 break;
376
377 case 1:
378 if (!(val & ARIZONA_HP_DONE_B)) {
379 dev_err(arizona->dev, "HPDET did not complete: %x\n",
380 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900381 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900382 }
383
384 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
385 if (ret != 0) {
386 dev_err(arizona->dev, "Failed to read HP value: %d\n",
387 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900388 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900389 }
390
391 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
392 &range);
393 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
394 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
395
396 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100397 (val < arizona_hpdet_b_ranges[range].threshold ||
398 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900399 range++;
400 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
401 range);
402 regmap_update_bits(arizona->regmap,
403 ARIZONA_HEADPHONE_DETECT_1,
404 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
405 range <<
406 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
407 return -EAGAIN;
408 }
409
410 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100411 if (val < arizona_hpdet_b_ranges[range].threshold ||
412 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900413 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100414 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900415 }
416
417 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
418 val, range);
419
420 val = arizona_hpdet_b_ranges[range].factor_b
421 / ((val * 100) -
422 arizona_hpdet_b_ranges[range].factor_a);
423 break;
424
425 default:
426 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
427 info->hpdet_ip);
428 case 2:
429 if (!(val & ARIZONA_HP_DONE_B)) {
430 dev_err(arizona->dev, "HPDET did not complete: %x\n",
431 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900432 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900433 }
434
435 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000436 /* Convert to ohms, the value is in 0.5 ohm increments */
437 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900438
439 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
440 &range);
441 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
442 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
443
Charles Keepax91414612013-11-14 16:18:24 +0000444 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900445 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
446 (val >= arizona_hpdet_c_ranges[range].max)) {
447 range++;
448 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
449 arizona_hpdet_c_ranges[range].min,
450 arizona_hpdet_c_ranges[range].max);
451 regmap_update_bits(arizona->regmap,
452 ARIZONA_HEADPHONE_DETECT_1,
453 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
454 range <<
455 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
456 return -EAGAIN;
457 }
Charles Keepax91414612013-11-14 16:18:24 +0000458
459 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
460 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
461 arizona_hpdet_c_ranges[range].min);
462 val = arizona_hpdet_c_ranges[range].min;
463 }
Mark Brown4f340332013-01-11 08:55:43 +0900464 }
465
466 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
467 return val;
468}
469
Mark Brown9c2ba272013-02-25 23:42:31 +0000470static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
471 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900472{
473 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900474 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900475
476 /*
477 * If we're using HPDET for accessory identification we need
478 * to take multiple measurements, step through them in sequence.
479 */
480 if (arizona->pdata.hpdet_acc_id) {
481 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900482
483 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000484 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900485 dev_dbg(arizona->dev, "Measuring mic\n");
486
487 regmap_update_bits(arizona->regmap,
488 ARIZONA_ACCESSORY_DETECT_MODE_1,
489 ARIZONA_ACCDET_MODE_MASK |
490 ARIZONA_ACCDET_SRC,
491 ARIZONA_ACCDET_MODE_HPR |
492 info->micd_modes[0].src);
493
494 gpio_set_value_cansleep(id_gpio, 1);
495
Mark Browndd235ee2013-01-11 08:55:51 +0900496 regmap_update_bits(arizona->regmap,
497 ARIZONA_HEADPHONE_DETECT_1,
498 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
499 return -EAGAIN;
500 }
501
502 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000503 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
504 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000505
506 /* Take the headphone impedance for the main report */
507 *reading = info->hpdet_res[0];
508
Mark Brown9dd5e532013-04-01 19:09:45 +0100509 /* Sometimes we get false readings due to slow insert */
510 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
511 dev_dbg(arizona->dev, "Retrying high impedance\n");
512 info->num_hpdet_res = 0;
513 info->hpdet_retried = true;
514 arizona_start_hpdet_acc_id(info);
515 pm_runtime_put(info->dev);
516 return -EAGAIN;
517 }
518
Mark Brown1eda6aa2013-01-11 08:55:54 +0900519 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530520 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900521 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000522 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900523 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000524 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000525 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900526 } else {
527 dev_dbg(arizona->dev, "Detected headphone\n");
528 }
529
530 /* Make sure everything is reset back to the real polarity */
531 regmap_update_bits(arizona->regmap,
532 ARIZONA_ACCESSORY_DETECT_MODE_1,
533 ARIZONA_ACCDET_SRC,
534 info->micd_modes[0].src);
535 }
536
537 return 0;
538}
539
Mark Brown4f340332013-01-11 08:55:43 +0900540static irqreturn_t arizona_hpdet_irq(int irq, void *data)
541{
542 struct arizona_extcon_info *info = data;
543 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900544 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900545 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900546 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000547 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900548
549 mutex_lock(&info->lock);
550
551 /* If we got a spurious IRQ for some reason then ignore it */
552 if (!info->hpdet_active) {
553 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
554 mutex_unlock(&info->lock);
555 return IRQ_NONE;
556 }
557
558 /* If the cable was removed while measuring ignore the result */
Chanwoo Choief70a212014-04-21 20:47:31 +0900559 ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900560 if (ret < 0) {
561 dev_err(arizona->dev, "Failed to check cable state: %d\n",
562 ret);
563 goto out;
564 } else if (!ret) {
565 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
566 goto done;
567 }
568
569 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900570 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900571 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900572 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900573 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900574 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900575
576 /* Reset back to starting range */
577 regmap_update_bits(arizona->regmap,
578 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900579 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
580 0);
581
Mark Brown9c2ba272013-02-25 23:42:31 +0000582 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900583 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900584 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900585 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900586 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900587
588 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900589 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900590 report = ARIZONA_CABLE_LINEOUT;
591 else
592 report = ARIZONA_CABLE_HEADPHONE;
593
Chanwoo Choief70a212014-04-21 20:47:31 +0900594 ret = extcon_set_cable_state_(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900595 if (ret != 0)
596 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
597 ret);
598
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000599done:
600 /* Reset back to starting range */
601 regmap_update_bits(arizona->regmap,
602 ARIZONA_HEADPHONE_DETECT_1,
603 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
604 0);
605
Mark Brown03409072013-02-12 13:00:31 +0000606 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900607
Mark Brown1eda6aa2013-01-11 08:55:54 +0900608 if (id_gpio)
609 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900610
611 /* Revert back to MICDET mode */
612 regmap_update_bits(arizona->regmap,
613 ARIZONA_ACCESSORY_DETECT_MODE_1,
614 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
615
616 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000617 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900618 arizona_start_mic(info);
619
620 if (info->hpdet_active) {
621 pm_runtime_put_autosuspend(info->dev);
622 info->hpdet_active = false;
623 }
624
Mark Brownbf14ee52013-02-05 20:20:17 +0000625 info->hpdet_done = true;
626
Mark Brown4f340332013-01-11 08:55:43 +0900627out:
628 mutex_unlock(&info->lock);
629
630 return IRQ_HANDLED;
631}
632
633static void arizona_identify_headphone(struct arizona_extcon_info *info)
634{
635 struct arizona *arizona = info->arizona;
636 int ret;
637
Mark Brownbf14ee52013-02-05 20:20:17 +0000638 if (info->hpdet_done)
639 return;
640
Mark Brown4f340332013-01-11 08:55:43 +0900641 dev_dbg(arizona->dev, "Starting HPDET\n");
642
643 /* Make sure we keep the device enabled during the measurement */
644 pm_runtime_get(info->dev);
645
646 info->hpdet_active = true;
647
648 if (info->mic)
649 arizona_stop_mic(info);
650
Mark Brown03409072013-02-12 13:00:31 +0000651 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900652
653 ret = regmap_update_bits(arizona->regmap,
654 ARIZONA_ACCESSORY_DETECT_MODE_1,
655 ARIZONA_ACCDET_MODE_MASK,
656 ARIZONA_ACCDET_MODE_HPL);
657 if (ret != 0) {
658 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
659 goto err;
660 }
661
662 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
663 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
664 if (ret != 0) {
665 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
666 ret);
667 goto err;
668 }
669
670 return;
671
672err:
673 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
674 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
675
676 /* Just report headphone */
Nikesh Oswal34602482014-05-29 16:27:52 +0100677 ret = extcon_set_cable_state_(info->edev,
678 ARIZONA_CABLE_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900679 if (ret != 0)
680 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
681
682 if (info->mic)
683 arizona_start_mic(info);
684
685 info->hpdet_active = false;
686}
Mark Browndd235ee2013-01-11 08:55:51 +0900687
688static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
689{
690 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000691 int hp_reading = 32;
692 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900693 int ret;
694
695 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
696
697 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000698 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900699
700 info->hpdet_active = true;
701
Mark Brown03409072013-02-12 13:00:31 +0000702 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900703
704 ret = regmap_update_bits(arizona->regmap,
705 ARIZONA_ACCESSORY_DETECT_MODE_1,
706 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
707 info->micd_modes[0].src |
708 ARIZONA_ACCDET_MODE_HPL);
709 if (ret != 0) {
710 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
711 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900712 }
713
Mark Brown9c2ba272013-02-25 23:42:31 +0000714 if (arizona->pdata.hpdet_acc_id_line) {
715 ret = regmap_update_bits(arizona->regmap,
716 ARIZONA_HEADPHONE_DETECT_1,
717 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
718 if (ret != 0) {
719 dev_err(arizona->dev,
720 "Can't start HPDETL measurement: %d\n",
721 ret);
722 goto err;
723 }
724 } else {
725 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900726 }
727
728 return;
729
730err:
731 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
732 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
733
734 /* Just report headphone */
Nikesh Oswal34602482014-05-29 16:27:52 +0100735 ret = extcon_set_cable_state_(info->edev,
736 ARIZONA_CABLE_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900737 if (ret != 0)
738 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
739
Mark Brown4f340332013-01-11 08:55:43 +0900740 info->hpdet_active = false;
741}
742
Mark Brown939c5672013-04-01 19:17:34 +0100743static void arizona_micd_timeout_work(struct work_struct *work)
744{
745 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900746 struct arizona_extcon_info,
747 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100748
749 mutex_lock(&info->lock);
750
751 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
752 arizona_identify_headphone(info);
753
754 info->detecting = false;
755
756 arizona_stop_mic(info);
757
758 mutex_unlock(&info->lock);
759}
760
Mark Browncd59e792013-04-01 19:21:48 +0100761static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100762{
Mark Browncd59e792013-04-01 19:21:48 +0100763 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900764 struct arizona_extcon_info,
765 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100766 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100767 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100768 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100769
Mark Brown939c5672013-04-01 19:17:34 +0100770 cancel_delayed_work_sync(&info->micd_timeout_work);
771
Mark Brownf2c32a82012-06-24 12:09:45 +0100772 mutex_lock(&info->lock);
773
Charles Keepax31a847e2013-11-14 16:18:23 +0000774 /* If the cable was removed while measuring ignore the result */
Chanwoo Choief70a212014-04-21 20:47:31 +0900775 ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000776 if (ret < 0) {
777 dev_err(arizona->dev, "Failed to check cable state: %d\n",
778 ret);
779 mutex_unlock(&info->lock);
780 return;
781 } else if (!ret) {
782 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
783 mutex_unlock(&info->lock);
784 return;
785 }
786
Charles Keepaxffae24f2013-11-14 16:18:21 +0000787 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100788 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
789 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900790 dev_err(arizona->dev,
791 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100792 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100793 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100794 }
795
796 dev_dbg(arizona->dev, "MICDET: %x\n", val);
797
798 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900799 dev_warn(arizona->dev,
800 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100801 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100802 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100803 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100804 }
805
Charles Keepaxffae24f2013-11-14 16:18:21 +0000806 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100807 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100808 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100809 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100810 }
811
812 /* Due to jack detect this should never happen */
813 if (!(val & ARIZONA_MICD_STS)) {
814 dev_warn(arizona->dev, "Detected open circuit\n");
815 info->detecting = false;
816 goto handled;
817 }
818
819 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000820 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900821 arizona_identify_headphone(info);
822
Nikesh Oswal34602482014-05-29 16:27:52 +0100823 ret = extcon_set_cable_state_(info->edev,
824 ARIZONA_CABLE_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100825
826 if (ret != 0)
827 dev_err(arizona->dev, "Headset report failed: %d\n",
828 ret);
829
Mark Brownbbbd46e2013-01-10 19:38:43 +0000830 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100831 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000832 if (ret != 0) {
833 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
834 ret);
835 }
836
Mark Brownf2c32a82012-06-24 12:09:45 +0100837 info->mic = true;
838 info->detecting = false;
839 goto handled;
840 }
841
842 /* If we detected a lower impedence during initial startup
843 * then we probably have the wrong polarity, flip it. Don't
844 * do this for the lowest impedences to speed up detection of
845 * plain headphones. If both polarities report a low
846 * impedence then give up and report headphones.
847 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000848 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800849 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900850 dev_dbg(arizona->dev, "Detected HP/line\n");
851 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100852
Mark Brown4f340332013-01-11 08:55:43 +0900853 info->detecting = false;
854
855 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100856 } else {
857 info->micd_mode++;
858 if (info->micd_mode == info->micd_num_modes)
859 info->micd_mode = 0;
860 arizona_extcon_set_mode(info, info->micd_mode);
861
862 info->jack_flips++;
863 }
864
865 goto handled;
866 }
867
868 /*
869 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100870 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100871 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000872 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100873 if (info->mic) {
874 dev_dbg(arizona->dev, "Mic button detected\n");
875
Mark Brown34efe4d2012-07-20 17:07:29 +0100876 lvl = val & ARIZONA_MICD_LVL_MASK;
877 lvl >>= ARIZONA_MICD_LVL_SHIFT;
878
Mark Brown41a57852013-04-01 19:18:18 +0100879 for (i = 0; i < info->num_micd_ranges; i++)
880 input_report_key(info->input,
881 info->micd_ranges[i].key, 0);
882
Mark Brown6fed4d82013-04-01 22:03:06 +0100883 WARN_ON(!lvl);
884 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
885 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
886 key = info->micd_ranges[ffs(lvl) - 1].key;
887 input_report_key(info->input, key, 1);
888 input_sync(info->input);
889 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100890
Mark Brownf2c32a82012-06-24 12:09:45 +0100891 } else if (info->detecting) {
892 dev_dbg(arizona->dev, "Headphone detected\n");
893 info->detecting = false;
894 arizona_stop_mic(info);
895
Mark Brown4f340332013-01-11 08:55:43 +0900896 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100897 } else {
898 dev_warn(arizona->dev, "Button with no mic: %x\n",
899 val);
900 }
901 } else {
902 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100903 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100904 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100905 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100906 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000907 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100908 }
909
910handled:
Mark Brown939c5672013-04-01 19:17:34 +0100911 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100912 queue_delayed_work(system_power_efficient_wq,
913 &info->micd_timeout_work,
914 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100915
Mark Brownf2c32a82012-06-24 12:09:45 +0100916 pm_runtime_mark_last_busy(info->dev);
917 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100918}
919
920static irqreturn_t arizona_micdet(int irq, void *data)
921{
922 struct arizona_extcon_info *info = data;
923 struct arizona *arizona = info->arizona;
924 int debounce = arizona->pdata.micd_detect_debounce;
925
926 cancel_delayed_work_sync(&info->micd_detect_work);
927 cancel_delayed_work_sync(&info->micd_timeout_work);
928
929 mutex_lock(&info->lock);
930 if (!info->detecting)
931 debounce = 0;
932 mutex_unlock(&info->lock);
933
934 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100935 queue_delayed_work(system_power_efficient_wq,
936 &info->micd_detect_work,
937 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100938 else
939 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100940
941 return IRQ_HANDLED;
942}
943
Mark Brown0e27bd32013-02-05 21:00:15 +0000944static void arizona_hpdet_work(struct work_struct *work)
945{
946 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900947 struct arizona_extcon_info,
948 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000949
950 mutex_lock(&info->lock);
951 arizona_start_hpdet_acc_id(info);
952 mutex_unlock(&info->lock);
953}
954
Mark Brownf2c32a82012-06-24 12:09:45 +0100955static irqreturn_t arizona_jackdet(int irq, void *data)
956{
957 struct arizona_extcon_info *info = data;
958 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900959 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100960 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100961 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100962
Mark Brown939c5672013-04-01 19:17:34 +0100963 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
964 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100965
Mark Browna3e20782013-04-01 19:05:27 +0100966 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000967
Mark Brownf2c32a82012-06-24 12:09:45 +0100968 mutex_lock(&info->lock);
969
Mark Brown92a49872013-01-11 08:55:39 +0900970 if (arizona->pdata.jd_gpio5) {
971 mask = ARIZONA_MICD_CLAMP_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100972 if (arizona->pdata.jd_invert)
973 present = ARIZONA_MICD_CLAMP_STS;
974 else
975 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +0900976 } else {
977 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100978 if (arizona->pdata.jd_invert)
979 present = 0;
980 else
981 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +0900982 }
983
Mark Brownf2c32a82012-06-24 12:09:45 +0100984 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
985 if (ret != 0) {
986 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
987 ret);
988 mutex_unlock(&info->lock);
989 pm_runtime_put_autosuspend(info->dev);
990 return IRQ_NONE;
991 }
992
Mark Browna3e20782013-04-01 19:05:27 +0100993 val &= mask;
994 if (val == info->last_jackdet) {
995 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +0100996 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100997 queue_delayed_work(system_power_efficient_wq,
998 &info->hpdet_work,
999 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001000
Chanwoo Choic2275d22013-08-23 10:21:37 +09001001 if (cancelled_mic) {
1002 int micd_timeout = info->micd_timeout;
1003
Mark Browndf9a5ab2013-07-18 22:42:22 +01001004 queue_delayed_work(system_power_efficient_wq,
1005 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001006 msecs_to_jiffies(micd_timeout));
1007 }
Mark Brown939c5672013-04-01 19:17:34 +01001008
Mark Browna3e20782013-04-01 19:05:27 +01001009 goto out;
1010 }
1011 info->last_jackdet = val;
1012
1013 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001014 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choief70a212014-04-21 20:47:31 +09001015 ret = extcon_set_cable_state_(info->edev,
Mark Brown325c6422012-06-28 13:08:30 +01001016 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001017
1018 if (ret != 0)
1019 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1020 ret);
1021
Mark Browndd235ee2013-01-11 08:55:51 +09001022 if (!arizona->pdata.hpdet_acc_id) {
1023 info->detecting = true;
1024 info->mic = false;
1025 info->jack_flips = 0;
1026
1027 arizona_start_mic(info);
1028 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001029 queue_delayed_work(system_power_efficient_wq,
1030 &info->hpdet_work,
1031 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001032 }
Mark Brown4e616872013-01-15 22:09:20 +09001033
1034 regmap_update_bits(arizona->regmap,
1035 ARIZONA_JACK_DETECT_DEBOUNCE,
1036 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001037 } else {
1038 dev_dbg(arizona->dev, "Detected jack removal\n");
1039
1040 arizona_stop_mic(info);
1041
Mark Browndd235ee2013-01-11 08:55:51 +09001042 info->num_hpdet_res = 0;
1043 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1044 info->hpdet_res[i] = 0;
1045 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001046 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001047 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001048
Mark Brown6fed4d82013-04-01 22:03:06 +01001049 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001050 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001051 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001052 input_sync(info->input);
1053
Chanwoo Choief70a212014-04-21 20:47:31 +09001054 ret = extcon_update_state(info->edev, 0xffffffff, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001055 if (ret != 0)
1056 dev_err(arizona->dev, "Removal report failed: %d\n",
1057 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001058
1059 regmap_update_bits(arizona->regmap,
1060 ARIZONA_JACK_DETECT_DEBOUNCE,
1061 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1062 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001063 }
1064
Mark Brown7abd4e22013-04-01 19:25:55 +01001065 if (arizona->pdata.micd_timeout)
1066 info->micd_timeout = arizona->pdata.micd_timeout;
1067 else
1068 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1069
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001070out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001071 /* Clear trig_sts to make sure DCVDD is not forced up */
1072 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1073 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1074 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1075 ARIZONA_JD1_FALL_TRIG_STS |
1076 ARIZONA_JD1_RISE_TRIG_STS);
1077
Mark Brownf2c32a82012-06-24 12:09:45 +01001078 mutex_unlock(&info->lock);
1079
1080 pm_runtime_mark_last_busy(info->dev);
1081 pm_runtime_put_autosuspend(info->dev);
1082
1083 return IRQ_HANDLED;
1084}
1085
Mark Brown6fed4d82013-04-01 22:03:06 +01001086/* Map a level onto a slot in the register bank */
1087static void arizona_micd_set_level(struct arizona *arizona, int index,
1088 unsigned int level)
1089{
1090 int reg;
1091 unsigned int mask;
1092
1093 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1094
1095 if (!(index % 2)) {
1096 mask = 0x3f00;
1097 level <<= 8;
1098 } else {
1099 mask = 0x3f;
1100 }
1101
1102 /* Program the level itself */
1103 regmap_update_bits(arizona->regmap, reg, mask, level);
1104}
1105
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001106static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001107{
1108 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001109 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001110 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001111 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001112 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001113 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001114 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001115
Mark Brownbbbd46e2013-01-10 19:38:43 +00001116 if (!arizona->dapm || !arizona->dapm->card)
1117 return -EPROBE_DEFER;
1118
Mark Brownf2c32a82012-06-24 12:09:45 +01001119 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001120 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001121 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001122
Charles Keepax17271f62014-07-18 12:59:00 +01001123 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001124 if (IS_ERR(info->micvdd)) {
1125 ret = PTR_ERR(info->micvdd);
1126 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001127 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001128 }
1129
1130 mutex_init(&info->lock);
1131 info->arizona = arizona;
1132 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001133 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001134 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001135 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001136 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001137 platform_set_drvdata(pdev, info);
1138
1139 switch (arizona->type) {
1140 case WM5102:
1141 switch (arizona->rev) {
1142 case 0:
1143 info->micd_reva = true;
1144 break;
1145 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001146 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001147 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001148 break;
1149 }
1150 break;
Charles Keepax77438612013-11-14 16:18:25 +00001151 case WM5110:
1152 switch (arizona->rev) {
1153 case 0 ... 2:
1154 break;
1155 default:
1156 info->micd_clamp = true;
1157 info->hpdet_ip = 2;
1158 break;
1159 }
1160 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001161 default:
1162 break;
1163 }
1164
Chanwoo Choief70a212014-04-21 20:47:31 +09001165 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1166 if (IS_ERR(info->edev)) {
1167 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1168 return -ENOMEM;
1169 }
1170 info->edev->name = "Headset Jack";
Mark Brownf2c32a82012-06-24 12:09:45 +01001171
Chanwoo Choief70a212014-04-21 20:47:31 +09001172 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001173 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001174 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001175 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001176 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001177 }
1178
Mark Brown6fed4d82013-04-01 22:03:06 +01001179 info->input = devm_input_allocate_device(&pdev->dev);
1180 if (!info->input) {
1181 dev_err(arizona->dev, "Can't allocate input dev\n");
1182 ret = -ENOMEM;
1183 goto err_register;
1184 }
1185
1186 info->input->name = "Headset";
1187 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001188
Mark Brownf2c32a82012-06-24 12:09:45 +01001189 if (pdata->num_micd_configs) {
1190 info->micd_modes = pdata->micd_configs;
1191 info->micd_num_modes = pdata->num_micd_configs;
1192 } else {
1193 info->micd_modes = micd_default_modes;
1194 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1195 }
1196
1197 if (arizona->pdata.micd_pol_gpio > 0) {
1198 if (info->micd_modes[0].gpio)
1199 mode = GPIOF_OUT_INIT_HIGH;
1200 else
1201 mode = GPIOF_OUT_INIT_LOW;
1202
1203 ret = devm_gpio_request_one(&pdev->dev,
1204 arizona->pdata.micd_pol_gpio,
1205 mode,
1206 "MICD polarity");
1207 if (ret != 0) {
1208 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1209 arizona->pdata.micd_pol_gpio, ret);
1210 goto err_register;
1211 }
1212 }
1213
Mark Brown1eda6aa2013-01-11 08:55:54 +09001214 if (arizona->pdata.hpdet_id_gpio > 0) {
1215 ret = devm_gpio_request_one(&pdev->dev,
1216 arizona->pdata.hpdet_id_gpio,
1217 GPIOF_OUT_INIT_LOW,
1218 "HPDET");
1219 if (ret != 0) {
1220 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1221 arizona->pdata.hpdet_id_gpio, ret);
1222 goto err_register;
1223 }
1224 }
1225
Mark Brownb17e5462013-01-11 08:55:24 +09001226 if (arizona->pdata.micd_bias_start_time)
1227 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1228 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1229 arizona->pdata.micd_bias_start_time
1230 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1231
Mark Brown2e033db2013-01-21 17:36:33 +09001232 if (arizona->pdata.micd_rate)
1233 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1234 ARIZONA_MICD_RATE_MASK,
1235 arizona->pdata.micd_rate
1236 << ARIZONA_MICD_RATE_SHIFT);
1237
1238 if (arizona->pdata.micd_dbtime)
1239 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1240 ARIZONA_MICD_DBTIME_MASK,
1241 arizona->pdata.micd_dbtime
1242 << ARIZONA_MICD_DBTIME_SHIFT);
1243
Mark Brown6fed4d82013-04-01 22:03:06 +01001244 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1245
1246 if (arizona->pdata.num_micd_ranges) {
1247 info->micd_ranges = pdata->micd_ranges;
1248 info->num_micd_ranges = pdata->num_micd_ranges;
1249 } else {
1250 info->micd_ranges = micd_default_ranges;
1251 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1252 }
1253
1254 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1255 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1256 arizona->pdata.num_micd_ranges);
1257 }
1258
1259 if (info->num_micd_ranges > 1) {
1260 for (i = 1; i < info->num_micd_ranges; i++) {
1261 if (info->micd_ranges[i - 1].max >
1262 info->micd_ranges[i].max) {
1263 dev_err(arizona->dev,
1264 "MICD ranges must be sorted\n");
1265 ret = -EINVAL;
1266 goto err_input;
1267 }
1268 }
1269 }
1270
1271 /* Disable all buttons by default */
1272 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1273 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1274
1275 /* Set up all the buttons the user specified */
1276 for (i = 0; i < info->num_micd_ranges; i++) {
1277 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1278 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1279 break;
1280
1281 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1282 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1283 info->micd_ranges[i].max);
1284 ret = -EINVAL;
1285 goto err_input;
1286 }
1287
1288 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1289 arizona_micd_levels[j], i);
1290
1291 arizona_micd_set_level(arizona, i, j);
1292 input_set_capability(info->input, EV_KEY,
1293 info->micd_ranges[i].key);
1294
1295 /* Enable reporting of that range */
1296 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1297 1 << i, 1 << i);
1298 }
1299
1300 /* Set all the remaining keys to a maximum */
1301 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1302 arizona_micd_set_level(arizona, i, 0x3f);
1303
Mark Browndab63eb2013-01-11 08:55:36 +09001304 /*
Mark Brown92a49872013-01-11 08:55:39 +09001305 * If we have a clamp use it, activating in conjunction with
1306 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001307 */
1308 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001309 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001310 /* Put the GPIO into input mode with optional pull */
1311 val = 0xc101;
1312 if (arizona->pdata.jd_gpio5_nopull)
1313 val &= ~ARIZONA_GPN_PU;
1314
Mark Brown92a49872013-01-11 08:55:39 +09001315 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001316 val);
Mark Brown92a49872013-01-11 08:55:39 +09001317
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001318 if (arizona->pdata.jd_invert)
1319 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1320 else
1321 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001322 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001323 if (arizona->pdata.jd_invert)
1324 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1325 else
1326 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001327 }
1328
Mark Browndab63eb2013-01-11 08:55:36 +09001329 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001330 ARIZONA_MICD_CLAMP_CONTROL,
1331 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1332
1333 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001334 ARIZONA_JACK_DETECT_DEBOUNCE,
1335 ARIZONA_MICD_CLAMP_DB,
1336 ARIZONA_MICD_CLAMP_DB);
1337 }
1338
Mark Brownf2c32a82012-06-24 12:09:45 +01001339 arizona_extcon_set_mode(info, 0);
1340
1341 pm_runtime_enable(&pdev->dev);
1342 pm_runtime_idle(&pdev->dev);
1343 pm_runtime_get_sync(&pdev->dev);
1344
Mark Brown92a49872013-01-11 08:55:39 +09001345 if (arizona->pdata.jd_gpio5) {
1346 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1347 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1348 } else {
1349 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1350 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1351 }
1352
1353 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001354 "JACKDET rise", arizona_jackdet, info);
1355 if (ret != 0) {
1356 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1357 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001358 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001359 }
1360
Mark Brown92a49872013-01-11 08:55:39 +09001361 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001362 if (ret != 0) {
1363 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1364 ret);
1365 goto err_rise;
1366 }
1367
Mark Brown92a49872013-01-11 08:55:39 +09001368 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001369 "JACKDET fall", arizona_jackdet, info);
1370 if (ret != 0) {
1371 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1372 goto err_rise_wake;
1373 }
1374
Mark Brown92a49872013-01-11 08:55:39 +09001375 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001376 if (ret != 0) {
1377 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1378 ret);
1379 goto err_fall;
1380 }
1381
1382 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1383 "MICDET", arizona_micdet, info);
1384 if (ret != 0) {
1385 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1386 goto err_fall_wake;
1387 }
1388
Mark Brown4f340332013-01-11 08:55:43 +09001389 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1390 "HPDET", arizona_hpdet_irq, info);
1391 if (ret != 0) {
1392 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1393 goto err_micdet;
1394 }
1395
Mark Brownf2c32a82012-06-24 12:09:45 +01001396 arizona_clk32k_enable(arizona);
1397 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1398 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1399 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1400 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1401
Mark Brownb8575a12012-09-07 17:01:15 +08001402 ret = regulator_allow_bypass(info->micvdd, true);
1403 if (ret != 0)
1404 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1405 ret);
1406
Mark Brownf2c32a82012-06-24 12:09:45 +01001407 pm_runtime_put(&pdev->dev);
1408
Mark Brown34efe4d2012-07-20 17:07:29 +01001409 ret = input_register_device(info->input);
1410 if (ret) {
1411 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001412 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001413 }
1414
Mark Brownf2c32a82012-06-24 12:09:45 +01001415 return 0;
1416
Mark Brown4f340332013-01-11 08:55:43 +09001417err_hpdet:
1418 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001419err_micdet:
1420 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001421err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001422 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001423err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001424 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001425err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001426 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001427err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001428 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001429err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001430err_register:
1431 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001432 return ret;
1433}
1434
Bill Pemberton93ed0322012-11-19 13:25:49 -05001435static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001436{
1437 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1438 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001439 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001440
1441 pm_runtime_disable(&pdev->dev);
1442
Mark Browndab63eb2013-01-11 08:55:36 +09001443 regmap_update_bits(arizona->regmap,
1444 ARIZONA_MICD_CLAMP_CONTROL,
1445 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1446
Mark Brown92a49872013-01-11 08:55:39 +09001447 if (arizona->pdata.jd_gpio5) {
1448 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1449 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1450 } else {
1451 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1452 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1453 }
1454
1455 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1456 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1457 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001458 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001459 arizona_free_irq(arizona, jack_irq_rise, info);
1460 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001461 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001462 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1463 ARIZONA_JD1_ENA, 0);
1464 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001465
1466 return 0;
1467}
1468
1469static struct platform_driver arizona_extcon_driver = {
1470 .driver = {
1471 .name = "arizona-extcon",
1472 .owner = THIS_MODULE,
1473 },
1474 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001475 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001476};
1477
1478module_platform_driver(arizona_extcon_driver);
1479
1480MODULE_DESCRIPTION("Arizona Extcon driver");
1481MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1482MODULE_LICENSE("GPL");
1483MODULE_ALIAS("platform:extcon-arizona");