blob: ad87f263056f1f4995dba394af244e829afa2f84 [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>
Inha Song9e86b2a2015-05-04 13:42:13 +090035#include <dt-bindings/mfd/arizona.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010036
Mark Brown6fed4d82013-04-01 22:03:06 +010037#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010038
Richard Fitzgeralda288d642014-05-23 12:54:57 +010039#define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
40#define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
41#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
42#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
43
Mark Brown9dd5e532013-04-01 19:09:45 +010044#define ARIZONA_HPDET_MAX 10000
45
Mark Brown2643fd62013-04-01 19:07:28 +010046#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010047#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010048
Charles Keepaxffae24f2013-11-14 16:18:21 +000049#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
50 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
51 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
52 ARIZONA_MICD_LVL_7)
53
54#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
55
56#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
57
Mark Brownf2c32a82012-06-24 12:09:45 +010058struct arizona_extcon_info {
59 struct device *dev;
60 struct arizona *arizona;
61 struct mutex lock;
62 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010063 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010064
Mark Browna3e20782013-04-01 19:05:27 +010065 u16 last_jackdet;
66
Mark Brownf2c32a82012-06-24 12:09:45 +010067 int micd_mode;
68 const struct arizona_micd_config *micd_modes;
69 int micd_num_modes;
70
Mark Brown6fed4d82013-04-01 22:03:06 +010071 const struct arizona_micd_range *micd_ranges;
72 int num_micd_ranges;
73
Mark Brown7abd4e22013-04-01 19:25:55 +010074 int micd_timeout;
75
Mark Brownf2c32a82012-06-24 12:09:45 +010076 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090077 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010078
Mark Brown0e27bd32013-02-05 21:00:15 +000079 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010080 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010081 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000082
Mark Brown4f340332013-01-11 08:55:43 +090083 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000084 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010085 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090086
Mark Browndd235ee2013-01-11 08:55:51 +090087 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090088 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090089
Mark Brownf2c32a82012-06-24 12:09:45 +010090 bool mic;
91 bool detecting;
92 int jack_flips;
93
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +010094 int hpdet_ip_version;
Mark Brown4f340332013-01-11 08:55:43 +090095
Chanwoo Choief70a212014-04-21 20:47:31 +090096 struct extcon_dev *edev;
Mark Brownf2c32a82012-06-24 12:09:45 +010097};
98
99static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +0100100 { ARIZONA_ACCDET_SRC, 1, 0 },
101 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100102};
103
Mark Brown6fed4d82013-04-01 22:03:06 +0100104static const struct arizona_micd_range micd_default_ranges[] = {
105 { .max = 11, .key = BTN_0 },
106 { .max = 28, .key = BTN_1 },
107 { .max = 54, .key = BTN_2 },
108 { .max = 100, .key = BTN_3 },
109 { .max = 186, .key = BTN_4 },
110 { .max = 430, .key = BTN_5 },
111};
112
113static const int arizona_micd_levels[] = {
114 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
115 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
116 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
117 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
118 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100119};
120
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900121static const unsigned int arizona_cable[] = {
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900122 EXTCON_MECHANICAL,
123 EXTCON_MICROPHONE,
124 EXTCON_HEADPHONE,
125 EXTCON_LINE_OUT,
126 EXTCON_NONE,
Mark Brownf2c32a82012-06-24 12:09:45 +0100127};
128
Mark Brown9dd5e532013-04-01 19:09:45 +0100129static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
130
Charles Keepax112bdfa2015-02-16 15:41:02 +0000131static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
132 bool clamp)
Mark Brown03409072013-02-12 13:00:31 +0000133{
134 struct arizona *arizona = info->arizona;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000135 unsigned int mask = 0, val = 0;
Mark Brown03409072013-02-12 13:00:31 +0000136 int ret;
137
Charles Keepax43f0acd2015-02-16 15:41:03 +0000138 switch (arizona->type) {
139 case WM5110:
Charles Keepax2b51f9c2015-04-30 23:43:37 +0900140 case WM8280:
Charles Keepax43f0acd2015-02-16 15:41:03 +0000141 mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
142 ARIZONA_HP1L_SHRTI;
143 if (clamp)
144 val = ARIZONA_HP1L_SHRTO;
145 else
146 val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
147 break;
148 default:
149 mask = ARIZONA_RMV_SHRT_HP1L;
150 if (clamp)
151 val = ARIZONA_RMV_SHRT_HP1L;
152 break;
153 };
Charles Keepax112bdfa2015-02-16 15:41:02 +0000154
Mark Brown03409072013-02-12 13:00:31 +0000155 mutex_lock(&arizona->dapm->card->dapm_mutex);
156
Charles Keepax112bdfa2015-02-16 15:41:02 +0000157 arizona->hpdet_clamp = clamp;
Mark Browndf8c3db2013-02-22 18:38:03 +0000158
Charles Keepax112bdfa2015-02-16 15:41:02 +0000159 /* Keep the HP output stages disabled while doing the clamp */
160 if (clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000161 ret = regmap_update_bits(arizona->regmap,
162 ARIZONA_OUTPUT_ENABLES_1,
163 ARIZONA_OUT1L_ENA |
164 ARIZONA_OUT1R_ENA, 0);
165 if (ret != 0)
166 dev_warn(arizona->dev,
167 "Failed to disable headphone outputs: %d\n",
168 ret);
Mark Brown03409072013-02-12 13:00:31 +0000169 }
170
Charles Keepax112bdfa2015-02-16 15:41:02 +0000171 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
Charles Keepax43f0acd2015-02-16 15:41:03 +0000172 mask, 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 Brown03409072013-02-12 13:00:31 +0000175 ret);
176
Charles Keepax112bdfa2015-02-16 15:41:02 +0000177 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
Charles Keepax43f0acd2015-02-16 15:41:03 +0000178 mask, val);
Mark Browndf8c3db2013-02-22 18:38:03 +0000179 if (ret != 0)
Charles Keepax112bdfa2015-02-16 15:41:02 +0000180 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Browndf8c3db2013-02-22 18:38:03 +0000181 ret);
182
Charles Keepax112bdfa2015-02-16 15:41:02 +0000183 /* Restore the desired state while not doing the clamp */
184 if (!clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000185 ret = regmap_update_bits(arizona->regmap,
186 ARIZONA_OUTPUT_ENABLES_1,
187 ARIZONA_OUT1L_ENA |
188 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000189 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000190 dev_warn(arizona->dev,
191 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000192 ret);
193 }
194
195 mutex_unlock(&arizona->dapm->card->dapm_mutex);
196}
197
Mark Brownf2c32a82012-06-24 12:09:45 +0100198static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
199{
200 struct arizona *arizona = info->arizona;
201
Mark Brown6fed4d82013-04-01 22:03:06 +0100202 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800203
Mark Browncd74f7b2012-11-27 16:14:26 +0900204 if (arizona->pdata.micd_pol_gpio > 0)
205 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
206 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100207 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
208 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100209 info->micd_modes[mode].bias <<
210 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100211 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
212 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
213
214 info->micd_mode = mode;
215
216 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
217}
218
Mark Brownbbbd46e2013-01-10 19:38:43 +0000219static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
220{
Charles Keepax41024242013-09-23 14:33:59 +0100221 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000222 case 1:
223 return "MICBIAS1";
224 case 2:
225 return "MICBIAS2";
226 case 3:
227 return "MICBIAS3";
228 default:
229 return "MICVDD";
230 }
231}
232
233static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
234{
235 struct arizona *arizona = info->arizona;
236 const char *widget = arizona_extcon_get_micbias(info);
237 struct snd_soc_dapm_context *dapm = arizona->dapm;
238 int ret;
239
Mark Brownbbbd46e2013-01-10 19:38:43 +0000240 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
241 if (ret != 0)
242 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
243 widget, ret);
244
Mark Brownbbbd46e2013-01-10 19:38:43 +0000245 snd_soc_dapm_sync(dapm);
246
247 if (!arizona->pdata.micd_force_micbias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000248 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
249 if (ret != 0)
250 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
251 widget, ret);
252
Mark Brownbbbd46e2013-01-10 19:38:43 +0000253 snd_soc_dapm_sync(dapm);
254 }
255}
256
Mark Brown9b1270c2013-01-11 08:55:46 +0900257static void arizona_start_mic(struct arizona_extcon_info *info)
258{
259 struct arizona *arizona = info->arizona;
260 bool change;
261 int ret;
262
Mark Brown9b1270c2013-01-11 08:55:46 +0900263 /* Microphone detection can't use idle mode */
264 pm_runtime_get(info->dev);
265
Mark Brownbbbd46e2013-01-10 19:38:43 +0000266 if (info->detecting) {
267 ret = regulator_allow_bypass(info->micvdd, false);
268 if (ret != 0) {
269 dev_err(arizona->dev,
270 "Failed to regulate MICVDD: %d\n",
271 ret);
272 }
273 }
274
Mark Brown9b1270c2013-01-11 08:55:46 +0900275 ret = regulator_enable(info->micvdd);
276 if (ret != 0) {
277 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
278 ret);
279 }
280
281 if (info->micd_reva) {
282 regmap_write(arizona->regmap, 0x80, 0x3);
283 regmap_write(arizona->regmap, 0x294, 0);
284 regmap_write(arizona->regmap, 0x80, 0x0);
285 }
286
287 regmap_update_bits(arizona->regmap,
288 ARIZONA_ACCESSORY_DETECT_MODE_1,
289 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
290
Mark Brownbbbd46e2013-01-10 19:38:43 +0000291 arizona_extcon_pulse_micbias(info);
292
Mark Brown9b1270c2013-01-11 08:55:46 +0900293 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
294 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
295 &change);
296 if (!change) {
297 regulator_disable(info->micvdd);
298 pm_runtime_put_autosuspend(info->dev);
299 }
300}
301
302static void arizona_stop_mic(struct arizona_extcon_info *info)
303{
304 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000305 const char *widget = arizona_extcon_get_micbias(info);
306 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900307 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000308 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900309
310 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
311 ARIZONA_MICD_ENA, 0,
312 &change);
313
Mark Brownbbbd46e2013-01-10 19:38:43 +0000314 ret = snd_soc_dapm_disable_pin(dapm, widget);
315 if (ret != 0)
316 dev_warn(arizona->dev,
317 "Failed to disable %s: %d\n",
318 widget, ret);
319
Mark Brownbbbd46e2013-01-10 19:38:43 +0000320 snd_soc_dapm_sync(dapm);
321
Mark Brown9b1270c2013-01-11 08:55:46 +0900322 if (info->micd_reva) {
323 regmap_write(arizona->regmap, 0x80, 0x3);
324 regmap_write(arizona->regmap, 0x294, 2);
325 regmap_write(arizona->regmap, 0x80, 0x0);
326 }
327
Mark Brownbbbd46e2013-01-10 19:38:43 +0000328 ret = regulator_allow_bypass(info->micvdd, true);
329 if (ret != 0) {
330 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
331 ret);
332 }
333
Mark Brown9b1270c2013-01-11 08:55:46 +0900334 if (change) {
335 regulator_disable(info->micvdd);
336 pm_runtime_mark_last_busy(info->dev);
337 pm_runtime_put_autosuspend(info->dev);
338 }
339}
340
Mark Brown4f340332013-01-11 08:55:43 +0900341static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100342 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900343 unsigned int factor_a;
344 unsigned int factor_b;
345} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100346 { 100, 5528, 362464 },
347 { 169, 11084, 6186851 },
348 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900349};
350
Charles Keepax24a279b2014-05-30 13:19:17 +0100351#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
352
Mark Brown4f340332013-01-11 08:55:43 +0900353static struct {
354 int min;
355 int max;
356} arizona_hpdet_c_ranges[] = {
357 { 0, 30 },
358 { 8, 100 },
359 { 100, 1000 },
360 { 1000, 10000 },
361};
362
363static int arizona_hpdet_read(struct arizona_extcon_info *info)
364{
365 struct arizona *arizona = info->arizona;
366 unsigned int val, range;
367 int ret;
368
369 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
370 if (ret != 0) {
371 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
372 ret);
373 return ret;
374 }
375
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100376 switch (info->hpdet_ip_version) {
Mark Brown4f340332013-01-11 08:55:43 +0900377 case 0:
378 if (!(val & ARIZONA_HP_DONE)) {
379 dev_err(arizona->dev, "HPDET did not complete: %x\n",
380 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900381 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900382 }
383
384 val &= ARIZONA_HP_LVL_MASK;
385 break;
386
387 case 1:
388 if (!(val & ARIZONA_HP_DONE_B)) {
389 dev_err(arizona->dev, "HPDET did not complete: %x\n",
390 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900391 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900392 }
393
394 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
395 if (ret != 0) {
396 dev_err(arizona->dev, "Failed to read HP value: %d\n",
397 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900398 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900399 }
400
401 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
402 &range);
403 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
404 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
405
406 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100407 (val < arizona_hpdet_b_ranges[range].threshold ||
408 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900409 range++;
410 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
411 range);
412 regmap_update_bits(arizona->regmap,
413 ARIZONA_HEADPHONE_DETECT_1,
414 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
415 range <<
416 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
417 return -EAGAIN;
418 }
419
420 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100421 if (val < arizona_hpdet_b_ranges[range].threshold ||
422 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900423 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100424 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900425 }
426
427 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
428 val, range);
429
430 val = arizona_hpdet_b_ranges[range].factor_b
431 / ((val * 100) -
432 arizona_hpdet_b_ranges[range].factor_a);
433 break;
434
435 default:
436 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100437 info->hpdet_ip_version);
Mark Brown4f340332013-01-11 08:55:43 +0900438 case 2:
439 if (!(val & ARIZONA_HP_DONE_B)) {
440 dev_err(arizona->dev, "HPDET did not complete: %x\n",
441 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900442 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900443 }
444
445 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000446 /* Convert to ohms, the value is in 0.5 ohm increments */
447 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900448
449 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
450 &range);
451 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
452 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
453
Charles Keepax91414612013-11-14 16:18:24 +0000454 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900455 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
456 (val >= arizona_hpdet_c_ranges[range].max)) {
457 range++;
458 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
459 arizona_hpdet_c_ranges[range].min,
460 arizona_hpdet_c_ranges[range].max);
461 regmap_update_bits(arizona->regmap,
462 ARIZONA_HEADPHONE_DETECT_1,
463 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
464 range <<
465 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
466 return -EAGAIN;
467 }
Charles Keepax91414612013-11-14 16:18:24 +0000468
469 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
470 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
471 arizona_hpdet_c_ranges[range].min);
472 val = arizona_hpdet_c_ranges[range].min;
473 }
Mark Brown4f340332013-01-11 08:55:43 +0900474 }
475
476 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
477 return val;
478}
479
Mark Brown9c2ba272013-02-25 23:42:31 +0000480static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
481 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900482{
483 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900484 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900485
486 /*
487 * If we're using HPDET for accessory identification we need
488 * to take multiple measurements, step through them in sequence.
489 */
490 if (arizona->pdata.hpdet_acc_id) {
491 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900492
493 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000494 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900495 dev_dbg(arizona->dev, "Measuring mic\n");
496
497 regmap_update_bits(arizona->regmap,
498 ARIZONA_ACCESSORY_DETECT_MODE_1,
499 ARIZONA_ACCDET_MODE_MASK |
500 ARIZONA_ACCDET_SRC,
501 ARIZONA_ACCDET_MODE_HPR |
502 info->micd_modes[0].src);
503
504 gpio_set_value_cansleep(id_gpio, 1);
505
Mark Browndd235ee2013-01-11 08:55:51 +0900506 regmap_update_bits(arizona->regmap,
507 ARIZONA_HEADPHONE_DETECT_1,
508 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
509 return -EAGAIN;
510 }
511
512 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000513 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
514 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000515
516 /* Take the headphone impedance for the main report */
517 *reading = info->hpdet_res[0];
518
Mark Brown9dd5e532013-04-01 19:09:45 +0100519 /* Sometimes we get false readings due to slow insert */
520 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
521 dev_dbg(arizona->dev, "Retrying high impedance\n");
522 info->num_hpdet_res = 0;
523 info->hpdet_retried = true;
524 arizona_start_hpdet_acc_id(info);
525 pm_runtime_put(info->dev);
526 return -EAGAIN;
527 }
528
Mark Brown1eda6aa2013-01-11 08:55:54 +0900529 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530530 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900531 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000532 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900533 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000534 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000535 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900536 } else {
537 dev_dbg(arizona->dev, "Detected headphone\n");
538 }
539
540 /* Make sure everything is reset back to the real polarity */
541 regmap_update_bits(arizona->regmap,
542 ARIZONA_ACCESSORY_DETECT_MODE_1,
543 ARIZONA_ACCDET_SRC,
544 info->micd_modes[0].src);
545 }
546
547 return 0;
548}
549
Mark Brown4f340332013-01-11 08:55:43 +0900550static irqreturn_t arizona_hpdet_irq(int irq, void *data)
551{
552 struct arizona_extcon_info *info = data;
553 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900554 int id_gpio = arizona->pdata.hpdet_id_gpio;
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900555 unsigned int report = EXTCON_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900556 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000557 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900558
559 mutex_lock(&info->lock);
560
561 /* If we got a spurious IRQ for some reason then ignore it */
562 if (!info->hpdet_active) {
563 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
564 mutex_unlock(&info->lock);
565 return IRQ_NONE;
566 }
567
568 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900569 ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900570 if (ret < 0) {
571 dev_err(arizona->dev, "Failed to check cable state: %d\n",
572 ret);
573 goto out;
574 } else if (!ret) {
575 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
576 goto done;
577 }
578
579 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900580 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900581 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900582 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900583 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900584 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900585
586 /* Reset back to starting range */
587 regmap_update_bits(arizona->regmap,
588 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900589 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
590 0);
591
Mark Brown9c2ba272013-02-25 23:42:31 +0000592 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900593 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900594 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900595 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900596 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900597
598 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900599 if (reading >= 5000)
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900600 report = EXTCON_LINE_OUT;
Mark Brown4f340332013-01-11 08:55:43 +0900601 else
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900602 report = EXTCON_HEADPHONE;
Mark Brown4f340332013-01-11 08:55:43 +0900603
Chanwoo Choief70a212014-04-21 20:47:31 +0900604 ret = extcon_set_cable_state_(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900605 if (ret != 0)
606 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
607 ret);
608
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000609done:
610 /* Reset back to starting range */
611 regmap_update_bits(arizona->regmap,
612 ARIZONA_HEADPHONE_DETECT_1,
613 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
614 0);
615
Charles Keepax112bdfa2015-02-16 15:41:02 +0000616 arizona_extcon_hp_clamp(info, false);
Mark Brown4f340332013-01-11 08:55:43 +0900617
Mark Brown1eda6aa2013-01-11 08:55:54 +0900618 if (id_gpio)
619 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900620
621 /* Revert back to MICDET mode */
622 regmap_update_bits(arizona->regmap,
623 ARIZONA_ACCESSORY_DETECT_MODE_1,
624 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
625
626 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000627 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900628 arizona_start_mic(info);
629
630 if (info->hpdet_active) {
631 pm_runtime_put_autosuspend(info->dev);
632 info->hpdet_active = false;
633 }
634
Mark Brownbf14ee52013-02-05 20:20:17 +0000635 info->hpdet_done = true;
636
Mark Brown4f340332013-01-11 08:55:43 +0900637out:
638 mutex_unlock(&info->lock);
639
640 return IRQ_HANDLED;
641}
642
643static void arizona_identify_headphone(struct arizona_extcon_info *info)
644{
645 struct arizona *arizona = info->arizona;
646 int ret;
647
Mark Brownbf14ee52013-02-05 20:20:17 +0000648 if (info->hpdet_done)
649 return;
650
Mark Brown4f340332013-01-11 08:55:43 +0900651 dev_dbg(arizona->dev, "Starting HPDET\n");
652
653 /* Make sure we keep the device enabled during the measurement */
654 pm_runtime_get(info->dev);
655
656 info->hpdet_active = true;
657
658 if (info->mic)
659 arizona_stop_mic(info);
660
Charles Keepax112bdfa2015-02-16 15:41:02 +0000661 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900662
663 ret = regmap_update_bits(arizona->regmap,
664 ARIZONA_ACCESSORY_DETECT_MODE_1,
665 ARIZONA_ACCDET_MODE_MASK,
Inha Song9e86b2a2015-05-04 13:42:13 +0900666 arizona->pdata.hpdet_channel);
Mark Brown4f340332013-01-11 08:55:43 +0900667 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900668 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +0900669 goto err;
670 }
671
672 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
673 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
674 if (ret != 0) {
675 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
676 ret);
677 goto err;
678 }
679
680 return;
681
682err:
683 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
684 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
685
686 /* Just report headphone */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900687 ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900688 if (ret != 0)
689 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
690
691 if (info->mic)
692 arizona_start_mic(info);
693
694 info->hpdet_active = false;
695}
Mark Browndd235ee2013-01-11 08:55:51 +0900696
697static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
698{
699 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000700 int hp_reading = 32;
701 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900702 int ret;
703
704 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
705
706 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000707 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900708
709 info->hpdet_active = true;
710
Charles Keepax112bdfa2015-02-16 15:41:02 +0000711 arizona_extcon_hp_clamp(info, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900712
713 ret = regmap_update_bits(arizona->regmap,
714 ARIZONA_ACCESSORY_DETECT_MODE_1,
715 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
716 info->micd_modes[0].src |
Inha Song9e86b2a2015-05-04 13:42:13 +0900717 arizona->pdata.hpdet_channel);
Mark Browndd235ee2013-01-11 08:55:51 +0900718 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900719 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Browndd235ee2013-01-11 08:55:51 +0900720 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900721 }
722
Mark Brown9c2ba272013-02-25 23:42:31 +0000723 if (arizona->pdata.hpdet_acc_id_line) {
724 ret = regmap_update_bits(arizona->regmap,
725 ARIZONA_HEADPHONE_DETECT_1,
726 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
727 if (ret != 0) {
728 dev_err(arizona->dev,
729 "Can't start HPDETL measurement: %d\n",
730 ret);
731 goto err;
732 }
733 } else {
734 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900735 }
736
737 return;
738
739err:
740 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
741 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
742
743 /* Just report headphone */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900744 ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900745 if (ret != 0)
746 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
747
Mark Brown4f340332013-01-11 08:55:43 +0900748 info->hpdet_active = false;
749}
750
Mark Brown939c5672013-04-01 19:17:34 +0100751static void arizona_micd_timeout_work(struct work_struct *work)
752{
753 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900754 struct arizona_extcon_info,
755 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100756
757 mutex_lock(&info->lock);
758
759 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
760 arizona_identify_headphone(info);
761
762 info->detecting = false;
763
764 arizona_stop_mic(info);
765
766 mutex_unlock(&info->lock);
767}
768
Mark Browncd59e792013-04-01 19:21:48 +0100769static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100770{
Mark Browncd59e792013-04-01 19:21:48 +0100771 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900772 struct arizona_extcon_info,
773 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100774 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100775 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100776 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100777
Mark Brown939c5672013-04-01 19:17:34 +0100778 cancel_delayed_work_sync(&info->micd_timeout_work);
779
Mark Brownf2c32a82012-06-24 12:09:45 +0100780 mutex_lock(&info->lock);
781
Charles Keepax31a847e2013-11-14 16:18:23 +0000782 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900783 ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000784 if (ret < 0) {
785 dev_err(arizona->dev, "Failed to check cable state: %d\n",
786 ret);
787 mutex_unlock(&info->lock);
788 return;
789 } else if (!ret) {
790 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
791 mutex_unlock(&info->lock);
792 return;
793 }
794
Charles Keepaxffae24f2013-11-14 16:18:21 +0000795 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100796 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
797 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900798 dev_err(arizona->dev,
799 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100800 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100801 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100802 }
803
804 dev_dbg(arizona->dev, "MICDET: %x\n", val);
805
806 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900807 dev_warn(arizona->dev,
808 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100809 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100810 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100811 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100812 }
813
Charles Keepaxffae24f2013-11-14 16:18:21 +0000814 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100815 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100816 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100817 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100818 }
819
820 /* Due to jack detect this should never happen */
821 if (!(val & ARIZONA_MICD_STS)) {
822 dev_warn(arizona->dev, "Detected open circuit\n");
823 info->detecting = false;
824 goto handled;
825 }
826
827 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000828 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900829 arizona_identify_headphone(info);
830
Nikesh Oswal34602482014-05-29 16:27:52 +0100831 ret = extcon_set_cable_state_(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900832 EXTCON_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100833 if (ret != 0)
834 dev_err(arizona->dev, "Headset report failed: %d\n",
835 ret);
836
Mark Brownbbbd46e2013-01-10 19:38:43 +0000837 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100838 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000839 if (ret != 0) {
840 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
841 ret);
842 }
843
Mark Brownf2c32a82012-06-24 12:09:45 +0100844 info->mic = true;
845 info->detecting = false;
846 goto handled;
847 }
848
849 /* If we detected a lower impedence during initial startup
850 * then we probably have the wrong polarity, flip it. Don't
851 * do this for the lowest impedences to speed up detection of
852 * plain headphones. If both polarities report a low
853 * impedence then give up and report headphones.
854 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000855 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800856 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900857 dev_dbg(arizona->dev, "Detected HP/line\n");
858 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100859
Mark Brown4f340332013-01-11 08:55:43 +0900860 info->detecting = false;
861
862 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100863 } else {
864 info->micd_mode++;
865 if (info->micd_mode == info->micd_num_modes)
866 info->micd_mode = 0;
867 arizona_extcon_set_mode(info, info->micd_mode);
868
869 info->jack_flips++;
870 }
871
872 goto handled;
873 }
874
875 /*
876 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100877 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100878 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000879 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100880 if (info->mic) {
881 dev_dbg(arizona->dev, "Mic button detected\n");
882
Mark Brown34efe4d2012-07-20 17:07:29 +0100883 lvl = val & ARIZONA_MICD_LVL_MASK;
884 lvl >>= ARIZONA_MICD_LVL_SHIFT;
885
Mark Brown41a57852013-04-01 19:18:18 +0100886 for (i = 0; i < info->num_micd_ranges; i++)
887 input_report_key(info->input,
888 info->micd_ranges[i].key, 0);
889
Mark Brown6fed4d82013-04-01 22:03:06 +0100890 WARN_ON(!lvl);
891 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
892 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
893 key = info->micd_ranges[ffs(lvl) - 1].key;
894 input_report_key(info->input, key, 1);
895 input_sync(info->input);
896 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100897
Mark Brownf2c32a82012-06-24 12:09:45 +0100898 } else if (info->detecting) {
899 dev_dbg(arizona->dev, "Headphone detected\n");
900 info->detecting = false;
901 arizona_stop_mic(info);
902
Mark Brown4f340332013-01-11 08:55:43 +0900903 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100904 } else {
905 dev_warn(arizona->dev, "Button with no mic: %x\n",
906 val);
907 }
908 } else {
909 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100910 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100911 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100912 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100913 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000914 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100915 }
916
917handled:
Mark Brown939c5672013-04-01 19:17:34 +0100918 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100919 queue_delayed_work(system_power_efficient_wq,
920 &info->micd_timeout_work,
921 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100922
Mark Brownf2c32a82012-06-24 12:09:45 +0100923 pm_runtime_mark_last_busy(info->dev);
924 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100925}
926
927static irqreturn_t arizona_micdet(int irq, void *data)
928{
929 struct arizona_extcon_info *info = data;
930 struct arizona *arizona = info->arizona;
931 int debounce = arizona->pdata.micd_detect_debounce;
932
933 cancel_delayed_work_sync(&info->micd_detect_work);
934 cancel_delayed_work_sync(&info->micd_timeout_work);
935
936 mutex_lock(&info->lock);
937 if (!info->detecting)
938 debounce = 0;
939 mutex_unlock(&info->lock);
940
941 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100942 queue_delayed_work(system_power_efficient_wq,
943 &info->micd_detect_work,
944 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100945 else
946 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100947
948 return IRQ_HANDLED;
949}
950
Mark Brown0e27bd32013-02-05 21:00:15 +0000951static void arizona_hpdet_work(struct work_struct *work)
952{
953 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900954 struct arizona_extcon_info,
955 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000956
957 mutex_lock(&info->lock);
958 arizona_start_hpdet_acc_id(info);
959 mutex_unlock(&info->lock);
960}
961
Mark Brownf2c32a82012-06-24 12:09:45 +0100962static irqreturn_t arizona_jackdet(int irq, void *data)
963{
964 struct arizona_extcon_info *info = data;
965 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900966 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100967 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100968 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100969
Mark Brown939c5672013-04-01 19:17:34 +0100970 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
971 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100972
Mark Browna3e20782013-04-01 19:05:27 +0100973 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000974
Mark Brownf2c32a82012-06-24 12:09:45 +0100975 mutex_lock(&info->lock);
976
Mark Brown92a49872013-01-11 08:55:39 +0900977 if (arizona->pdata.jd_gpio5) {
978 mask = ARIZONA_MICD_CLAMP_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100979 if (arizona->pdata.jd_invert)
980 present = ARIZONA_MICD_CLAMP_STS;
981 else
982 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +0900983 } else {
984 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100985 if (arizona->pdata.jd_invert)
986 present = 0;
987 else
988 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +0900989 }
990
Mark Brownf2c32a82012-06-24 12:09:45 +0100991 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
992 if (ret != 0) {
993 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
994 ret);
995 mutex_unlock(&info->lock);
996 pm_runtime_put_autosuspend(info->dev);
997 return IRQ_NONE;
998 }
999
Mark Browna3e20782013-04-01 19:05:27 +01001000 val &= mask;
1001 if (val == info->last_jackdet) {
1002 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001003 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001004 queue_delayed_work(system_power_efficient_wq,
1005 &info->hpdet_work,
1006 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001007
Chanwoo Choic2275d22013-08-23 10:21:37 +09001008 if (cancelled_mic) {
1009 int micd_timeout = info->micd_timeout;
1010
Mark Browndf9a5ab2013-07-18 22:42:22 +01001011 queue_delayed_work(system_power_efficient_wq,
1012 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001013 msecs_to_jiffies(micd_timeout));
1014 }
Mark Brown939c5672013-04-01 19:17:34 +01001015
Mark Browna3e20782013-04-01 19:05:27 +01001016 goto out;
1017 }
1018 info->last_jackdet = val;
1019
1020 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001021 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choief70a212014-04-21 20:47:31 +09001022 ret = extcon_set_cable_state_(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +09001023 EXTCON_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001024
1025 if (ret != 0)
1026 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1027 ret);
1028
Mark Browndd235ee2013-01-11 08:55:51 +09001029 if (!arizona->pdata.hpdet_acc_id) {
1030 info->detecting = true;
1031 info->mic = false;
1032 info->jack_flips = 0;
1033
1034 arizona_start_mic(info);
1035 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001036 queue_delayed_work(system_power_efficient_wq,
1037 &info->hpdet_work,
1038 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001039 }
Mark Brown4e616872013-01-15 22:09:20 +09001040
1041 regmap_update_bits(arizona->regmap,
1042 ARIZONA_JACK_DETECT_DEBOUNCE,
1043 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001044 } else {
1045 dev_dbg(arizona->dev, "Detected jack removal\n");
1046
1047 arizona_stop_mic(info);
1048
Mark Browndd235ee2013-01-11 08:55:51 +09001049 info->num_hpdet_res = 0;
1050 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1051 info->hpdet_res[i] = 0;
1052 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001053 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001054 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001055
Mark Brown6fed4d82013-04-01 22:03:06 +01001056 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001057 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001058 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001059 input_sync(info->input);
1060
Chanwoo Choief70a212014-04-21 20:47:31 +09001061 ret = extcon_update_state(info->edev, 0xffffffff, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001062 if (ret != 0)
1063 dev_err(arizona->dev, "Removal report failed: %d\n",
1064 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001065
1066 regmap_update_bits(arizona->regmap,
1067 ARIZONA_JACK_DETECT_DEBOUNCE,
1068 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1069 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001070 }
1071
Mark Brown7abd4e22013-04-01 19:25:55 +01001072 if (arizona->pdata.micd_timeout)
1073 info->micd_timeout = arizona->pdata.micd_timeout;
1074 else
1075 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1076
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001077out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001078 /* Clear trig_sts to make sure DCVDD is not forced up */
1079 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1080 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1081 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1082 ARIZONA_JD1_FALL_TRIG_STS |
1083 ARIZONA_JD1_RISE_TRIG_STS);
1084
Mark Brownf2c32a82012-06-24 12:09:45 +01001085 mutex_unlock(&info->lock);
1086
1087 pm_runtime_mark_last_busy(info->dev);
1088 pm_runtime_put_autosuspend(info->dev);
1089
1090 return IRQ_HANDLED;
1091}
1092
Mark Brown6fed4d82013-04-01 22:03:06 +01001093/* Map a level onto a slot in the register bank */
1094static void arizona_micd_set_level(struct arizona *arizona, int index,
1095 unsigned int level)
1096{
1097 int reg;
1098 unsigned int mask;
1099
1100 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1101
1102 if (!(index % 2)) {
1103 mask = 0x3f00;
1104 level <<= 8;
1105 } else {
1106 mask = 0x3f;
1107 }
1108
1109 /* Program the level itself */
1110 regmap_update_bits(arizona->regmap, reg, mask, level);
1111}
1112
Inha Song9e86b2a2015-05-04 13:42:13 +09001113static int arizona_extcon_of_get_pdata(struct arizona *arizona)
1114{
1115 struct arizona_pdata *pdata = &arizona->pdata;
1116 unsigned int val = ARIZONA_ACCDET_MODE_HPL;
1117
1118 of_property_read_u32(arizona->dev->of_node, "wlf,hpdet-channel", &val);
1119 switch (val) {
1120 case ARIZONA_ACCDET_MODE_HPL:
1121 case ARIZONA_ACCDET_MODE_HPR:
1122 pdata->hpdet_channel = val;
1123 break;
1124 default:
1125 dev_err(arizona->dev,
1126 "Wrong wlf,hpdet-channel DT value %d\n", val);
1127 pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
1128 }
1129
1130 return 0;
1131}
1132
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001133static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001134{
1135 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001136 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001137 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001138 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001139 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001140 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001141 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001142
Mark Brownbbbd46e2013-01-10 19:38:43 +00001143 if (!arizona->dapm || !arizona->dapm->card)
1144 return -EPROBE_DEFER;
1145
Mark Brownf2c32a82012-06-24 12:09:45 +01001146 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001147 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001148 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001149
Inha Song9e86b2a2015-05-04 13:42:13 +09001150 if (IS_ENABLED(CONFIG_OF)) {
1151 if (!dev_get_platdata(arizona->dev))
1152 arizona_extcon_of_get_pdata(arizona);
1153 }
1154
Charles Keepax17271f62014-07-18 12:59:00 +01001155 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001156 if (IS_ERR(info->micvdd)) {
1157 ret = PTR_ERR(info->micvdd);
1158 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001159 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001160 }
1161
1162 mutex_init(&info->lock);
1163 info->arizona = arizona;
1164 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001165 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001166 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001167 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001168 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001169 platform_set_drvdata(pdev, info);
1170
1171 switch (arizona->type) {
1172 case WM5102:
1173 switch (arizona->rev) {
1174 case 0:
1175 info->micd_reva = true;
1176 break;
1177 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001178 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001179 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001180 break;
1181 }
1182 break;
Charles Keepax77438612013-11-14 16:18:25 +00001183 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001184 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001185 switch (arizona->rev) {
1186 case 0 ... 2:
1187 break;
1188 default:
1189 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001190 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001191 break;
1192 }
1193 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001194 default:
1195 break;
1196 }
1197
Chanwoo Choief70a212014-04-21 20:47:31 +09001198 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1199 if (IS_ERR(info->edev)) {
1200 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1201 return -ENOMEM;
1202 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001203
Chanwoo Choief70a212014-04-21 20:47:31 +09001204 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001205 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001206 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001207 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001208 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001209 }
1210
Mark Brown6fed4d82013-04-01 22:03:06 +01001211 info->input = devm_input_allocate_device(&pdev->dev);
1212 if (!info->input) {
1213 dev_err(arizona->dev, "Can't allocate input dev\n");
1214 ret = -ENOMEM;
1215 goto err_register;
1216 }
1217
1218 info->input->name = "Headset";
1219 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001220
Mark Brownf2c32a82012-06-24 12:09:45 +01001221 if (pdata->num_micd_configs) {
1222 info->micd_modes = pdata->micd_configs;
1223 info->micd_num_modes = pdata->num_micd_configs;
1224 } else {
1225 info->micd_modes = micd_default_modes;
1226 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1227 }
1228
1229 if (arizona->pdata.micd_pol_gpio > 0) {
1230 if (info->micd_modes[0].gpio)
1231 mode = GPIOF_OUT_INIT_HIGH;
1232 else
1233 mode = GPIOF_OUT_INIT_LOW;
1234
1235 ret = devm_gpio_request_one(&pdev->dev,
1236 arizona->pdata.micd_pol_gpio,
1237 mode,
1238 "MICD polarity");
1239 if (ret != 0) {
1240 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1241 arizona->pdata.micd_pol_gpio, ret);
1242 goto err_register;
1243 }
1244 }
1245
Mark Brown1eda6aa2013-01-11 08:55:54 +09001246 if (arizona->pdata.hpdet_id_gpio > 0) {
1247 ret = devm_gpio_request_one(&pdev->dev,
1248 arizona->pdata.hpdet_id_gpio,
1249 GPIOF_OUT_INIT_LOW,
1250 "HPDET");
1251 if (ret != 0) {
1252 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1253 arizona->pdata.hpdet_id_gpio, ret);
1254 goto err_register;
1255 }
1256 }
1257
Mark Brownb17e5462013-01-11 08:55:24 +09001258 if (arizona->pdata.micd_bias_start_time)
1259 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1260 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1261 arizona->pdata.micd_bias_start_time
1262 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1263
Mark Brown2e033db2013-01-21 17:36:33 +09001264 if (arizona->pdata.micd_rate)
1265 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1266 ARIZONA_MICD_RATE_MASK,
1267 arizona->pdata.micd_rate
1268 << ARIZONA_MICD_RATE_SHIFT);
1269
1270 if (arizona->pdata.micd_dbtime)
1271 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1272 ARIZONA_MICD_DBTIME_MASK,
1273 arizona->pdata.micd_dbtime
1274 << ARIZONA_MICD_DBTIME_SHIFT);
1275
Mark Brown6fed4d82013-04-01 22:03:06 +01001276 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1277
1278 if (arizona->pdata.num_micd_ranges) {
1279 info->micd_ranges = pdata->micd_ranges;
1280 info->num_micd_ranges = pdata->num_micd_ranges;
1281 } else {
1282 info->micd_ranges = micd_default_ranges;
1283 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1284 }
1285
1286 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1287 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1288 arizona->pdata.num_micd_ranges);
1289 }
1290
1291 if (info->num_micd_ranges > 1) {
1292 for (i = 1; i < info->num_micd_ranges; i++) {
1293 if (info->micd_ranges[i - 1].max >
1294 info->micd_ranges[i].max) {
1295 dev_err(arizona->dev,
1296 "MICD ranges must be sorted\n");
1297 ret = -EINVAL;
1298 goto err_input;
1299 }
1300 }
1301 }
1302
1303 /* Disable all buttons by default */
1304 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1305 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1306
1307 /* Set up all the buttons the user specified */
1308 for (i = 0; i < info->num_micd_ranges; i++) {
1309 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1310 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1311 break;
1312
1313 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1314 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1315 info->micd_ranges[i].max);
1316 ret = -EINVAL;
1317 goto err_input;
1318 }
1319
1320 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1321 arizona_micd_levels[j], i);
1322
1323 arizona_micd_set_level(arizona, i, j);
1324 input_set_capability(info->input, EV_KEY,
1325 info->micd_ranges[i].key);
1326
1327 /* Enable reporting of that range */
1328 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1329 1 << i, 1 << i);
1330 }
1331
1332 /* Set all the remaining keys to a maximum */
1333 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1334 arizona_micd_set_level(arizona, i, 0x3f);
1335
Mark Browndab63eb2013-01-11 08:55:36 +09001336 /*
Mark Brown92a49872013-01-11 08:55:39 +09001337 * If we have a clamp use it, activating in conjunction with
1338 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001339 */
1340 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001341 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001342 /* Put the GPIO into input mode with optional pull */
1343 val = 0xc101;
1344 if (arizona->pdata.jd_gpio5_nopull)
1345 val &= ~ARIZONA_GPN_PU;
1346
Mark Brown92a49872013-01-11 08:55:39 +09001347 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001348 val);
Mark Brown92a49872013-01-11 08:55:39 +09001349
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001350 if (arizona->pdata.jd_invert)
1351 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1352 else
1353 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001354 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001355 if (arizona->pdata.jd_invert)
1356 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1357 else
1358 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001359 }
1360
Mark Browndab63eb2013-01-11 08:55:36 +09001361 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001362 ARIZONA_MICD_CLAMP_CONTROL,
1363 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1364
1365 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001366 ARIZONA_JACK_DETECT_DEBOUNCE,
1367 ARIZONA_MICD_CLAMP_DB,
1368 ARIZONA_MICD_CLAMP_DB);
1369 }
1370
Mark Brownf2c32a82012-06-24 12:09:45 +01001371 arizona_extcon_set_mode(info, 0);
1372
1373 pm_runtime_enable(&pdev->dev);
1374 pm_runtime_idle(&pdev->dev);
1375 pm_runtime_get_sync(&pdev->dev);
1376
Mark Brown92a49872013-01-11 08:55:39 +09001377 if (arizona->pdata.jd_gpio5) {
1378 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1379 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1380 } else {
1381 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1382 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1383 }
1384
1385 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001386 "JACKDET rise", arizona_jackdet, info);
1387 if (ret != 0) {
1388 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1389 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001390 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001391 }
1392
Mark Brown92a49872013-01-11 08:55:39 +09001393 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001394 if (ret != 0) {
1395 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1396 ret);
1397 goto err_rise;
1398 }
1399
Mark Brown92a49872013-01-11 08:55:39 +09001400 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001401 "JACKDET fall", arizona_jackdet, info);
1402 if (ret != 0) {
1403 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1404 goto err_rise_wake;
1405 }
1406
Mark Brown92a49872013-01-11 08:55:39 +09001407 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001408 if (ret != 0) {
1409 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1410 ret);
1411 goto err_fall;
1412 }
1413
1414 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1415 "MICDET", arizona_micdet, info);
1416 if (ret != 0) {
1417 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1418 goto err_fall_wake;
1419 }
1420
Mark Brown4f340332013-01-11 08:55:43 +09001421 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1422 "HPDET", arizona_hpdet_irq, info);
1423 if (ret != 0) {
1424 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1425 goto err_micdet;
1426 }
1427
Mark Brownf2c32a82012-06-24 12:09:45 +01001428 arizona_clk32k_enable(arizona);
1429 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1430 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1431 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1432 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1433
Mark Brownb8575a12012-09-07 17:01:15 +08001434 ret = regulator_allow_bypass(info->micvdd, true);
1435 if (ret != 0)
1436 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1437 ret);
1438
Mark Brownf2c32a82012-06-24 12:09:45 +01001439 pm_runtime_put(&pdev->dev);
1440
Mark Brown34efe4d2012-07-20 17:07:29 +01001441 ret = input_register_device(info->input);
1442 if (ret) {
1443 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001444 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001445 }
1446
Mark Brownf2c32a82012-06-24 12:09:45 +01001447 return 0;
1448
Mark Brown4f340332013-01-11 08:55:43 +09001449err_hpdet:
1450 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001451err_micdet:
1452 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001453err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001454 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001455err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001456 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001457err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001458 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001459err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001460 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001461err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001462err_register:
1463 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001464 return ret;
1465}
1466
Bill Pemberton93ed0322012-11-19 13:25:49 -05001467static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001468{
1469 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1470 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001471 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001472
1473 pm_runtime_disable(&pdev->dev);
1474
Mark Browndab63eb2013-01-11 08:55:36 +09001475 regmap_update_bits(arizona->regmap,
1476 ARIZONA_MICD_CLAMP_CONTROL,
1477 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1478
Mark Brown92a49872013-01-11 08:55:39 +09001479 if (arizona->pdata.jd_gpio5) {
1480 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1481 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1482 } else {
1483 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1484 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1485 }
1486
1487 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1488 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1489 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001490 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001491 arizona_free_irq(arizona, jack_irq_rise, info);
1492 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001493 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001494 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1495 ARIZONA_JD1_ENA, 0);
1496 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001497
1498 return 0;
1499}
1500
1501static struct platform_driver arizona_extcon_driver = {
1502 .driver = {
1503 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001504 },
1505 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001506 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001507};
1508
1509module_platform_driver(arizona_extcon_driver);
1510
1511MODULE_DESCRIPTION("Arizona Extcon driver");
1512MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1513MODULE_LICENSE("GPL");
1514MODULE_ALIAS("platform:extcon-arizona");