blob: cf907430a69854cabe6750a1b1cffd2cc59df3fc [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 {
332 unsigned int factor_a;
333 unsigned int factor_b;
334} arizona_hpdet_b_ranges[] = {
335 { 5528, 362464 },
336 { 11084, 6186851 },
337 { 11065, 65460395 },
338};
339
340static struct {
341 int min;
342 int max;
343} arizona_hpdet_c_ranges[] = {
344 { 0, 30 },
345 { 8, 100 },
346 { 100, 1000 },
347 { 1000, 10000 },
348};
349
350static int arizona_hpdet_read(struct arizona_extcon_info *info)
351{
352 struct arizona *arizona = info->arizona;
353 unsigned int val, range;
354 int ret;
355
356 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
357 if (ret != 0) {
358 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
359 ret);
360 return ret;
361 }
362
363 switch (info->hpdet_ip) {
364 case 0:
365 if (!(val & ARIZONA_HP_DONE)) {
366 dev_err(arizona->dev, "HPDET did not complete: %x\n",
367 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900368 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900369 }
370
371 val &= ARIZONA_HP_LVL_MASK;
372 break;
373
374 case 1:
375 if (!(val & ARIZONA_HP_DONE_B)) {
376 dev_err(arizona->dev, "HPDET did not complete: %x\n",
377 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900378 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900379 }
380
381 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
382 if (ret != 0) {
383 dev_err(arizona->dev, "Failed to read HP value: %d\n",
384 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900385 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900386 }
387
388 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
389 &range);
390 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
391 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
392
393 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100394 (val < 100 || val >= 0x3fb)) {
Mark Brown4f340332013-01-11 08:55:43 +0900395 range++;
396 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
397 range);
398 regmap_update_bits(arizona->regmap,
399 ARIZONA_HEADPHONE_DETECT_1,
400 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
401 range <<
402 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
403 return -EAGAIN;
404 }
405
406 /* If we go out of range report top of range */
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100407 if (val < 100 || val >= 0x3fb) {
Mark Brown4f340332013-01-11 08:55:43 +0900408 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100409 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900410 }
411
412 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
413 val, range);
414
415 val = arizona_hpdet_b_ranges[range].factor_b
416 / ((val * 100) -
417 arizona_hpdet_b_ranges[range].factor_a);
418 break;
419
420 default:
421 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
422 info->hpdet_ip);
423 case 2:
424 if (!(val & ARIZONA_HP_DONE_B)) {
425 dev_err(arizona->dev, "HPDET did not complete: %x\n",
426 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900427 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900428 }
429
430 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000431 /* Convert to ohms, the value is in 0.5 ohm increments */
432 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900433
434 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
435 &range);
436 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
437 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
438
Charles Keepax91414612013-11-14 16:18:24 +0000439 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900440 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
441 (val >= arizona_hpdet_c_ranges[range].max)) {
442 range++;
443 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
444 arizona_hpdet_c_ranges[range].min,
445 arizona_hpdet_c_ranges[range].max);
446 regmap_update_bits(arizona->regmap,
447 ARIZONA_HEADPHONE_DETECT_1,
448 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
449 range <<
450 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
451 return -EAGAIN;
452 }
Charles Keepax91414612013-11-14 16:18:24 +0000453
454 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
455 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
456 arizona_hpdet_c_ranges[range].min);
457 val = arizona_hpdet_c_ranges[range].min;
458 }
Mark Brown4f340332013-01-11 08:55:43 +0900459 }
460
461 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
462 return val;
463}
464
Mark Brown9c2ba272013-02-25 23:42:31 +0000465static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
466 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900467{
468 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900469 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900470
471 /*
472 * If we're using HPDET for accessory identification we need
473 * to take multiple measurements, step through them in sequence.
474 */
475 if (arizona->pdata.hpdet_acc_id) {
476 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900477
478 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000479 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900480 dev_dbg(arizona->dev, "Measuring mic\n");
481
482 regmap_update_bits(arizona->regmap,
483 ARIZONA_ACCESSORY_DETECT_MODE_1,
484 ARIZONA_ACCDET_MODE_MASK |
485 ARIZONA_ACCDET_SRC,
486 ARIZONA_ACCDET_MODE_HPR |
487 info->micd_modes[0].src);
488
489 gpio_set_value_cansleep(id_gpio, 1);
490
Mark Browndd235ee2013-01-11 08:55:51 +0900491 regmap_update_bits(arizona->regmap,
492 ARIZONA_HEADPHONE_DETECT_1,
493 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
494 return -EAGAIN;
495 }
496
497 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000498 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
499 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000500
501 /* Take the headphone impedance for the main report */
502 *reading = info->hpdet_res[0];
503
Mark Brown9dd5e532013-04-01 19:09:45 +0100504 /* Sometimes we get false readings due to slow insert */
505 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
506 dev_dbg(arizona->dev, "Retrying high impedance\n");
507 info->num_hpdet_res = 0;
508 info->hpdet_retried = true;
509 arizona_start_hpdet_acc_id(info);
510 pm_runtime_put(info->dev);
511 return -EAGAIN;
512 }
513
Mark Brown1eda6aa2013-01-11 08:55:54 +0900514 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530515 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900516 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000517 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900518 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000519 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000520 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900521 } else {
522 dev_dbg(arizona->dev, "Detected headphone\n");
523 }
524
525 /* Make sure everything is reset back to the real polarity */
526 regmap_update_bits(arizona->regmap,
527 ARIZONA_ACCESSORY_DETECT_MODE_1,
528 ARIZONA_ACCDET_SRC,
529 info->micd_modes[0].src);
530 }
531
532 return 0;
533}
534
Mark Brown4f340332013-01-11 08:55:43 +0900535static irqreturn_t arizona_hpdet_irq(int irq, void *data)
536{
537 struct arizona_extcon_info *info = data;
538 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900539 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900540 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900541 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000542 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900543
544 mutex_lock(&info->lock);
545
546 /* If we got a spurious IRQ for some reason then ignore it */
547 if (!info->hpdet_active) {
548 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
549 mutex_unlock(&info->lock);
550 return IRQ_NONE;
551 }
552
553 /* If the cable was removed while measuring ignore the result */
Chanwoo Choief70a212014-04-21 20:47:31 +0900554 ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900555 if (ret < 0) {
556 dev_err(arizona->dev, "Failed to check cable state: %d\n",
557 ret);
558 goto out;
559 } else if (!ret) {
560 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
561 goto done;
562 }
563
564 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900565 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900566 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900567 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900568 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900569 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900570
571 /* Reset back to starting range */
572 regmap_update_bits(arizona->regmap,
573 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900574 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
575 0);
576
Mark Brown9c2ba272013-02-25 23:42:31 +0000577 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900578 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900579 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900580 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900581 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900582
583 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900584 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900585 report = ARIZONA_CABLE_LINEOUT;
586 else
587 report = ARIZONA_CABLE_HEADPHONE;
588
Chanwoo Choief70a212014-04-21 20:47:31 +0900589 ret = extcon_set_cable_state_(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900590 if (ret != 0)
591 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
592 ret);
593
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000594done:
595 /* Reset back to starting range */
596 regmap_update_bits(arizona->regmap,
597 ARIZONA_HEADPHONE_DETECT_1,
598 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
599 0);
600
Mark Brown03409072013-02-12 13:00:31 +0000601 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900602
Mark Brown1eda6aa2013-01-11 08:55:54 +0900603 if (id_gpio)
604 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900605
606 /* Revert back to MICDET mode */
607 regmap_update_bits(arizona->regmap,
608 ARIZONA_ACCESSORY_DETECT_MODE_1,
609 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
610
611 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000612 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900613 arizona_start_mic(info);
614
615 if (info->hpdet_active) {
616 pm_runtime_put_autosuspend(info->dev);
617 info->hpdet_active = false;
618 }
619
Mark Brownbf14ee52013-02-05 20:20:17 +0000620 info->hpdet_done = true;
621
Mark Brown4f340332013-01-11 08:55:43 +0900622out:
623 mutex_unlock(&info->lock);
624
625 return IRQ_HANDLED;
626}
627
628static void arizona_identify_headphone(struct arizona_extcon_info *info)
629{
630 struct arizona *arizona = info->arizona;
631 int ret;
632
Mark Brownbf14ee52013-02-05 20:20:17 +0000633 if (info->hpdet_done)
634 return;
635
Mark Brown4f340332013-01-11 08:55:43 +0900636 dev_dbg(arizona->dev, "Starting HPDET\n");
637
638 /* Make sure we keep the device enabled during the measurement */
639 pm_runtime_get(info->dev);
640
641 info->hpdet_active = true;
642
643 if (info->mic)
644 arizona_stop_mic(info);
645
Mark Brown03409072013-02-12 13:00:31 +0000646 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900647
648 ret = regmap_update_bits(arizona->regmap,
649 ARIZONA_ACCESSORY_DETECT_MODE_1,
650 ARIZONA_ACCDET_MODE_MASK,
651 ARIZONA_ACCDET_MODE_HPL);
652 if (ret != 0) {
653 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
654 goto err;
655 }
656
657 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
658 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
659 if (ret != 0) {
660 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
661 ret);
662 goto err;
663 }
664
665 return;
666
667err:
668 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
669 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
670
671 /* Just report headphone */
Chanwoo Choief70a212014-04-21 20:47:31 +0900672 ret = extcon_update_state(info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900673 1 << ARIZONA_CABLE_HEADPHONE,
674 1 << ARIZONA_CABLE_HEADPHONE);
675 if (ret != 0)
676 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
677
678 if (info->mic)
679 arizona_start_mic(info);
680
681 info->hpdet_active = false;
682}
Mark Browndd235ee2013-01-11 08:55:51 +0900683
684static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
685{
686 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000687 int hp_reading = 32;
688 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900689 int ret;
690
691 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
692
693 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000694 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900695
696 info->hpdet_active = true;
697
Mark Brown03409072013-02-12 13:00:31 +0000698 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900699
700 ret = regmap_update_bits(arizona->regmap,
701 ARIZONA_ACCESSORY_DETECT_MODE_1,
702 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
703 info->micd_modes[0].src |
704 ARIZONA_ACCDET_MODE_HPL);
705 if (ret != 0) {
706 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
707 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900708 }
709
Mark Brown9c2ba272013-02-25 23:42:31 +0000710 if (arizona->pdata.hpdet_acc_id_line) {
711 ret = regmap_update_bits(arizona->regmap,
712 ARIZONA_HEADPHONE_DETECT_1,
713 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
714 if (ret != 0) {
715 dev_err(arizona->dev,
716 "Can't start HPDETL measurement: %d\n",
717 ret);
718 goto err;
719 }
720 } else {
721 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900722 }
723
724 return;
725
726err:
727 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
728 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
729
730 /* Just report headphone */
Chanwoo Choief70a212014-04-21 20:47:31 +0900731 ret = extcon_update_state(info->edev,
Mark Browndd235ee2013-01-11 08:55:51 +0900732 1 << ARIZONA_CABLE_HEADPHONE,
733 1 << ARIZONA_CABLE_HEADPHONE);
734 if (ret != 0)
735 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
736
Mark Brown4f340332013-01-11 08:55:43 +0900737 info->hpdet_active = false;
738}
739
Mark Brown939c5672013-04-01 19:17:34 +0100740static void arizona_micd_timeout_work(struct work_struct *work)
741{
742 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900743 struct arizona_extcon_info,
744 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100745
746 mutex_lock(&info->lock);
747
748 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
749 arizona_identify_headphone(info);
750
751 info->detecting = false;
752
753 arizona_stop_mic(info);
754
755 mutex_unlock(&info->lock);
756}
757
Mark Browncd59e792013-04-01 19:21:48 +0100758static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100759{
Mark Browncd59e792013-04-01 19:21:48 +0100760 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900761 struct arizona_extcon_info,
762 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100763 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100764 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100765 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100766
Mark Brown939c5672013-04-01 19:17:34 +0100767 cancel_delayed_work_sync(&info->micd_timeout_work);
768
Mark Brownf2c32a82012-06-24 12:09:45 +0100769 mutex_lock(&info->lock);
770
Charles Keepax31a847e2013-11-14 16:18:23 +0000771 /* If the cable was removed while measuring ignore the result */
Chanwoo Choief70a212014-04-21 20:47:31 +0900772 ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000773 if (ret < 0) {
774 dev_err(arizona->dev, "Failed to check cable state: %d\n",
775 ret);
776 mutex_unlock(&info->lock);
777 return;
778 } else if (!ret) {
779 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
780 mutex_unlock(&info->lock);
781 return;
782 }
783
Charles Keepaxffae24f2013-11-14 16:18:21 +0000784 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100785 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
786 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900787 dev_err(arizona->dev,
788 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100789 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100790 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100791 }
792
793 dev_dbg(arizona->dev, "MICDET: %x\n", val);
794
795 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900796 dev_warn(arizona->dev,
797 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100798 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100799 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100800 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100801 }
802
Charles Keepaxffae24f2013-11-14 16:18:21 +0000803 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100804 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100805 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100806 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100807 }
808
809 /* Due to jack detect this should never happen */
810 if (!(val & ARIZONA_MICD_STS)) {
811 dev_warn(arizona->dev, "Detected open circuit\n");
812 info->detecting = false;
813 goto handled;
814 }
815
816 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000817 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900818 arizona_identify_headphone(info);
819
Chanwoo Choief70a212014-04-21 20:47:31 +0900820 ret = extcon_update_state(info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900821 1 << ARIZONA_CABLE_MICROPHONE,
822 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100823
824 if (ret != 0)
825 dev_err(arizona->dev, "Headset report failed: %d\n",
826 ret);
827
Mark Brownbbbd46e2013-01-10 19:38:43 +0000828 /* Don't need to regulate for button detection */
829 ret = regulator_allow_bypass(info->micvdd, false);
830 if (ret != 0) {
831 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
832 ret);
833 }
834
Mark Brownf2c32a82012-06-24 12:09:45 +0100835 info->mic = true;
836 info->detecting = false;
837 goto handled;
838 }
839
840 /* If we detected a lower impedence during initial startup
841 * then we probably have the wrong polarity, flip it. Don't
842 * do this for the lowest impedences to speed up detection of
843 * plain headphones. If both polarities report a low
844 * impedence then give up and report headphones.
845 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000846 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800847 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900848 dev_dbg(arizona->dev, "Detected HP/line\n");
849 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100850
Mark Brown4f340332013-01-11 08:55:43 +0900851 info->detecting = false;
852
853 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100854 } else {
855 info->micd_mode++;
856 if (info->micd_mode == info->micd_num_modes)
857 info->micd_mode = 0;
858 arizona_extcon_set_mode(info, info->micd_mode);
859
860 info->jack_flips++;
861 }
862
863 goto handled;
864 }
865
866 /*
867 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100868 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100869 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000870 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100871 if (info->mic) {
872 dev_dbg(arizona->dev, "Mic button detected\n");
873
Mark Brown34efe4d2012-07-20 17:07:29 +0100874 lvl = val & ARIZONA_MICD_LVL_MASK;
875 lvl >>= ARIZONA_MICD_LVL_SHIFT;
876
Mark Brown41a57852013-04-01 19:18:18 +0100877 for (i = 0; i < info->num_micd_ranges; i++)
878 input_report_key(info->input,
879 info->micd_ranges[i].key, 0);
880
Mark Brown6fed4d82013-04-01 22:03:06 +0100881 WARN_ON(!lvl);
882 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
883 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
884 key = info->micd_ranges[ffs(lvl) - 1].key;
885 input_report_key(info->input, key, 1);
886 input_sync(info->input);
887 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100888
Mark Brownf2c32a82012-06-24 12:09:45 +0100889 } else if (info->detecting) {
890 dev_dbg(arizona->dev, "Headphone detected\n");
891 info->detecting = false;
892 arizona_stop_mic(info);
893
Mark Brown4f340332013-01-11 08:55:43 +0900894 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100895 } else {
896 dev_warn(arizona->dev, "Button with no mic: %x\n",
897 val);
898 }
899 } else {
900 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100901 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100902 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100903 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100904 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000905 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100906 }
907
908handled:
Mark Brown939c5672013-04-01 19:17:34 +0100909 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100910 queue_delayed_work(system_power_efficient_wq,
911 &info->micd_timeout_work,
912 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100913
Mark Brownf2c32a82012-06-24 12:09:45 +0100914 pm_runtime_mark_last_busy(info->dev);
915 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100916}
917
918static irqreturn_t arizona_micdet(int irq, void *data)
919{
920 struct arizona_extcon_info *info = data;
921 struct arizona *arizona = info->arizona;
922 int debounce = arizona->pdata.micd_detect_debounce;
923
924 cancel_delayed_work_sync(&info->micd_detect_work);
925 cancel_delayed_work_sync(&info->micd_timeout_work);
926
927 mutex_lock(&info->lock);
928 if (!info->detecting)
929 debounce = 0;
930 mutex_unlock(&info->lock);
931
932 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100933 queue_delayed_work(system_power_efficient_wq,
934 &info->micd_detect_work,
935 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100936 else
937 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100938
939 return IRQ_HANDLED;
940}
941
Mark Brown0e27bd32013-02-05 21:00:15 +0000942static void arizona_hpdet_work(struct work_struct *work)
943{
944 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900945 struct arizona_extcon_info,
946 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000947
948 mutex_lock(&info->lock);
949 arizona_start_hpdet_acc_id(info);
950 mutex_unlock(&info->lock);
951}
952
Mark Brownf2c32a82012-06-24 12:09:45 +0100953static irqreturn_t arizona_jackdet(int irq, void *data)
954{
955 struct arizona_extcon_info *info = data;
956 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900957 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100958 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100959 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100960
Mark Brown939c5672013-04-01 19:17:34 +0100961 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
962 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100963
Mark Browna3e20782013-04-01 19:05:27 +0100964 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000965
Mark Brownf2c32a82012-06-24 12:09:45 +0100966 mutex_lock(&info->lock);
967
Mark Brown92a49872013-01-11 08:55:39 +0900968 if (arizona->pdata.jd_gpio5) {
969 mask = ARIZONA_MICD_CLAMP_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100970 if (arizona->pdata.jd_invert)
971 present = ARIZONA_MICD_CLAMP_STS;
972 else
973 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +0900974 } else {
975 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100976 if (arizona->pdata.jd_invert)
977 present = 0;
978 else
979 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +0900980 }
981
Mark Brownf2c32a82012-06-24 12:09:45 +0100982 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
983 if (ret != 0) {
984 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
985 ret);
986 mutex_unlock(&info->lock);
987 pm_runtime_put_autosuspend(info->dev);
988 return IRQ_NONE;
989 }
990
Mark Browna3e20782013-04-01 19:05:27 +0100991 val &= mask;
992 if (val == info->last_jackdet) {
993 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +0100994 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100995 queue_delayed_work(system_power_efficient_wq,
996 &info->hpdet_work,
997 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +0100998
Chanwoo Choic2275d22013-08-23 10:21:37 +0900999 if (cancelled_mic) {
1000 int micd_timeout = info->micd_timeout;
1001
Mark Browndf9a5ab2013-07-18 22:42:22 +01001002 queue_delayed_work(system_power_efficient_wq,
1003 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001004 msecs_to_jiffies(micd_timeout));
1005 }
Mark Brown939c5672013-04-01 19:17:34 +01001006
Mark Browna3e20782013-04-01 19:05:27 +01001007 goto out;
1008 }
1009 info->last_jackdet = val;
1010
1011 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001012 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choief70a212014-04-21 20:47:31 +09001013 ret = extcon_set_cable_state_(info->edev,
Mark Brown325c6422012-06-28 13:08:30 +01001014 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001015
1016 if (ret != 0)
1017 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1018 ret);
1019
Mark Browndd235ee2013-01-11 08:55:51 +09001020 if (!arizona->pdata.hpdet_acc_id) {
1021 info->detecting = true;
1022 info->mic = false;
1023 info->jack_flips = 0;
1024
1025 arizona_start_mic(info);
1026 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001027 queue_delayed_work(system_power_efficient_wq,
1028 &info->hpdet_work,
1029 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001030 }
Mark Brown4e616872013-01-15 22:09:20 +09001031
1032 regmap_update_bits(arizona->regmap,
1033 ARIZONA_JACK_DETECT_DEBOUNCE,
1034 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001035 } else {
1036 dev_dbg(arizona->dev, "Detected jack removal\n");
1037
1038 arizona_stop_mic(info);
1039
Mark Browndd235ee2013-01-11 08:55:51 +09001040 info->num_hpdet_res = 0;
1041 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1042 info->hpdet_res[i] = 0;
1043 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001044 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001045 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001046
Mark Brown6fed4d82013-04-01 22:03:06 +01001047 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001048 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001049 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001050 input_sync(info->input);
1051
Chanwoo Choief70a212014-04-21 20:47:31 +09001052 ret = extcon_update_state(info->edev, 0xffffffff, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001053 if (ret != 0)
1054 dev_err(arizona->dev, "Removal report failed: %d\n",
1055 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001056
1057 regmap_update_bits(arizona->regmap,
1058 ARIZONA_JACK_DETECT_DEBOUNCE,
1059 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1060 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001061 }
1062
Mark Brown7abd4e22013-04-01 19:25:55 +01001063 if (arizona->pdata.micd_timeout)
1064 info->micd_timeout = arizona->pdata.micd_timeout;
1065 else
1066 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1067
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001068out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001069 /* Clear trig_sts to make sure DCVDD is not forced up */
1070 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1071 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1072 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1073 ARIZONA_JD1_FALL_TRIG_STS |
1074 ARIZONA_JD1_RISE_TRIG_STS);
1075
Mark Brownf2c32a82012-06-24 12:09:45 +01001076 mutex_unlock(&info->lock);
1077
1078 pm_runtime_mark_last_busy(info->dev);
1079 pm_runtime_put_autosuspend(info->dev);
1080
1081 return IRQ_HANDLED;
1082}
1083
Mark Brown6fed4d82013-04-01 22:03:06 +01001084/* Map a level onto a slot in the register bank */
1085static void arizona_micd_set_level(struct arizona *arizona, int index,
1086 unsigned int level)
1087{
1088 int reg;
1089 unsigned int mask;
1090
1091 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1092
1093 if (!(index % 2)) {
1094 mask = 0x3f00;
1095 level <<= 8;
1096 } else {
1097 mask = 0x3f;
1098 }
1099
1100 /* Program the level itself */
1101 regmap_update_bits(arizona->regmap, reg, mask, level);
1102}
1103
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001104static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001105{
1106 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001107 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001108 struct arizona_extcon_info *info;
Mark Browne56a0a572013-04-01 19:03:52 +01001109 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001110 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001111 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001112 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001113
Mark Brownbbbd46e2013-01-10 19:38:43 +00001114 if (!arizona->dapm || !arizona->dapm->card)
1115 return -EPROBE_DEFER;
1116
Mark Brownf2c32a82012-06-24 12:09:45 +01001117 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1118 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001119 dev_err(&pdev->dev, "Failed to allocate memory\n");
Sangjung Wood88cc362014-04-21 19:10:15 +09001120 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001121 }
1122
1123 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1124 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";
1171 info->edev->dev.parent = arizona->dev;
Mark Brownf2c32a82012-06-24 12:09:45 +01001172
Chanwoo Choief70a212014-04-21 20:47:31 +09001173 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001174 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001175 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001176 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001177 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001178 }
1179
Mark Brown6fed4d82013-04-01 22:03:06 +01001180 info->input = devm_input_allocate_device(&pdev->dev);
1181 if (!info->input) {
1182 dev_err(arizona->dev, "Can't allocate input dev\n");
1183 ret = -ENOMEM;
1184 goto err_register;
1185 }
1186
1187 info->input->name = "Headset";
1188 info->input->phys = "arizona/extcon";
1189 info->input->dev.parent = &pdev->dev;
1190
Mark Brownf2c32a82012-06-24 12:09:45 +01001191 if (pdata->num_micd_configs) {
1192 info->micd_modes = pdata->micd_configs;
1193 info->micd_num_modes = pdata->num_micd_configs;
1194 } else {
1195 info->micd_modes = micd_default_modes;
1196 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1197 }
1198
1199 if (arizona->pdata.micd_pol_gpio > 0) {
1200 if (info->micd_modes[0].gpio)
1201 mode = GPIOF_OUT_INIT_HIGH;
1202 else
1203 mode = GPIOF_OUT_INIT_LOW;
1204
1205 ret = devm_gpio_request_one(&pdev->dev,
1206 arizona->pdata.micd_pol_gpio,
1207 mode,
1208 "MICD polarity");
1209 if (ret != 0) {
1210 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1211 arizona->pdata.micd_pol_gpio, ret);
1212 goto err_register;
1213 }
1214 }
1215
Mark Brown1eda6aa2013-01-11 08:55:54 +09001216 if (arizona->pdata.hpdet_id_gpio > 0) {
1217 ret = devm_gpio_request_one(&pdev->dev,
1218 arizona->pdata.hpdet_id_gpio,
1219 GPIOF_OUT_INIT_LOW,
1220 "HPDET");
1221 if (ret != 0) {
1222 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1223 arizona->pdata.hpdet_id_gpio, ret);
1224 goto err_register;
1225 }
1226 }
1227
Mark Brownb17e5462013-01-11 08:55:24 +09001228 if (arizona->pdata.micd_bias_start_time)
1229 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1230 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1231 arizona->pdata.micd_bias_start_time
1232 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1233
Mark Brown2e033db2013-01-21 17:36:33 +09001234 if (arizona->pdata.micd_rate)
1235 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1236 ARIZONA_MICD_RATE_MASK,
1237 arizona->pdata.micd_rate
1238 << ARIZONA_MICD_RATE_SHIFT);
1239
1240 if (arizona->pdata.micd_dbtime)
1241 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1242 ARIZONA_MICD_DBTIME_MASK,
1243 arizona->pdata.micd_dbtime
1244 << ARIZONA_MICD_DBTIME_SHIFT);
1245
Mark Brown6fed4d82013-04-01 22:03:06 +01001246 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1247
1248 if (arizona->pdata.num_micd_ranges) {
1249 info->micd_ranges = pdata->micd_ranges;
1250 info->num_micd_ranges = pdata->num_micd_ranges;
1251 } else {
1252 info->micd_ranges = micd_default_ranges;
1253 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1254 }
1255
1256 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1257 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1258 arizona->pdata.num_micd_ranges);
1259 }
1260
1261 if (info->num_micd_ranges > 1) {
1262 for (i = 1; i < info->num_micd_ranges; i++) {
1263 if (info->micd_ranges[i - 1].max >
1264 info->micd_ranges[i].max) {
1265 dev_err(arizona->dev,
1266 "MICD ranges must be sorted\n");
1267 ret = -EINVAL;
1268 goto err_input;
1269 }
1270 }
1271 }
1272
1273 /* Disable all buttons by default */
1274 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1275 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1276
1277 /* Set up all the buttons the user specified */
1278 for (i = 0; i < info->num_micd_ranges; i++) {
1279 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1280 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1281 break;
1282
1283 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1284 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1285 info->micd_ranges[i].max);
1286 ret = -EINVAL;
1287 goto err_input;
1288 }
1289
1290 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1291 arizona_micd_levels[j], i);
1292
1293 arizona_micd_set_level(arizona, i, j);
1294 input_set_capability(info->input, EV_KEY,
1295 info->micd_ranges[i].key);
1296
1297 /* Enable reporting of that range */
1298 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1299 1 << i, 1 << i);
1300 }
1301
1302 /* Set all the remaining keys to a maximum */
1303 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1304 arizona_micd_set_level(arizona, i, 0x3f);
1305
Mark Browndab63eb2013-01-11 08:55:36 +09001306 /*
Mark Brown92a49872013-01-11 08:55:39 +09001307 * If we have a clamp use it, activating in conjunction with
1308 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001309 */
1310 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001311 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a572013-04-01 19:03:52 +01001312 /* Put the GPIO into input mode with optional pull */
1313 val = 0xc101;
1314 if (arizona->pdata.jd_gpio5_nopull)
1315 val &= ~ARIZONA_GPN_PU;
1316
Mark Brown92a49872013-01-11 08:55:39 +09001317 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a572013-04-01 19:03:52 +01001318 val);
Mark Brown92a49872013-01-11 08:55:39 +09001319
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001320 if (arizona->pdata.jd_invert)
1321 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1322 else
1323 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001324 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001325 if (arizona->pdata.jd_invert)
1326 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1327 else
1328 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001329 }
1330
Mark Browndab63eb2013-01-11 08:55:36 +09001331 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001332 ARIZONA_MICD_CLAMP_CONTROL,
1333 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1334
1335 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001336 ARIZONA_JACK_DETECT_DEBOUNCE,
1337 ARIZONA_MICD_CLAMP_DB,
1338 ARIZONA_MICD_CLAMP_DB);
1339 }
1340
Mark Brownf2c32a82012-06-24 12:09:45 +01001341 arizona_extcon_set_mode(info, 0);
1342
1343 pm_runtime_enable(&pdev->dev);
1344 pm_runtime_idle(&pdev->dev);
1345 pm_runtime_get_sync(&pdev->dev);
1346
Mark Brown92a49872013-01-11 08:55:39 +09001347 if (arizona->pdata.jd_gpio5) {
1348 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1349 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1350 } else {
1351 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1352 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1353 }
1354
1355 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001356 "JACKDET rise", arizona_jackdet, info);
1357 if (ret != 0) {
1358 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1359 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001360 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001361 }
1362
Mark Brown92a49872013-01-11 08:55:39 +09001363 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001364 if (ret != 0) {
1365 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1366 ret);
1367 goto err_rise;
1368 }
1369
Mark Brown92a49872013-01-11 08:55:39 +09001370 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001371 "JACKDET fall", arizona_jackdet, info);
1372 if (ret != 0) {
1373 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1374 goto err_rise_wake;
1375 }
1376
Mark Brown92a49872013-01-11 08:55:39 +09001377 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001378 if (ret != 0) {
1379 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1380 ret);
1381 goto err_fall;
1382 }
1383
1384 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1385 "MICDET", arizona_micdet, info);
1386 if (ret != 0) {
1387 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1388 goto err_fall_wake;
1389 }
1390
Mark Brown4f340332013-01-11 08:55:43 +09001391 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1392 "HPDET", arizona_hpdet_irq, info);
1393 if (ret != 0) {
1394 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1395 goto err_micdet;
1396 }
1397
Mark Brownf2c32a82012-06-24 12:09:45 +01001398 arizona_clk32k_enable(arizona);
1399 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1400 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1401 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1402 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1403
Mark Brownb8575a12012-09-07 17:01:15 +08001404 ret = regulator_allow_bypass(info->micvdd, true);
1405 if (ret != 0)
1406 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1407 ret);
1408
Mark Brownf2c32a82012-06-24 12:09:45 +01001409 pm_runtime_put(&pdev->dev);
1410
Mark Brown34efe4d2012-07-20 17:07:29 +01001411 ret = input_register_device(info->input);
1412 if (ret) {
1413 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001414 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001415 }
1416
Mark Brownf2c32a82012-06-24 12:09:45 +01001417 return 0;
1418
Mark Brown4f340332013-01-11 08:55:43 +09001419err_hpdet:
1420 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001421err_micdet:
1422 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001423err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001424 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001425err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001426 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001427err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001428 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001429err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001430 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001431err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001432err_register:
1433 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001434 return ret;
1435}
1436
Bill Pemberton93ed0322012-11-19 13:25:49 -05001437static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001438{
1439 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1440 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001441 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001442
1443 pm_runtime_disable(&pdev->dev);
1444
Mark Browndab63eb2013-01-11 08:55:36 +09001445 regmap_update_bits(arizona->regmap,
1446 ARIZONA_MICD_CLAMP_CONTROL,
1447 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1448
Mark Brown92a49872013-01-11 08:55:39 +09001449 if (arizona->pdata.jd_gpio5) {
1450 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1451 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1452 } else {
1453 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1454 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1455 }
1456
1457 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1458 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1459 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001460 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001461 arizona_free_irq(arizona, jack_irq_rise, info);
1462 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001463 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001464 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1465 ARIZONA_JD1_ENA, 0);
1466 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001467
1468 return 0;
1469}
1470
1471static struct platform_driver arizona_extcon_driver = {
1472 .driver = {
1473 .name = "arizona-extcon",
1474 .owner = THIS_MODULE,
1475 },
1476 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001477 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001478};
1479
1480module_platform_driver(arizona_extcon_driver);
1481
1482MODULE_DESCRIPTION("Arizona Extcon driver");
1483MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1484MODULE_LICENSE("GPL");
1485MODULE_ALIAS("platform:extcon-arizona");