blob: 95cf7f875bb33a8ad73ace290a2524120f1f7a45 [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
Charles Keepax112bdfa2015-02-16 15:41:02 +0000139static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
140 bool clamp)
Mark Brown03409072013-02-12 13:00:31 +0000141{
142 struct arizona *arizona = info->arizona;
Charles Keepax112bdfa2015-02-16 15:41:02 +0000143 unsigned int val = 0;
Mark Brown03409072013-02-12 13:00:31 +0000144 int ret;
145
Charles Keepax112bdfa2015-02-16 15:41:02 +0000146 if (clamp)
147 val = ARIZONA_RMV_SHRT_HP1L;
148
Mark Brown03409072013-02-12 13:00:31 +0000149 mutex_lock(&arizona->dapm->card->dapm_mutex);
150
Charles Keepax112bdfa2015-02-16 15:41:02 +0000151 arizona->hpdet_clamp = clamp;
Mark Browndf8c3db2013-02-22 18:38:03 +0000152
Charles Keepax112bdfa2015-02-16 15:41:02 +0000153 /* Keep the HP output stages disabled while doing the clamp */
154 if (clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000155 ret = regmap_update_bits(arizona->regmap,
156 ARIZONA_OUTPUT_ENABLES_1,
157 ARIZONA_OUT1L_ENA |
158 ARIZONA_OUT1R_ENA, 0);
159 if (ret != 0)
160 dev_warn(arizona->dev,
161 "Failed to disable headphone outputs: %d\n",
162 ret);
Mark Brown03409072013-02-12 13:00:31 +0000163 }
164
Charles Keepax112bdfa2015-02-16 15:41:02 +0000165 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
166 ARIZONA_RMV_SHRT_HP1L, val);
Mark Browndf8c3db2013-02-22 18:38:03 +0000167 if (ret != 0)
Charles Keepax112bdfa2015-02-16 15:41:02 +0000168 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000169 ret);
170
Charles Keepax112bdfa2015-02-16 15:41:02 +0000171 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
172 ARIZONA_RMV_SHRT_HP1R, val);
Mark Browndf8c3db2013-02-22 18:38:03 +0000173 if (ret != 0)
Charles Keepax112bdfa2015-02-16 15:41:02 +0000174 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Browndf8c3db2013-02-22 18:38:03 +0000175 ret);
176
Charles Keepax112bdfa2015-02-16 15:41:02 +0000177 /* Restore the desired state while not doing the clamp */
178 if (!clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000179 ret = regmap_update_bits(arizona->regmap,
180 ARIZONA_OUTPUT_ENABLES_1,
181 ARIZONA_OUT1L_ENA |
182 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000183 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000184 dev_warn(arizona->dev,
185 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000186 ret);
187 }
188
189 mutex_unlock(&arizona->dapm->card->dapm_mutex);
190}
191
Mark Brownf2c32a82012-06-24 12:09:45 +0100192static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
193{
194 struct arizona *arizona = info->arizona;
195
Mark Brown6fed4d82013-04-01 22:03:06 +0100196 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800197
Mark Browncd74f7b2012-11-27 16:14:26 +0900198 if (arizona->pdata.micd_pol_gpio > 0)
199 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
200 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100201 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
202 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100203 info->micd_modes[mode].bias <<
204 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100205 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
206 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
207
208 info->micd_mode = mode;
209
210 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
211}
212
Mark Brownbbbd46e2013-01-10 19:38:43 +0000213static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
214{
Charles Keepax41024242013-09-23 14:33:59 +0100215 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000216 case 1:
217 return "MICBIAS1";
218 case 2:
219 return "MICBIAS2";
220 case 3:
221 return "MICBIAS3";
222 default:
223 return "MICVDD";
224 }
225}
226
227static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
228{
229 struct arizona *arizona = info->arizona;
230 const char *widget = arizona_extcon_get_micbias(info);
231 struct snd_soc_dapm_context *dapm = arizona->dapm;
232 int ret;
233
Mark Brownbbbd46e2013-01-10 19:38:43 +0000234 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
235 if (ret != 0)
236 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
237 widget, ret);
238
Mark Brownbbbd46e2013-01-10 19:38:43 +0000239 snd_soc_dapm_sync(dapm);
240
241 if (!arizona->pdata.micd_force_micbias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000242 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
243 if (ret != 0)
244 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
245 widget, ret);
246
Mark Brownbbbd46e2013-01-10 19:38:43 +0000247 snd_soc_dapm_sync(dapm);
248 }
249}
250
Mark Brown9b1270c2013-01-11 08:55:46 +0900251static void arizona_start_mic(struct arizona_extcon_info *info)
252{
253 struct arizona *arizona = info->arizona;
254 bool change;
255 int ret;
256
Mark Brown9b1270c2013-01-11 08:55:46 +0900257 /* Microphone detection can't use idle mode */
258 pm_runtime_get(info->dev);
259
Mark Brownbbbd46e2013-01-10 19:38:43 +0000260 if (info->detecting) {
261 ret = regulator_allow_bypass(info->micvdd, false);
262 if (ret != 0) {
263 dev_err(arizona->dev,
264 "Failed to regulate MICVDD: %d\n",
265 ret);
266 }
267 }
268
Mark Brown9b1270c2013-01-11 08:55:46 +0900269 ret = regulator_enable(info->micvdd);
270 if (ret != 0) {
271 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
272 ret);
273 }
274
275 if (info->micd_reva) {
276 regmap_write(arizona->regmap, 0x80, 0x3);
277 regmap_write(arizona->regmap, 0x294, 0);
278 regmap_write(arizona->regmap, 0x80, 0x0);
279 }
280
281 regmap_update_bits(arizona->regmap,
282 ARIZONA_ACCESSORY_DETECT_MODE_1,
283 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
284
Mark Brownbbbd46e2013-01-10 19:38:43 +0000285 arizona_extcon_pulse_micbias(info);
286
Mark Brown9b1270c2013-01-11 08:55:46 +0900287 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
288 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
289 &change);
290 if (!change) {
291 regulator_disable(info->micvdd);
292 pm_runtime_put_autosuspend(info->dev);
293 }
294}
295
296static void arizona_stop_mic(struct arizona_extcon_info *info)
297{
298 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000299 const char *widget = arizona_extcon_get_micbias(info);
300 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900301 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000302 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900303
304 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
305 ARIZONA_MICD_ENA, 0,
306 &change);
307
Mark Brownbbbd46e2013-01-10 19:38:43 +0000308 ret = snd_soc_dapm_disable_pin(dapm, widget);
309 if (ret != 0)
310 dev_warn(arizona->dev,
311 "Failed to disable %s: %d\n",
312 widget, ret);
313
Mark Brownbbbd46e2013-01-10 19:38:43 +0000314 snd_soc_dapm_sync(dapm);
315
Mark Brown9b1270c2013-01-11 08:55:46 +0900316 if (info->micd_reva) {
317 regmap_write(arizona->regmap, 0x80, 0x3);
318 regmap_write(arizona->regmap, 0x294, 2);
319 regmap_write(arizona->regmap, 0x80, 0x0);
320 }
321
Mark Brownbbbd46e2013-01-10 19:38:43 +0000322 ret = regulator_allow_bypass(info->micvdd, true);
323 if (ret != 0) {
324 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
325 ret);
326 }
327
Mark Brown9b1270c2013-01-11 08:55:46 +0900328 if (change) {
329 regulator_disable(info->micvdd);
330 pm_runtime_mark_last_busy(info->dev);
331 pm_runtime_put_autosuspend(info->dev);
332 }
333}
334
Mark Brown4f340332013-01-11 08:55:43 +0900335static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100336 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900337 unsigned int factor_a;
338 unsigned int factor_b;
339} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100340 { 100, 5528, 362464 },
341 { 169, 11084, 6186851 },
342 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900343};
344
Charles Keepax24a279b2014-05-30 13:19:17 +0100345#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
346
Mark Brown4f340332013-01-11 08:55:43 +0900347static struct {
348 int min;
349 int max;
350} arizona_hpdet_c_ranges[] = {
351 { 0, 30 },
352 { 8, 100 },
353 { 100, 1000 },
354 { 1000, 10000 },
355};
356
357static int arizona_hpdet_read(struct arizona_extcon_info *info)
358{
359 struct arizona *arizona = info->arizona;
360 unsigned int val, range;
361 int ret;
362
363 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
364 if (ret != 0) {
365 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
366 ret);
367 return ret;
368 }
369
370 switch (info->hpdet_ip) {
371 case 0:
372 if (!(val & ARIZONA_HP_DONE)) {
373 dev_err(arizona->dev, "HPDET did not complete: %x\n",
374 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900375 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900376 }
377
378 val &= ARIZONA_HP_LVL_MASK;
379 break;
380
381 case 1:
382 if (!(val & ARIZONA_HP_DONE_B)) {
383 dev_err(arizona->dev, "HPDET did not complete: %x\n",
384 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900385 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900386 }
387
388 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
389 if (ret != 0) {
390 dev_err(arizona->dev, "Failed to read HP value: %d\n",
391 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900392 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900393 }
394
395 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
396 &range);
397 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
398 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
399
400 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100401 (val < arizona_hpdet_b_ranges[range].threshold ||
402 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900403 range++;
404 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
405 range);
406 regmap_update_bits(arizona->regmap,
407 ARIZONA_HEADPHONE_DETECT_1,
408 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
409 range <<
410 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
411 return -EAGAIN;
412 }
413
414 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100415 if (val < arizona_hpdet_b_ranges[range].threshold ||
416 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900417 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100418 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900419 }
420
421 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
422 val, range);
423
424 val = arizona_hpdet_b_ranges[range].factor_b
425 / ((val * 100) -
426 arizona_hpdet_b_ranges[range].factor_a);
427 break;
428
429 default:
430 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
431 info->hpdet_ip);
432 case 2:
433 if (!(val & ARIZONA_HP_DONE_B)) {
434 dev_err(arizona->dev, "HPDET did not complete: %x\n",
435 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900436 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900437 }
438
439 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000440 /* Convert to ohms, the value is in 0.5 ohm increments */
441 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900442
443 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
444 &range);
445 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
446 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
447
Charles Keepax91414612013-11-14 16:18:24 +0000448 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900449 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
450 (val >= arizona_hpdet_c_ranges[range].max)) {
451 range++;
452 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
453 arizona_hpdet_c_ranges[range].min,
454 arizona_hpdet_c_ranges[range].max);
455 regmap_update_bits(arizona->regmap,
456 ARIZONA_HEADPHONE_DETECT_1,
457 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
458 range <<
459 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
460 return -EAGAIN;
461 }
Charles Keepax91414612013-11-14 16:18:24 +0000462
463 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
464 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
465 arizona_hpdet_c_ranges[range].min);
466 val = arizona_hpdet_c_ranges[range].min;
467 }
Mark Brown4f340332013-01-11 08:55:43 +0900468 }
469
470 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
471 return val;
472}
473
Mark Brown9c2ba272013-02-25 23:42:31 +0000474static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
475 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900476{
477 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900478 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900479
480 /*
481 * If we're using HPDET for accessory identification we need
482 * to take multiple measurements, step through them in sequence.
483 */
484 if (arizona->pdata.hpdet_acc_id) {
485 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900486
487 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000488 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900489 dev_dbg(arizona->dev, "Measuring mic\n");
490
491 regmap_update_bits(arizona->regmap,
492 ARIZONA_ACCESSORY_DETECT_MODE_1,
493 ARIZONA_ACCDET_MODE_MASK |
494 ARIZONA_ACCDET_SRC,
495 ARIZONA_ACCDET_MODE_HPR |
496 info->micd_modes[0].src);
497
498 gpio_set_value_cansleep(id_gpio, 1);
499
Mark Browndd235ee2013-01-11 08:55:51 +0900500 regmap_update_bits(arizona->regmap,
501 ARIZONA_HEADPHONE_DETECT_1,
502 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
503 return -EAGAIN;
504 }
505
506 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000507 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
508 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000509
510 /* Take the headphone impedance for the main report */
511 *reading = info->hpdet_res[0];
512
Mark Brown9dd5e532013-04-01 19:09:45 +0100513 /* Sometimes we get false readings due to slow insert */
514 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
515 dev_dbg(arizona->dev, "Retrying high impedance\n");
516 info->num_hpdet_res = 0;
517 info->hpdet_retried = true;
518 arizona_start_hpdet_acc_id(info);
519 pm_runtime_put(info->dev);
520 return -EAGAIN;
521 }
522
Mark Brown1eda6aa2013-01-11 08:55:54 +0900523 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530524 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900525 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000526 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900527 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000528 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000529 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900530 } else {
531 dev_dbg(arizona->dev, "Detected headphone\n");
532 }
533
534 /* Make sure everything is reset back to the real polarity */
535 regmap_update_bits(arizona->regmap,
536 ARIZONA_ACCESSORY_DETECT_MODE_1,
537 ARIZONA_ACCDET_SRC,
538 info->micd_modes[0].src);
539 }
540
541 return 0;
542}
543
Mark Brown4f340332013-01-11 08:55:43 +0900544static irqreturn_t arizona_hpdet_irq(int irq, void *data)
545{
546 struct arizona_extcon_info *info = data;
547 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900548 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900549 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900550 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000551 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900552
553 mutex_lock(&info->lock);
554
555 /* If we got a spurious IRQ for some reason then ignore it */
556 if (!info->hpdet_active) {
557 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
558 mutex_unlock(&info->lock);
559 return IRQ_NONE;
560 }
561
562 /* If the cable was removed while measuring ignore the result */
Chanwoo Choief70a212014-04-21 20:47:31 +0900563 ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900564 if (ret < 0) {
565 dev_err(arizona->dev, "Failed to check cable state: %d\n",
566 ret);
567 goto out;
568 } else if (!ret) {
569 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
570 goto done;
571 }
572
573 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900574 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900575 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900576 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900577 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900578 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900579
580 /* Reset back to starting range */
581 regmap_update_bits(arizona->regmap,
582 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900583 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
584 0);
585
Mark Brown9c2ba272013-02-25 23:42:31 +0000586 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900587 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900588 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900589 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900590 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900591
592 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900593 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900594 report = ARIZONA_CABLE_LINEOUT;
595 else
596 report = ARIZONA_CABLE_HEADPHONE;
597
Chanwoo Choief70a212014-04-21 20:47:31 +0900598 ret = extcon_set_cable_state_(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900599 if (ret != 0)
600 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
601 ret);
602
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000603done:
604 /* Reset back to starting range */
605 regmap_update_bits(arizona->regmap,
606 ARIZONA_HEADPHONE_DETECT_1,
607 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
608 0);
609
Charles Keepax112bdfa2015-02-16 15:41:02 +0000610 arizona_extcon_hp_clamp(info, false);
Mark Brown4f340332013-01-11 08:55:43 +0900611
Mark Brown1eda6aa2013-01-11 08:55:54 +0900612 if (id_gpio)
613 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900614
615 /* Revert back to MICDET mode */
616 regmap_update_bits(arizona->regmap,
617 ARIZONA_ACCESSORY_DETECT_MODE_1,
618 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
619
620 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000621 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900622 arizona_start_mic(info);
623
624 if (info->hpdet_active) {
625 pm_runtime_put_autosuspend(info->dev);
626 info->hpdet_active = false;
627 }
628
Mark Brownbf14ee52013-02-05 20:20:17 +0000629 info->hpdet_done = true;
630
Mark Brown4f340332013-01-11 08:55:43 +0900631out:
632 mutex_unlock(&info->lock);
633
634 return IRQ_HANDLED;
635}
636
637static void arizona_identify_headphone(struct arizona_extcon_info *info)
638{
639 struct arizona *arizona = info->arizona;
640 int ret;
641
Mark Brownbf14ee52013-02-05 20:20:17 +0000642 if (info->hpdet_done)
643 return;
644
Mark Brown4f340332013-01-11 08:55:43 +0900645 dev_dbg(arizona->dev, "Starting HPDET\n");
646
647 /* Make sure we keep the device enabled during the measurement */
648 pm_runtime_get(info->dev);
649
650 info->hpdet_active = true;
651
652 if (info->mic)
653 arizona_stop_mic(info);
654
Charles Keepax112bdfa2015-02-16 15:41:02 +0000655 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900656
657 ret = regmap_update_bits(arizona->regmap,
658 ARIZONA_ACCESSORY_DETECT_MODE_1,
659 ARIZONA_ACCDET_MODE_MASK,
660 ARIZONA_ACCDET_MODE_HPL);
661 if (ret != 0) {
662 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
663 goto err;
664 }
665
666 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
667 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
668 if (ret != 0) {
669 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
670 ret);
671 goto err;
672 }
673
674 return;
675
676err:
677 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
678 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
679
680 /* Just report headphone */
Nikesh Oswal34602482014-05-29 16:27:52 +0100681 ret = extcon_set_cable_state_(info->edev,
682 ARIZONA_CABLE_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900683 if (ret != 0)
684 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
685
686 if (info->mic)
687 arizona_start_mic(info);
688
689 info->hpdet_active = false;
690}
Mark Browndd235ee2013-01-11 08:55:51 +0900691
692static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
693{
694 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000695 int hp_reading = 32;
696 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900697 int ret;
698
699 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
700
701 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000702 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900703
704 info->hpdet_active = true;
705
Charles Keepax112bdfa2015-02-16 15:41:02 +0000706 arizona_extcon_hp_clamp(info, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900707
708 ret = regmap_update_bits(arizona->regmap,
709 ARIZONA_ACCESSORY_DETECT_MODE_1,
710 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
711 info->micd_modes[0].src |
712 ARIZONA_ACCDET_MODE_HPL);
713 if (ret != 0) {
714 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
715 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900716 }
717
Mark Brown9c2ba272013-02-25 23:42:31 +0000718 if (arizona->pdata.hpdet_acc_id_line) {
719 ret = regmap_update_bits(arizona->regmap,
720 ARIZONA_HEADPHONE_DETECT_1,
721 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
722 if (ret != 0) {
723 dev_err(arizona->dev,
724 "Can't start HPDETL measurement: %d\n",
725 ret);
726 goto err;
727 }
728 } else {
729 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900730 }
731
732 return;
733
734err:
735 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
736 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
737
738 /* Just report headphone */
Nikesh Oswal34602482014-05-29 16:27:52 +0100739 ret = extcon_set_cable_state_(info->edev,
740 ARIZONA_CABLE_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900741 if (ret != 0)
742 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
743
Mark Brown4f340332013-01-11 08:55:43 +0900744 info->hpdet_active = false;
745}
746
Mark Brown939c5672013-04-01 19:17:34 +0100747static void arizona_micd_timeout_work(struct work_struct *work)
748{
749 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900750 struct arizona_extcon_info,
751 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100752
753 mutex_lock(&info->lock);
754
755 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
756 arizona_identify_headphone(info);
757
758 info->detecting = false;
759
760 arizona_stop_mic(info);
761
762 mutex_unlock(&info->lock);
763}
764
Mark Browncd59e792013-04-01 19:21:48 +0100765static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100766{
Mark Browncd59e792013-04-01 19:21:48 +0100767 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900768 struct arizona_extcon_info,
769 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100770 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100771 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100772 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100773
Mark Brown939c5672013-04-01 19:17:34 +0100774 cancel_delayed_work_sync(&info->micd_timeout_work);
775
Mark Brownf2c32a82012-06-24 12:09:45 +0100776 mutex_lock(&info->lock);
777
Charles Keepax31a847e2013-11-14 16:18:23 +0000778 /* If the cable was removed while measuring ignore the result */
Chanwoo Choief70a212014-04-21 20:47:31 +0900779 ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000780 if (ret < 0) {
781 dev_err(arizona->dev, "Failed to check cable state: %d\n",
782 ret);
783 mutex_unlock(&info->lock);
784 return;
785 } else if (!ret) {
786 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
787 mutex_unlock(&info->lock);
788 return;
789 }
790
Charles Keepaxffae24f2013-11-14 16:18:21 +0000791 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100792 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
793 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900794 dev_err(arizona->dev,
795 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100796 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100797 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100798 }
799
800 dev_dbg(arizona->dev, "MICDET: %x\n", val);
801
802 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900803 dev_warn(arizona->dev,
804 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100805 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100806 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100807 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100808 }
809
Charles Keepaxffae24f2013-11-14 16:18:21 +0000810 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100811 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100812 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100813 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100814 }
815
816 /* Due to jack detect this should never happen */
817 if (!(val & ARIZONA_MICD_STS)) {
818 dev_warn(arizona->dev, "Detected open circuit\n");
819 info->detecting = false;
820 goto handled;
821 }
822
823 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000824 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900825 arizona_identify_headphone(info);
826
Nikesh Oswal34602482014-05-29 16:27:52 +0100827 ret = extcon_set_cable_state_(info->edev,
828 ARIZONA_CABLE_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100829
830 if (ret != 0)
831 dev_err(arizona->dev, "Headset report failed: %d\n",
832 ret);
833
Mark Brownbbbd46e2013-01-10 19:38:43 +0000834 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100835 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000836 if (ret != 0) {
837 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
838 ret);
839 }
840
Mark Brownf2c32a82012-06-24 12:09:45 +0100841 info->mic = true;
842 info->detecting = false;
843 goto handled;
844 }
845
846 /* If we detected a lower impedence during initial startup
847 * then we probably have the wrong polarity, flip it. Don't
848 * do this for the lowest impedences to speed up detection of
849 * plain headphones. If both polarities report a low
850 * impedence then give up and report headphones.
851 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000852 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800853 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900854 dev_dbg(arizona->dev, "Detected HP/line\n");
855 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100856
Mark Brown4f340332013-01-11 08:55:43 +0900857 info->detecting = false;
858
859 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100860 } else {
861 info->micd_mode++;
862 if (info->micd_mode == info->micd_num_modes)
863 info->micd_mode = 0;
864 arizona_extcon_set_mode(info, info->micd_mode);
865
866 info->jack_flips++;
867 }
868
869 goto handled;
870 }
871
872 /*
873 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100874 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100875 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000876 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100877 if (info->mic) {
878 dev_dbg(arizona->dev, "Mic button detected\n");
879
Mark Brown34efe4d2012-07-20 17:07:29 +0100880 lvl = val & ARIZONA_MICD_LVL_MASK;
881 lvl >>= ARIZONA_MICD_LVL_SHIFT;
882
Mark Brown41a57852013-04-01 19:18:18 +0100883 for (i = 0; i < info->num_micd_ranges; i++)
884 input_report_key(info->input,
885 info->micd_ranges[i].key, 0);
886
Mark Brown6fed4d82013-04-01 22:03:06 +0100887 WARN_ON(!lvl);
888 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
889 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
890 key = info->micd_ranges[ffs(lvl) - 1].key;
891 input_report_key(info->input, key, 1);
892 input_sync(info->input);
893 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100894
Mark Brownf2c32a82012-06-24 12:09:45 +0100895 } else if (info->detecting) {
896 dev_dbg(arizona->dev, "Headphone detected\n");
897 info->detecting = false;
898 arizona_stop_mic(info);
899
Mark Brown4f340332013-01-11 08:55:43 +0900900 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100901 } else {
902 dev_warn(arizona->dev, "Button with no mic: %x\n",
903 val);
904 }
905 } else {
906 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100907 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100908 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100909 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100910 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000911 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100912 }
913
914handled:
Mark Brown939c5672013-04-01 19:17:34 +0100915 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100916 queue_delayed_work(system_power_efficient_wq,
917 &info->micd_timeout_work,
918 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100919
Mark Brownf2c32a82012-06-24 12:09:45 +0100920 pm_runtime_mark_last_busy(info->dev);
921 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100922}
923
924static irqreturn_t arizona_micdet(int irq, void *data)
925{
926 struct arizona_extcon_info *info = data;
927 struct arizona *arizona = info->arizona;
928 int debounce = arizona->pdata.micd_detect_debounce;
929
930 cancel_delayed_work_sync(&info->micd_detect_work);
931 cancel_delayed_work_sync(&info->micd_timeout_work);
932
933 mutex_lock(&info->lock);
934 if (!info->detecting)
935 debounce = 0;
936 mutex_unlock(&info->lock);
937
938 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100939 queue_delayed_work(system_power_efficient_wq,
940 &info->micd_detect_work,
941 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100942 else
943 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100944
945 return IRQ_HANDLED;
946}
947
Mark Brown0e27bd32013-02-05 21:00:15 +0000948static void arizona_hpdet_work(struct work_struct *work)
949{
950 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900951 struct arizona_extcon_info,
952 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000953
954 mutex_lock(&info->lock);
955 arizona_start_hpdet_acc_id(info);
956 mutex_unlock(&info->lock);
957}
958
Mark Brownf2c32a82012-06-24 12:09:45 +0100959static irqreturn_t arizona_jackdet(int irq, void *data)
960{
961 struct arizona_extcon_info *info = data;
962 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900963 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100964 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100965 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100966
Mark Brown939c5672013-04-01 19:17:34 +0100967 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
968 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100969
Mark Browna3e20782013-04-01 19:05:27 +0100970 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000971
Mark Brownf2c32a82012-06-24 12:09:45 +0100972 mutex_lock(&info->lock);
973
Mark Brown92a49872013-01-11 08:55:39 +0900974 if (arizona->pdata.jd_gpio5) {
975 mask = ARIZONA_MICD_CLAMP_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100976 if (arizona->pdata.jd_invert)
977 present = ARIZONA_MICD_CLAMP_STS;
978 else
979 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +0900980 } else {
981 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100982 if (arizona->pdata.jd_invert)
983 present = 0;
984 else
985 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +0900986 }
987
Mark Brownf2c32a82012-06-24 12:09:45 +0100988 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
989 if (ret != 0) {
990 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
991 ret);
992 mutex_unlock(&info->lock);
993 pm_runtime_put_autosuspend(info->dev);
994 return IRQ_NONE;
995 }
996
Mark Browna3e20782013-04-01 19:05:27 +0100997 val &= mask;
998 if (val == info->last_jackdet) {
999 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001000 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001001 queue_delayed_work(system_power_efficient_wq,
1002 &info->hpdet_work,
1003 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001004
Chanwoo Choic2275d22013-08-23 10:21:37 +09001005 if (cancelled_mic) {
1006 int micd_timeout = info->micd_timeout;
1007
Mark Browndf9a5ab2013-07-18 22:42:22 +01001008 queue_delayed_work(system_power_efficient_wq,
1009 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001010 msecs_to_jiffies(micd_timeout));
1011 }
Mark Brown939c5672013-04-01 19:17:34 +01001012
Mark Browna3e20782013-04-01 19:05:27 +01001013 goto out;
1014 }
1015 info->last_jackdet = val;
1016
1017 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001018 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choief70a212014-04-21 20:47:31 +09001019 ret = extcon_set_cable_state_(info->edev,
Mark Brown325c6422012-06-28 13:08:30 +01001020 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001021
1022 if (ret != 0)
1023 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1024 ret);
1025
Mark Browndd235ee2013-01-11 08:55:51 +09001026 if (!arizona->pdata.hpdet_acc_id) {
1027 info->detecting = true;
1028 info->mic = false;
1029 info->jack_flips = 0;
1030
1031 arizona_start_mic(info);
1032 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001033 queue_delayed_work(system_power_efficient_wq,
1034 &info->hpdet_work,
1035 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001036 }
Mark Brown4e616872013-01-15 22:09:20 +09001037
1038 regmap_update_bits(arizona->regmap,
1039 ARIZONA_JACK_DETECT_DEBOUNCE,
1040 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001041 } else {
1042 dev_dbg(arizona->dev, "Detected jack removal\n");
1043
1044 arizona_stop_mic(info);
1045
Mark Browndd235ee2013-01-11 08:55:51 +09001046 info->num_hpdet_res = 0;
1047 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1048 info->hpdet_res[i] = 0;
1049 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001050 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001051 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001052
Mark Brown6fed4d82013-04-01 22:03:06 +01001053 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001054 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001055 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001056 input_sync(info->input);
1057
Chanwoo Choief70a212014-04-21 20:47:31 +09001058 ret = extcon_update_state(info->edev, 0xffffffff, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001059 if (ret != 0)
1060 dev_err(arizona->dev, "Removal report failed: %d\n",
1061 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001062
1063 regmap_update_bits(arizona->regmap,
1064 ARIZONA_JACK_DETECT_DEBOUNCE,
1065 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1066 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001067 }
1068
Mark Brown7abd4e22013-04-01 19:25:55 +01001069 if (arizona->pdata.micd_timeout)
1070 info->micd_timeout = arizona->pdata.micd_timeout;
1071 else
1072 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1073
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001074out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001075 /* Clear trig_sts to make sure DCVDD is not forced up */
1076 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1077 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1078 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1079 ARIZONA_JD1_FALL_TRIG_STS |
1080 ARIZONA_JD1_RISE_TRIG_STS);
1081
Mark Brownf2c32a82012-06-24 12:09:45 +01001082 mutex_unlock(&info->lock);
1083
1084 pm_runtime_mark_last_busy(info->dev);
1085 pm_runtime_put_autosuspend(info->dev);
1086
1087 return IRQ_HANDLED;
1088}
1089
Mark Brown6fed4d82013-04-01 22:03:06 +01001090/* Map a level onto a slot in the register bank */
1091static void arizona_micd_set_level(struct arizona *arizona, int index,
1092 unsigned int level)
1093{
1094 int reg;
1095 unsigned int mask;
1096
1097 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1098
1099 if (!(index % 2)) {
1100 mask = 0x3f00;
1101 level <<= 8;
1102 } else {
1103 mask = 0x3f;
1104 }
1105
1106 /* Program the level itself */
1107 regmap_update_bits(arizona->regmap, reg, mask, level);
1108}
1109
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001110static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001111{
1112 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001113 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001114 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001115 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001116 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001117 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001118 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001119
Mark Brownbbbd46e2013-01-10 19:38:43 +00001120 if (!arizona->dapm || !arizona->dapm->card)
1121 return -EPROBE_DEFER;
1122
Mark Brownf2c32a82012-06-24 12:09:45 +01001123 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001124 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001125 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001126
Charles Keepax17271f62014-07-18 12:59:00 +01001127 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001128 if (IS_ERR(info->micvdd)) {
1129 ret = PTR_ERR(info->micvdd);
1130 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001131 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001132 }
1133
1134 mutex_init(&info->lock);
1135 info->arizona = arizona;
1136 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001137 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001138 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001139 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001140 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001141 platform_set_drvdata(pdev, info);
1142
1143 switch (arizona->type) {
1144 case WM5102:
1145 switch (arizona->rev) {
1146 case 0:
1147 info->micd_reva = true;
1148 break;
1149 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001150 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001151 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001152 break;
1153 }
1154 break;
Charles Keepax77438612013-11-14 16:18:25 +00001155 case WM5110:
1156 switch (arizona->rev) {
1157 case 0 ... 2:
1158 break;
1159 default:
1160 info->micd_clamp = true;
1161 info->hpdet_ip = 2;
1162 break;
1163 }
1164 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001165 default:
1166 break;
1167 }
1168
Chanwoo Choief70a212014-04-21 20:47:31 +09001169 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1170 if (IS_ERR(info->edev)) {
1171 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1172 return -ENOMEM;
1173 }
1174 info->edev->name = "Headset Jack";
Mark Brownf2c32a82012-06-24 12:09:45 +01001175
Chanwoo Choief70a212014-04-21 20:47:31 +09001176 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001177 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001178 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001179 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001180 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001181 }
1182
Mark Brown6fed4d82013-04-01 22:03:06 +01001183 info->input = devm_input_allocate_device(&pdev->dev);
1184 if (!info->input) {
1185 dev_err(arizona->dev, "Can't allocate input dev\n");
1186 ret = -ENOMEM;
1187 goto err_register;
1188 }
1189
1190 info->input->name = "Headset";
1191 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001192
Mark Brownf2c32a82012-06-24 12:09:45 +01001193 if (pdata->num_micd_configs) {
1194 info->micd_modes = pdata->micd_configs;
1195 info->micd_num_modes = pdata->num_micd_configs;
1196 } else {
1197 info->micd_modes = micd_default_modes;
1198 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1199 }
1200
1201 if (arizona->pdata.micd_pol_gpio > 0) {
1202 if (info->micd_modes[0].gpio)
1203 mode = GPIOF_OUT_INIT_HIGH;
1204 else
1205 mode = GPIOF_OUT_INIT_LOW;
1206
1207 ret = devm_gpio_request_one(&pdev->dev,
1208 arizona->pdata.micd_pol_gpio,
1209 mode,
1210 "MICD polarity");
1211 if (ret != 0) {
1212 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1213 arizona->pdata.micd_pol_gpio, ret);
1214 goto err_register;
1215 }
1216 }
1217
Mark Brown1eda6aa2013-01-11 08:55:54 +09001218 if (arizona->pdata.hpdet_id_gpio > 0) {
1219 ret = devm_gpio_request_one(&pdev->dev,
1220 arizona->pdata.hpdet_id_gpio,
1221 GPIOF_OUT_INIT_LOW,
1222 "HPDET");
1223 if (ret != 0) {
1224 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1225 arizona->pdata.hpdet_id_gpio, ret);
1226 goto err_register;
1227 }
1228 }
1229
Mark Brownb17e5462013-01-11 08:55:24 +09001230 if (arizona->pdata.micd_bias_start_time)
1231 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1232 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1233 arizona->pdata.micd_bias_start_time
1234 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1235
Mark Brown2e033db2013-01-21 17:36:33 +09001236 if (arizona->pdata.micd_rate)
1237 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1238 ARIZONA_MICD_RATE_MASK,
1239 arizona->pdata.micd_rate
1240 << ARIZONA_MICD_RATE_SHIFT);
1241
1242 if (arizona->pdata.micd_dbtime)
1243 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1244 ARIZONA_MICD_DBTIME_MASK,
1245 arizona->pdata.micd_dbtime
1246 << ARIZONA_MICD_DBTIME_SHIFT);
1247
Mark Brown6fed4d82013-04-01 22:03:06 +01001248 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1249
1250 if (arizona->pdata.num_micd_ranges) {
1251 info->micd_ranges = pdata->micd_ranges;
1252 info->num_micd_ranges = pdata->num_micd_ranges;
1253 } else {
1254 info->micd_ranges = micd_default_ranges;
1255 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1256 }
1257
1258 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1259 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1260 arizona->pdata.num_micd_ranges);
1261 }
1262
1263 if (info->num_micd_ranges > 1) {
1264 for (i = 1; i < info->num_micd_ranges; i++) {
1265 if (info->micd_ranges[i - 1].max >
1266 info->micd_ranges[i].max) {
1267 dev_err(arizona->dev,
1268 "MICD ranges must be sorted\n");
1269 ret = -EINVAL;
1270 goto err_input;
1271 }
1272 }
1273 }
1274
1275 /* Disable all buttons by default */
1276 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1277 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1278
1279 /* Set up all the buttons the user specified */
1280 for (i = 0; i < info->num_micd_ranges; i++) {
1281 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1282 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1283 break;
1284
1285 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1286 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1287 info->micd_ranges[i].max);
1288 ret = -EINVAL;
1289 goto err_input;
1290 }
1291
1292 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1293 arizona_micd_levels[j], i);
1294
1295 arizona_micd_set_level(arizona, i, j);
1296 input_set_capability(info->input, EV_KEY,
1297 info->micd_ranges[i].key);
1298
1299 /* Enable reporting of that range */
1300 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1301 1 << i, 1 << i);
1302 }
1303
1304 /* Set all the remaining keys to a maximum */
1305 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1306 arizona_micd_set_level(arizona, i, 0x3f);
1307
Mark Browndab63eb2013-01-11 08:55:36 +09001308 /*
Mark Brown92a49872013-01-11 08:55:39 +09001309 * If we have a clamp use it, activating in conjunction with
1310 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001311 */
1312 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001313 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001314 /* Put the GPIO into input mode with optional pull */
1315 val = 0xc101;
1316 if (arizona->pdata.jd_gpio5_nopull)
1317 val &= ~ARIZONA_GPN_PU;
1318
Mark Brown92a49872013-01-11 08:55:39 +09001319 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001320 val);
Mark Brown92a49872013-01-11 08:55:39 +09001321
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001322 if (arizona->pdata.jd_invert)
1323 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1324 else
1325 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001326 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001327 if (arizona->pdata.jd_invert)
1328 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1329 else
1330 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001331 }
1332
Mark Browndab63eb2013-01-11 08:55:36 +09001333 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001334 ARIZONA_MICD_CLAMP_CONTROL,
1335 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1336
1337 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001338 ARIZONA_JACK_DETECT_DEBOUNCE,
1339 ARIZONA_MICD_CLAMP_DB,
1340 ARIZONA_MICD_CLAMP_DB);
1341 }
1342
Mark Brownf2c32a82012-06-24 12:09:45 +01001343 arizona_extcon_set_mode(info, 0);
1344
1345 pm_runtime_enable(&pdev->dev);
1346 pm_runtime_idle(&pdev->dev);
1347 pm_runtime_get_sync(&pdev->dev);
1348
Mark Brown92a49872013-01-11 08:55:39 +09001349 if (arizona->pdata.jd_gpio5) {
1350 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1351 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1352 } else {
1353 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1354 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1355 }
1356
1357 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001358 "JACKDET rise", arizona_jackdet, info);
1359 if (ret != 0) {
1360 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1361 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001362 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001363 }
1364
Mark Brown92a49872013-01-11 08:55:39 +09001365 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001366 if (ret != 0) {
1367 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1368 ret);
1369 goto err_rise;
1370 }
1371
Mark Brown92a49872013-01-11 08:55:39 +09001372 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001373 "JACKDET fall", arizona_jackdet, info);
1374 if (ret != 0) {
1375 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1376 goto err_rise_wake;
1377 }
1378
Mark Brown92a49872013-01-11 08:55:39 +09001379 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001380 if (ret != 0) {
1381 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1382 ret);
1383 goto err_fall;
1384 }
1385
1386 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1387 "MICDET", arizona_micdet, info);
1388 if (ret != 0) {
1389 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1390 goto err_fall_wake;
1391 }
1392
Mark Brown4f340332013-01-11 08:55:43 +09001393 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1394 "HPDET", arizona_hpdet_irq, info);
1395 if (ret != 0) {
1396 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1397 goto err_micdet;
1398 }
1399
Mark Brownf2c32a82012-06-24 12:09:45 +01001400 arizona_clk32k_enable(arizona);
1401 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1402 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1403 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1404 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1405
Mark Brownb8575a12012-09-07 17:01:15 +08001406 ret = regulator_allow_bypass(info->micvdd, true);
1407 if (ret != 0)
1408 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1409 ret);
1410
Mark Brownf2c32a82012-06-24 12:09:45 +01001411 pm_runtime_put(&pdev->dev);
1412
Mark Brown34efe4d2012-07-20 17:07:29 +01001413 ret = input_register_device(info->input);
1414 if (ret) {
1415 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001416 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001417 }
1418
Mark Brownf2c32a82012-06-24 12:09:45 +01001419 return 0;
1420
Mark Brown4f340332013-01-11 08:55:43 +09001421err_hpdet:
1422 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001423err_micdet:
1424 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001425err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001426 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001427err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001428 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001429err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001430 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001431err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001432 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001433err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001434err_register:
1435 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001436 return ret;
1437}
1438
Bill Pemberton93ed0322012-11-19 13:25:49 -05001439static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001440{
1441 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1442 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001443 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001444
1445 pm_runtime_disable(&pdev->dev);
1446
Mark Browndab63eb2013-01-11 08:55:36 +09001447 regmap_update_bits(arizona->regmap,
1448 ARIZONA_MICD_CLAMP_CONTROL,
1449 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1450
Mark Brown92a49872013-01-11 08:55:39 +09001451 if (arizona->pdata.jd_gpio5) {
1452 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1453 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1454 } else {
1455 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1456 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1457 }
1458
1459 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1460 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1461 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001462 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001463 arizona_free_irq(arizona, jack_irq_rise, info);
1464 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001465 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001466 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1467 ARIZONA_JD1_ENA, 0);
1468 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001469
1470 return 0;
1471}
1472
1473static struct platform_driver arizona_extcon_driver = {
1474 .driver = {
1475 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001476 },
1477 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001478 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001479};
1480
1481module_platform_driver(arizona_extcon_driver);
1482
1483MODULE_DESCRIPTION("Arizona Extcon driver");
1484MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1485MODULE_LICENSE("GPL");
1486MODULE_ALIAS("platform:extcon-arizona");