blob: a366ee33610ae80c216d52179881a826b1b2ba55 [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>
Charles Keepaxfeffb0c2015-06-19 17:23:29 +010027#include <linux/property.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010028#include <linux/regulator/consumer.h>
29#include <linux/extcon.h>
30
Mark Brownbbbd46e2013-01-10 19:38:43 +000031#include <sound/soc.h>
32
Mark Brownf2c32a82012-06-24 12:09:45 +010033#include <linux/mfd/arizona/core.h>
34#include <linux/mfd/arizona/pdata.h>
35#include <linux/mfd/arizona/registers.h>
Inha Song9e86b2a2015-05-04 13:42:13 +090036#include <dt-bindings/mfd/arizona.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010037
Mark Brown6fed4d82013-04-01 22:03:06 +010038#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010039
Richard Fitzgeralda288d642014-05-23 12:54:57 +010040#define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
41#define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
42#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
43#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
44
Mark Brown9dd5e532013-04-01 19:09:45 +010045#define ARIZONA_HPDET_MAX 10000
46
Mark Brown2643fd62013-04-01 19:07:28 +010047#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010048#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010049
Charles Keepaxffae24f2013-11-14 16:18:21 +000050#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
51 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
52 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
53 ARIZONA_MICD_LVL_7)
54
55#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
56
57#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
58
Mark Brownf2c32a82012-06-24 12:09:45 +010059struct arizona_extcon_info {
60 struct device *dev;
61 struct arizona *arizona;
62 struct mutex lock;
63 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010064 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010065
Mark Browna3e20782013-04-01 19:05:27 +010066 u16 last_jackdet;
67
Mark Brownf2c32a82012-06-24 12:09:45 +010068 int micd_mode;
69 const struct arizona_micd_config *micd_modes;
70 int micd_num_modes;
71
Mark Brown6fed4d82013-04-01 22:03:06 +010072 const struct arizona_micd_range *micd_ranges;
73 int num_micd_ranges;
74
Mark Brown7abd4e22013-04-01 19:25:55 +010075 int micd_timeout;
76
Mark Brownf2c32a82012-06-24 12:09:45 +010077 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090078 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010079
Mark Brown0e27bd32013-02-05 21:00:15 +000080 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010081 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010082 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000083
Mark Brown4f340332013-01-11 08:55:43 +090084 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000085 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010086 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090087
Mark Browndd235ee2013-01-11 08:55:51 +090088 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090089 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090090
Mark Brownf2c32a82012-06-24 12:09:45 +010091 bool mic;
92 bool detecting;
93 int jack_flips;
94
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +010095 int hpdet_ip_version;
Mark Brown4f340332013-01-11 08:55:43 +090096
Chanwoo Choief70a212014-04-21 20:47:31 +090097 struct extcon_dev *edev;
Mark Brownf2c32a82012-06-24 12:09:45 +010098};
99
100static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +0100101 { ARIZONA_ACCDET_SRC, 1, 0 },
102 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100103};
104
Mark Brown6fed4d82013-04-01 22:03:06 +0100105static const struct arizona_micd_range micd_default_ranges[] = {
106 { .max = 11, .key = BTN_0 },
107 { .max = 28, .key = BTN_1 },
108 { .max = 54, .key = BTN_2 },
109 { .max = 100, .key = BTN_3 },
110 { .max = 186, .key = BTN_4 },
111 { .max = 430, .key = BTN_5 },
112};
113
114static const int arizona_micd_levels[] = {
115 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
116 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
117 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
118 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
119 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100120};
121
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900122static const unsigned int arizona_cable[] = {
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900123 EXTCON_MECHANICAL,
124 EXTCON_MICROPHONE,
125 EXTCON_HEADPHONE,
126 EXTCON_LINE_OUT,
127 EXTCON_NONE,
Mark Brownf2c32a82012-06-24 12:09:45 +0100128};
129
Mark Brown9dd5e532013-04-01 19:09:45 +0100130static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
131
Charles Keepax112bdfa2015-02-16 15:41:02 +0000132static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
133 bool clamp)
Mark Brown03409072013-02-12 13:00:31 +0000134{
135 struct arizona *arizona = info->arizona;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000136 unsigned int mask = 0, val = 0;
Mark Brown03409072013-02-12 13:00:31 +0000137 int ret;
138
Charles Keepax43f0acd2015-02-16 15:41:03 +0000139 switch (arizona->type) {
140 case WM5110:
Charles Keepax2b51f9c2015-04-30 23:43:37 +0900141 case WM8280:
Charles Keepax43f0acd2015-02-16 15:41:03 +0000142 mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
143 ARIZONA_HP1L_SHRTI;
144 if (clamp)
145 val = ARIZONA_HP1L_SHRTO;
146 else
147 val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
148 break;
149 default:
150 mask = ARIZONA_RMV_SHRT_HP1L;
151 if (clamp)
152 val = ARIZONA_RMV_SHRT_HP1L;
153 break;
154 };
Charles Keepax112bdfa2015-02-16 15:41:02 +0000155
Mark Brown03409072013-02-12 13:00:31 +0000156 mutex_lock(&arizona->dapm->card->dapm_mutex);
157
Charles Keepax112bdfa2015-02-16 15:41:02 +0000158 arizona->hpdet_clamp = clamp;
Mark Browndf8c3db2013-02-22 18:38:03 +0000159
Charles Keepax112bdfa2015-02-16 15:41:02 +0000160 /* Keep the HP output stages disabled while doing the clamp */
161 if (clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000162 ret = regmap_update_bits(arizona->regmap,
163 ARIZONA_OUTPUT_ENABLES_1,
164 ARIZONA_OUT1L_ENA |
165 ARIZONA_OUT1R_ENA, 0);
166 if (ret != 0)
167 dev_warn(arizona->dev,
168 "Failed to disable headphone outputs: %d\n",
169 ret);
Mark Brown03409072013-02-12 13:00:31 +0000170 }
171
Charles Keepax112bdfa2015-02-16 15:41:02 +0000172 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
Charles Keepax43f0acd2015-02-16 15:41:03 +0000173 mask, val);
Mark Browndf8c3db2013-02-22 18:38:03 +0000174 if (ret != 0)
Charles Keepax112bdfa2015-02-16 15:41:02 +0000175 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000176 ret);
177
Charles Keepax112bdfa2015-02-16 15:41:02 +0000178 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
Charles Keepax43f0acd2015-02-16 15:41:03 +0000179 mask, val);
Mark Browndf8c3db2013-02-22 18:38:03 +0000180 if (ret != 0)
Charles Keepax112bdfa2015-02-16 15:41:02 +0000181 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Browndf8c3db2013-02-22 18:38:03 +0000182 ret);
183
Charles Keepax112bdfa2015-02-16 15:41:02 +0000184 /* Restore the desired state while not doing the clamp */
185 if (!clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000186 ret = regmap_update_bits(arizona->regmap,
187 ARIZONA_OUTPUT_ENABLES_1,
188 ARIZONA_OUT1L_ENA |
189 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000190 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000191 dev_warn(arizona->dev,
192 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000193 ret);
194 }
195
196 mutex_unlock(&arizona->dapm->card->dapm_mutex);
197}
198
Mark Brownf2c32a82012-06-24 12:09:45 +0100199static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
200{
201 struct arizona *arizona = info->arizona;
202
Mark Brown6fed4d82013-04-01 22:03:06 +0100203 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800204
Mark Browncd74f7b2012-11-27 16:14:26 +0900205 if (arizona->pdata.micd_pol_gpio > 0)
206 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
207 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100208 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
209 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100210 info->micd_modes[mode].bias <<
211 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100212 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
213 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
214
215 info->micd_mode = mode;
216
217 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
218}
219
Mark Brownbbbd46e2013-01-10 19:38:43 +0000220static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
221{
Charles Keepax41024242013-09-23 14:33:59 +0100222 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000223 case 1:
224 return "MICBIAS1";
225 case 2:
226 return "MICBIAS2";
227 case 3:
228 return "MICBIAS3";
229 default:
230 return "MICVDD";
231 }
232}
233
234static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
235{
236 struct arizona *arizona = info->arizona;
237 const char *widget = arizona_extcon_get_micbias(info);
238 struct snd_soc_dapm_context *dapm = arizona->dapm;
239 int ret;
240
Mark Brownbbbd46e2013-01-10 19:38:43 +0000241 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
242 if (ret != 0)
243 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
244 widget, ret);
245
Mark Brownbbbd46e2013-01-10 19:38:43 +0000246 snd_soc_dapm_sync(dapm);
247
248 if (!arizona->pdata.micd_force_micbias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000249 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
250 if (ret != 0)
251 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
252 widget, ret);
253
Mark Brownbbbd46e2013-01-10 19:38:43 +0000254 snd_soc_dapm_sync(dapm);
255 }
256}
257
Mark Brown9b1270c2013-01-11 08:55:46 +0900258static void arizona_start_mic(struct arizona_extcon_info *info)
259{
260 struct arizona *arizona = info->arizona;
261 bool change;
262 int ret;
263
Mark Brown9b1270c2013-01-11 08:55:46 +0900264 /* Microphone detection can't use idle mode */
265 pm_runtime_get(info->dev);
266
Mark Brownbbbd46e2013-01-10 19:38:43 +0000267 if (info->detecting) {
268 ret = regulator_allow_bypass(info->micvdd, false);
269 if (ret != 0) {
270 dev_err(arizona->dev,
271 "Failed to regulate MICVDD: %d\n",
272 ret);
273 }
274 }
275
Mark Brown9b1270c2013-01-11 08:55:46 +0900276 ret = regulator_enable(info->micvdd);
277 if (ret != 0) {
278 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
279 ret);
280 }
281
282 if (info->micd_reva) {
283 regmap_write(arizona->regmap, 0x80, 0x3);
284 regmap_write(arizona->regmap, 0x294, 0);
285 regmap_write(arizona->regmap, 0x80, 0x0);
286 }
287
288 regmap_update_bits(arizona->regmap,
289 ARIZONA_ACCESSORY_DETECT_MODE_1,
290 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
291
Mark Brownbbbd46e2013-01-10 19:38:43 +0000292 arizona_extcon_pulse_micbias(info);
293
Mark Brown9b1270c2013-01-11 08:55:46 +0900294 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
295 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
296 &change);
297 if (!change) {
298 regulator_disable(info->micvdd);
299 pm_runtime_put_autosuspend(info->dev);
300 }
301}
302
303static void arizona_stop_mic(struct arizona_extcon_info *info)
304{
305 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000306 const char *widget = arizona_extcon_get_micbias(info);
307 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900308 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000309 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900310
311 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
312 ARIZONA_MICD_ENA, 0,
313 &change);
314
Mark Brownbbbd46e2013-01-10 19:38:43 +0000315 ret = snd_soc_dapm_disable_pin(dapm, widget);
316 if (ret != 0)
317 dev_warn(arizona->dev,
318 "Failed to disable %s: %d\n",
319 widget, ret);
320
Mark Brownbbbd46e2013-01-10 19:38:43 +0000321 snd_soc_dapm_sync(dapm);
322
Mark Brown9b1270c2013-01-11 08:55:46 +0900323 if (info->micd_reva) {
324 regmap_write(arizona->regmap, 0x80, 0x3);
325 regmap_write(arizona->regmap, 0x294, 2);
326 regmap_write(arizona->regmap, 0x80, 0x0);
327 }
328
Mark Brownbbbd46e2013-01-10 19:38:43 +0000329 ret = regulator_allow_bypass(info->micvdd, true);
330 if (ret != 0) {
331 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
332 ret);
333 }
334
Mark Brown9b1270c2013-01-11 08:55:46 +0900335 if (change) {
336 regulator_disable(info->micvdd);
337 pm_runtime_mark_last_busy(info->dev);
338 pm_runtime_put_autosuspend(info->dev);
339 }
340}
341
Mark Brown4f340332013-01-11 08:55:43 +0900342static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100343 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900344 unsigned int factor_a;
345 unsigned int factor_b;
346} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100347 { 100, 5528, 362464 },
348 { 169, 11084, 6186851 },
349 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900350};
351
Charles Keepax24a279b2014-05-30 13:19:17 +0100352#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
353
Mark Brown4f340332013-01-11 08:55:43 +0900354static struct {
355 int min;
356 int max;
357} arizona_hpdet_c_ranges[] = {
358 { 0, 30 },
359 { 8, 100 },
360 { 100, 1000 },
361 { 1000, 10000 },
362};
363
364static int arizona_hpdet_read(struct arizona_extcon_info *info)
365{
366 struct arizona *arizona = info->arizona;
367 unsigned int val, range;
368 int ret;
369
370 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
371 if (ret != 0) {
372 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
373 ret);
374 return ret;
375 }
376
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100377 switch (info->hpdet_ip_version) {
Mark Brown4f340332013-01-11 08:55:43 +0900378 case 0:
379 if (!(val & ARIZONA_HP_DONE)) {
380 dev_err(arizona->dev, "HPDET did not complete: %x\n",
381 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900382 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900383 }
384
385 val &= ARIZONA_HP_LVL_MASK;
386 break;
387
388 case 1:
389 if (!(val & ARIZONA_HP_DONE_B)) {
390 dev_err(arizona->dev, "HPDET did not complete: %x\n",
391 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900392 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900393 }
394
395 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
396 if (ret != 0) {
397 dev_err(arizona->dev, "Failed to read HP value: %d\n",
398 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900399 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900400 }
401
402 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
403 &range);
404 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
405 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
406
407 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100408 (val < arizona_hpdet_b_ranges[range].threshold ||
409 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900410 range++;
411 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
412 range);
413 regmap_update_bits(arizona->regmap,
414 ARIZONA_HEADPHONE_DETECT_1,
415 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
416 range <<
417 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
418 return -EAGAIN;
419 }
420
421 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100422 if (val < arizona_hpdet_b_ranges[range].threshold ||
423 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900424 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100425 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900426 }
427
428 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
429 val, range);
430
431 val = arizona_hpdet_b_ranges[range].factor_b
432 / ((val * 100) -
433 arizona_hpdet_b_ranges[range].factor_a);
434 break;
435
436 default:
437 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100438 info->hpdet_ip_version);
Mark Brown4f340332013-01-11 08:55:43 +0900439 case 2:
440 if (!(val & ARIZONA_HP_DONE_B)) {
441 dev_err(arizona->dev, "HPDET did not complete: %x\n",
442 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900443 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900444 }
445
446 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000447 /* Convert to ohms, the value is in 0.5 ohm increments */
448 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900449
450 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
451 &range);
452 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
453 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
454
Charles Keepax91414612013-11-14 16:18:24 +0000455 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900456 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
457 (val >= arizona_hpdet_c_ranges[range].max)) {
458 range++;
459 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
460 arizona_hpdet_c_ranges[range].min,
461 arizona_hpdet_c_ranges[range].max);
462 regmap_update_bits(arizona->regmap,
463 ARIZONA_HEADPHONE_DETECT_1,
464 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
465 range <<
466 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
467 return -EAGAIN;
468 }
Charles Keepax91414612013-11-14 16:18:24 +0000469
470 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
471 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
472 arizona_hpdet_c_ranges[range].min);
473 val = arizona_hpdet_c_ranges[range].min;
474 }
Mark Brown4f340332013-01-11 08:55:43 +0900475 }
476
477 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
478 return val;
479}
480
Mark Brown9c2ba272013-02-25 23:42:31 +0000481static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
482 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900483{
484 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900485 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900486
487 /*
488 * If we're using HPDET for accessory identification we need
489 * to take multiple measurements, step through them in sequence.
490 */
491 if (arizona->pdata.hpdet_acc_id) {
492 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900493
494 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000495 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900496 dev_dbg(arizona->dev, "Measuring mic\n");
497
498 regmap_update_bits(arizona->regmap,
499 ARIZONA_ACCESSORY_DETECT_MODE_1,
500 ARIZONA_ACCDET_MODE_MASK |
501 ARIZONA_ACCDET_SRC,
502 ARIZONA_ACCDET_MODE_HPR |
503 info->micd_modes[0].src);
504
505 gpio_set_value_cansleep(id_gpio, 1);
506
Mark Browndd235ee2013-01-11 08:55:51 +0900507 regmap_update_bits(arizona->regmap,
508 ARIZONA_HEADPHONE_DETECT_1,
509 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
510 return -EAGAIN;
511 }
512
513 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000514 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
515 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000516
517 /* Take the headphone impedance for the main report */
518 *reading = info->hpdet_res[0];
519
Mark Brown9dd5e532013-04-01 19:09:45 +0100520 /* Sometimes we get false readings due to slow insert */
521 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
522 dev_dbg(arizona->dev, "Retrying high impedance\n");
523 info->num_hpdet_res = 0;
524 info->hpdet_retried = true;
525 arizona_start_hpdet_acc_id(info);
526 pm_runtime_put(info->dev);
527 return -EAGAIN;
528 }
529
Mark Brown1eda6aa2013-01-11 08:55:54 +0900530 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530531 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900532 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000533 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900534 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000535 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000536 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900537 } else {
538 dev_dbg(arizona->dev, "Detected headphone\n");
539 }
540
541 /* Make sure everything is reset back to the real polarity */
542 regmap_update_bits(arizona->regmap,
543 ARIZONA_ACCESSORY_DETECT_MODE_1,
544 ARIZONA_ACCDET_SRC,
545 info->micd_modes[0].src);
546 }
547
548 return 0;
549}
550
Mark Brown4f340332013-01-11 08:55:43 +0900551static irqreturn_t arizona_hpdet_irq(int irq, void *data)
552{
553 struct arizona_extcon_info *info = data;
554 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900555 int id_gpio = arizona->pdata.hpdet_id_gpio;
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900556 unsigned int report = EXTCON_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900557 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000558 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900559
560 mutex_lock(&info->lock);
561
562 /* If we got a spurious IRQ for some reason then ignore it */
563 if (!info->hpdet_active) {
564 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
565 mutex_unlock(&info->lock);
566 return IRQ_NONE;
567 }
568
569 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900570 ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900571 if (ret < 0) {
572 dev_err(arizona->dev, "Failed to check cable state: %d\n",
573 ret);
574 goto out;
575 } else if (!ret) {
576 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
577 goto done;
578 }
579
580 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900581 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900582 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900583 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900584 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900585 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900586
587 /* Reset back to starting range */
588 regmap_update_bits(arizona->regmap,
589 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900590 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
591 0);
592
Mark Brown9c2ba272013-02-25 23:42:31 +0000593 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900594 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900595 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900596 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900597 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900598
599 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900600 if (reading >= 5000)
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900601 report = EXTCON_LINE_OUT;
Mark Brown4f340332013-01-11 08:55:43 +0900602 else
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900603 report = EXTCON_HEADPHONE;
Mark Brown4f340332013-01-11 08:55:43 +0900604
Chanwoo Choief70a212014-04-21 20:47:31 +0900605 ret = extcon_set_cable_state_(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900606 if (ret != 0)
607 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
608 ret);
609
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000610done:
611 /* Reset back to starting range */
612 regmap_update_bits(arizona->regmap,
613 ARIZONA_HEADPHONE_DETECT_1,
614 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
615 0);
616
Charles Keepax112bdfa2015-02-16 15:41:02 +0000617 arizona_extcon_hp_clamp(info, false);
Mark Brown4f340332013-01-11 08:55:43 +0900618
Mark Brown1eda6aa2013-01-11 08:55:54 +0900619 if (id_gpio)
620 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900621
622 /* Revert back to MICDET mode */
623 regmap_update_bits(arizona->regmap,
624 ARIZONA_ACCESSORY_DETECT_MODE_1,
625 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
626
627 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000628 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900629 arizona_start_mic(info);
630
631 if (info->hpdet_active) {
632 pm_runtime_put_autosuspend(info->dev);
633 info->hpdet_active = false;
634 }
635
Mark Brownbf14ee52013-02-05 20:20:17 +0000636 info->hpdet_done = true;
637
Mark Brown4f340332013-01-11 08:55:43 +0900638out:
639 mutex_unlock(&info->lock);
640
641 return IRQ_HANDLED;
642}
643
644static void arizona_identify_headphone(struct arizona_extcon_info *info)
645{
646 struct arizona *arizona = info->arizona;
647 int ret;
648
Mark Brownbf14ee52013-02-05 20:20:17 +0000649 if (info->hpdet_done)
650 return;
651
Mark Brown4f340332013-01-11 08:55:43 +0900652 dev_dbg(arizona->dev, "Starting HPDET\n");
653
654 /* Make sure we keep the device enabled during the measurement */
655 pm_runtime_get(info->dev);
656
657 info->hpdet_active = true;
658
659 if (info->mic)
660 arizona_stop_mic(info);
661
Charles Keepax112bdfa2015-02-16 15:41:02 +0000662 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900663
664 ret = regmap_update_bits(arizona->regmap,
665 ARIZONA_ACCESSORY_DETECT_MODE_1,
666 ARIZONA_ACCDET_MODE_MASK,
Inha Song9e86b2a2015-05-04 13:42:13 +0900667 arizona->pdata.hpdet_channel);
Mark Brown4f340332013-01-11 08:55:43 +0900668 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900669 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +0900670 goto err;
671 }
672
673 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
674 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
675 if (ret != 0) {
676 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
677 ret);
678 goto err;
679 }
680
681 return;
682
683err:
684 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
685 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
686
687 /* Just report headphone */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900688 ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900689 if (ret != 0)
690 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
691
692 if (info->mic)
693 arizona_start_mic(info);
694
695 info->hpdet_active = false;
696}
Mark Browndd235ee2013-01-11 08:55:51 +0900697
698static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
699{
700 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000701 int hp_reading = 32;
702 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900703 int ret;
704
705 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
706
707 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000708 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900709
710 info->hpdet_active = true;
711
Charles Keepax112bdfa2015-02-16 15:41:02 +0000712 arizona_extcon_hp_clamp(info, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900713
714 ret = regmap_update_bits(arizona->regmap,
715 ARIZONA_ACCESSORY_DETECT_MODE_1,
716 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
717 info->micd_modes[0].src |
Inha Song9e86b2a2015-05-04 13:42:13 +0900718 arizona->pdata.hpdet_channel);
Mark Browndd235ee2013-01-11 08:55:51 +0900719 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900720 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Browndd235ee2013-01-11 08:55:51 +0900721 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900722 }
723
Mark Brown9c2ba272013-02-25 23:42:31 +0000724 if (arizona->pdata.hpdet_acc_id_line) {
725 ret = regmap_update_bits(arizona->regmap,
726 ARIZONA_HEADPHONE_DETECT_1,
727 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
728 if (ret != 0) {
729 dev_err(arizona->dev,
730 "Can't start HPDETL measurement: %d\n",
731 ret);
732 goto err;
733 }
734 } else {
735 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900736 }
737
738 return;
739
740err:
741 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
742 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
743
744 /* Just report headphone */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900745 ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900746 if (ret != 0)
747 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
748
Mark Brown4f340332013-01-11 08:55:43 +0900749 info->hpdet_active = false;
750}
751
Mark Brown939c5672013-04-01 19:17:34 +0100752static void arizona_micd_timeout_work(struct work_struct *work)
753{
754 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900755 struct arizona_extcon_info,
756 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100757
758 mutex_lock(&info->lock);
759
760 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
761 arizona_identify_headphone(info);
762
763 info->detecting = false;
764
765 arizona_stop_mic(info);
766
767 mutex_unlock(&info->lock);
768}
769
Mark Browncd59e792013-04-01 19:21:48 +0100770static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100771{
Mark Browncd59e792013-04-01 19:21:48 +0100772 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900773 struct arizona_extcon_info,
774 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100775 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100776 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100777 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100778
Mark Brown939c5672013-04-01 19:17:34 +0100779 cancel_delayed_work_sync(&info->micd_timeout_work);
780
Mark Brownf2c32a82012-06-24 12:09:45 +0100781 mutex_lock(&info->lock);
782
Charles Keepax31a847e2013-11-14 16:18:23 +0000783 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900784 ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000785 if (ret < 0) {
786 dev_err(arizona->dev, "Failed to check cable state: %d\n",
787 ret);
788 mutex_unlock(&info->lock);
789 return;
790 } else if (!ret) {
791 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
792 mutex_unlock(&info->lock);
793 return;
794 }
795
Charles Keepaxffae24f2013-11-14 16:18:21 +0000796 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100797 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
798 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900799 dev_err(arizona->dev,
800 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100801 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100802 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100803 }
804
805 dev_dbg(arizona->dev, "MICDET: %x\n", val);
806
807 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900808 dev_warn(arizona->dev,
809 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100810 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100811 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100812 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100813 }
814
Charles Keepaxffae24f2013-11-14 16:18:21 +0000815 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100816 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100817 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100818 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100819 }
820
821 /* Due to jack detect this should never happen */
822 if (!(val & ARIZONA_MICD_STS)) {
823 dev_warn(arizona->dev, "Detected open circuit\n");
824 info->detecting = false;
825 goto handled;
826 }
827
828 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000829 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900830 arizona_identify_headphone(info);
831
Nikesh Oswal34602482014-05-29 16:27:52 +0100832 ret = extcon_set_cable_state_(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900833 EXTCON_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100834 if (ret != 0)
835 dev_err(arizona->dev, "Headset report failed: %d\n",
836 ret);
837
Mark Brownbbbd46e2013-01-10 19:38:43 +0000838 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100839 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000840 if (ret != 0) {
841 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
842 ret);
843 }
844
Mark Brownf2c32a82012-06-24 12:09:45 +0100845 info->mic = true;
846 info->detecting = false;
847 goto handled;
848 }
849
850 /* If we detected a lower impedence during initial startup
851 * then we probably have the wrong polarity, flip it. Don't
852 * do this for the lowest impedences to speed up detection of
853 * plain headphones. If both polarities report a low
854 * impedence then give up and report headphones.
855 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000856 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800857 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900858 dev_dbg(arizona->dev, "Detected HP/line\n");
859 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100860
Mark Brown4f340332013-01-11 08:55:43 +0900861 info->detecting = false;
862
863 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100864 } else {
865 info->micd_mode++;
866 if (info->micd_mode == info->micd_num_modes)
867 info->micd_mode = 0;
868 arizona_extcon_set_mode(info, info->micd_mode);
869
870 info->jack_flips++;
871 }
872
873 goto handled;
874 }
875
876 /*
877 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100878 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100879 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000880 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100881 if (info->mic) {
882 dev_dbg(arizona->dev, "Mic button detected\n");
883
Mark Brown34efe4d2012-07-20 17:07:29 +0100884 lvl = val & ARIZONA_MICD_LVL_MASK;
885 lvl >>= ARIZONA_MICD_LVL_SHIFT;
886
Mark Brown41a57852013-04-01 19:18:18 +0100887 for (i = 0; i < info->num_micd_ranges; i++)
888 input_report_key(info->input,
889 info->micd_ranges[i].key, 0);
890
Mark Brown6fed4d82013-04-01 22:03:06 +0100891 WARN_ON(!lvl);
892 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
893 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
894 key = info->micd_ranges[ffs(lvl) - 1].key;
895 input_report_key(info->input, key, 1);
896 input_sync(info->input);
897 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100898
Mark Brownf2c32a82012-06-24 12:09:45 +0100899 } else if (info->detecting) {
900 dev_dbg(arizona->dev, "Headphone detected\n");
901 info->detecting = false;
902 arizona_stop_mic(info);
903
Mark Brown4f340332013-01-11 08:55:43 +0900904 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100905 } else {
906 dev_warn(arizona->dev, "Button with no mic: %x\n",
907 val);
908 }
909 } else {
910 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100911 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100912 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100913 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100914 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000915 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100916 }
917
918handled:
Mark Brown939c5672013-04-01 19:17:34 +0100919 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100920 queue_delayed_work(system_power_efficient_wq,
921 &info->micd_timeout_work,
922 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100923
Mark Brownf2c32a82012-06-24 12:09:45 +0100924 pm_runtime_mark_last_busy(info->dev);
925 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100926}
927
928static irqreturn_t arizona_micdet(int irq, void *data)
929{
930 struct arizona_extcon_info *info = data;
931 struct arizona *arizona = info->arizona;
932 int debounce = arizona->pdata.micd_detect_debounce;
933
934 cancel_delayed_work_sync(&info->micd_detect_work);
935 cancel_delayed_work_sync(&info->micd_timeout_work);
936
937 mutex_lock(&info->lock);
938 if (!info->detecting)
939 debounce = 0;
940 mutex_unlock(&info->lock);
941
942 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100943 queue_delayed_work(system_power_efficient_wq,
944 &info->micd_detect_work,
945 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100946 else
947 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100948
949 return IRQ_HANDLED;
950}
951
Mark Brown0e27bd32013-02-05 21:00:15 +0000952static void arizona_hpdet_work(struct work_struct *work)
953{
954 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900955 struct arizona_extcon_info,
956 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000957
958 mutex_lock(&info->lock);
959 arizona_start_hpdet_acc_id(info);
960 mutex_unlock(&info->lock);
961}
962
Mark Brownf2c32a82012-06-24 12:09:45 +0100963static irqreturn_t arizona_jackdet(int irq, void *data)
964{
965 struct arizona_extcon_info *info = data;
966 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900967 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100968 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100969 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100970
Mark Brown939c5672013-04-01 19:17:34 +0100971 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
972 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100973
Mark Browna3e20782013-04-01 19:05:27 +0100974 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000975
Mark Brownf2c32a82012-06-24 12:09:45 +0100976 mutex_lock(&info->lock);
977
Mark Brown92a49872013-01-11 08:55:39 +0900978 if (arizona->pdata.jd_gpio5) {
979 mask = ARIZONA_MICD_CLAMP_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100980 if (arizona->pdata.jd_invert)
981 present = ARIZONA_MICD_CLAMP_STS;
982 else
983 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +0900984 } else {
985 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100986 if (arizona->pdata.jd_invert)
987 present = 0;
988 else
989 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +0900990 }
991
Mark Brownf2c32a82012-06-24 12:09:45 +0100992 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
993 if (ret != 0) {
994 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
995 ret);
996 mutex_unlock(&info->lock);
997 pm_runtime_put_autosuspend(info->dev);
998 return IRQ_NONE;
999 }
1000
Mark Browna3e20782013-04-01 19:05:27 +01001001 val &= mask;
1002 if (val == info->last_jackdet) {
1003 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001004 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001005 queue_delayed_work(system_power_efficient_wq,
1006 &info->hpdet_work,
1007 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001008
Chanwoo Choic2275d22013-08-23 10:21:37 +09001009 if (cancelled_mic) {
1010 int micd_timeout = info->micd_timeout;
1011
Mark Browndf9a5ab2013-07-18 22:42:22 +01001012 queue_delayed_work(system_power_efficient_wq,
1013 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001014 msecs_to_jiffies(micd_timeout));
1015 }
Mark Brown939c5672013-04-01 19:17:34 +01001016
Mark Browna3e20782013-04-01 19:05:27 +01001017 goto out;
1018 }
1019 info->last_jackdet = val;
1020
1021 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001022 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choief70a212014-04-21 20:47:31 +09001023 ret = extcon_set_cable_state_(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +09001024 EXTCON_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001025
1026 if (ret != 0)
1027 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1028 ret);
1029
Mark Browndd235ee2013-01-11 08:55:51 +09001030 if (!arizona->pdata.hpdet_acc_id) {
1031 info->detecting = true;
1032 info->mic = false;
1033 info->jack_flips = 0;
1034
1035 arizona_start_mic(info);
1036 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001037 queue_delayed_work(system_power_efficient_wq,
1038 &info->hpdet_work,
1039 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001040 }
Mark Brown4e616872013-01-15 22:09:20 +09001041
1042 regmap_update_bits(arizona->regmap,
1043 ARIZONA_JACK_DETECT_DEBOUNCE,
1044 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001045 } else {
1046 dev_dbg(arizona->dev, "Detected jack removal\n");
1047
1048 arizona_stop_mic(info);
1049
Mark Browndd235ee2013-01-11 08:55:51 +09001050 info->num_hpdet_res = 0;
1051 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1052 info->hpdet_res[i] = 0;
1053 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001054 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001055 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001056
Mark Brown6fed4d82013-04-01 22:03:06 +01001057 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001058 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001059 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001060 input_sync(info->input);
1061
Chanwoo Choief70a212014-04-21 20:47:31 +09001062 ret = extcon_update_state(info->edev, 0xffffffff, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001063 if (ret != 0)
1064 dev_err(arizona->dev, "Removal report failed: %d\n",
1065 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001066
1067 regmap_update_bits(arizona->regmap,
1068 ARIZONA_JACK_DETECT_DEBOUNCE,
1069 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1070 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001071 }
1072
Mark Brown7abd4e22013-04-01 19:25:55 +01001073 if (arizona->pdata.micd_timeout)
1074 info->micd_timeout = arizona->pdata.micd_timeout;
1075 else
1076 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1077
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001078out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001079 /* Clear trig_sts to make sure DCVDD is not forced up */
1080 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1081 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1082 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1083 ARIZONA_JD1_FALL_TRIG_STS |
1084 ARIZONA_JD1_RISE_TRIG_STS);
1085
Mark Brownf2c32a82012-06-24 12:09:45 +01001086 mutex_unlock(&info->lock);
1087
1088 pm_runtime_mark_last_busy(info->dev);
1089 pm_runtime_put_autosuspend(info->dev);
1090
1091 return IRQ_HANDLED;
1092}
1093
Mark Brown6fed4d82013-04-01 22:03:06 +01001094/* Map a level onto a slot in the register bank */
1095static void arizona_micd_set_level(struct arizona *arizona, int index,
1096 unsigned int level)
1097{
1098 int reg;
1099 unsigned int mask;
1100
1101 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1102
1103 if (!(index % 2)) {
1104 mask = 0x3f00;
1105 level <<= 8;
1106 } else {
1107 mask = 0x3f;
1108 }
1109
1110 /* Program the level itself */
1111 regmap_update_bits(arizona->regmap, reg, mask, level);
1112}
1113
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001114static int arizona_extcon_device_get_pdata(struct arizona *arizona)
Inha Song9e86b2a2015-05-04 13:42:13 +09001115{
1116 struct arizona_pdata *pdata = &arizona->pdata;
1117 unsigned int val = ARIZONA_ACCDET_MODE_HPL;
1118
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001119 device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
Inha Song9e86b2a2015-05-04 13:42:13 +09001120 switch (val) {
1121 case ARIZONA_ACCDET_MODE_HPL:
1122 case ARIZONA_ACCDET_MODE_HPR:
1123 pdata->hpdet_channel = val;
1124 break;
1125 default:
1126 dev_err(arizona->dev,
1127 "Wrong wlf,hpdet-channel DT value %d\n", val);
1128 pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
1129 }
1130
1131 return 0;
1132}
1133
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001134static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001135{
1136 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001137 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001138 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001139 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001140 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001141 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001142 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001143
Mark Brownbbbd46e2013-01-10 19:38:43 +00001144 if (!arizona->dapm || !arizona->dapm->card)
1145 return -EPROBE_DEFER;
1146
Mark Brownf2c32a82012-06-24 12:09:45 +01001147 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001148 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001149 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001150
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001151 if (!dev_get_platdata(arizona->dev))
1152 arizona_extcon_device_get_pdata(arizona);
Inha Song9e86b2a2015-05-04 13:42:13 +09001153
Charles Keepax17271f62014-07-18 12:59:00 +01001154 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001155 if (IS_ERR(info->micvdd)) {
1156 ret = PTR_ERR(info->micvdd);
1157 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001158 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001159 }
1160
1161 mutex_init(&info->lock);
1162 info->arizona = arizona;
1163 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001164 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001165 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001166 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001167 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001168 platform_set_drvdata(pdev, info);
1169
1170 switch (arizona->type) {
1171 case WM5102:
1172 switch (arizona->rev) {
1173 case 0:
1174 info->micd_reva = true;
1175 break;
1176 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001177 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001178 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001179 break;
1180 }
1181 break;
Charles Keepax77438612013-11-14 16:18:25 +00001182 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001183 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001184 switch (arizona->rev) {
1185 case 0 ... 2:
1186 break;
1187 default:
1188 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001189 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001190 break;
1191 }
1192 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001193 default:
1194 break;
1195 }
1196
Chanwoo Choief70a212014-04-21 20:47:31 +09001197 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1198 if (IS_ERR(info->edev)) {
1199 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1200 return -ENOMEM;
1201 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001202
Chanwoo Choief70a212014-04-21 20:47:31 +09001203 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001204 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001205 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001206 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001207 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001208 }
1209
Mark Brown6fed4d82013-04-01 22:03:06 +01001210 info->input = devm_input_allocate_device(&pdev->dev);
1211 if (!info->input) {
1212 dev_err(arizona->dev, "Can't allocate input dev\n");
1213 ret = -ENOMEM;
1214 goto err_register;
1215 }
1216
1217 info->input->name = "Headset";
1218 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001219
Mark Brownf2c32a82012-06-24 12:09:45 +01001220 if (pdata->num_micd_configs) {
1221 info->micd_modes = pdata->micd_configs;
1222 info->micd_num_modes = pdata->num_micd_configs;
1223 } else {
1224 info->micd_modes = micd_default_modes;
1225 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1226 }
1227
1228 if (arizona->pdata.micd_pol_gpio > 0) {
1229 if (info->micd_modes[0].gpio)
1230 mode = GPIOF_OUT_INIT_HIGH;
1231 else
1232 mode = GPIOF_OUT_INIT_LOW;
1233
1234 ret = devm_gpio_request_one(&pdev->dev,
1235 arizona->pdata.micd_pol_gpio,
1236 mode,
1237 "MICD polarity");
1238 if (ret != 0) {
1239 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1240 arizona->pdata.micd_pol_gpio, ret);
1241 goto err_register;
1242 }
1243 }
1244
Mark Brown1eda6aa2013-01-11 08:55:54 +09001245 if (arizona->pdata.hpdet_id_gpio > 0) {
1246 ret = devm_gpio_request_one(&pdev->dev,
1247 arizona->pdata.hpdet_id_gpio,
1248 GPIOF_OUT_INIT_LOW,
1249 "HPDET");
1250 if (ret != 0) {
1251 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1252 arizona->pdata.hpdet_id_gpio, ret);
1253 goto err_register;
1254 }
1255 }
1256
Mark Brownb17e5462013-01-11 08:55:24 +09001257 if (arizona->pdata.micd_bias_start_time)
1258 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1259 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1260 arizona->pdata.micd_bias_start_time
1261 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1262
Mark Brown2e033db2013-01-21 17:36:33 +09001263 if (arizona->pdata.micd_rate)
1264 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1265 ARIZONA_MICD_RATE_MASK,
1266 arizona->pdata.micd_rate
1267 << ARIZONA_MICD_RATE_SHIFT);
1268
1269 if (arizona->pdata.micd_dbtime)
1270 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1271 ARIZONA_MICD_DBTIME_MASK,
1272 arizona->pdata.micd_dbtime
1273 << ARIZONA_MICD_DBTIME_SHIFT);
1274
Mark Brown6fed4d82013-04-01 22:03:06 +01001275 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1276
1277 if (arizona->pdata.num_micd_ranges) {
1278 info->micd_ranges = pdata->micd_ranges;
1279 info->num_micd_ranges = pdata->num_micd_ranges;
1280 } else {
1281 info->micd_ranges = micd_default_ranges;
1282 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1283 }
1284
1285 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1286 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1287 arizona->pdata.num_micd_ranges);
1288 }
1289
1290 if (info->num_micd_ranges > 1) {
1291 for (i = 1; i < info->num_micd_ranges; i++) {
1292 if (info->micd_ranges[i - 1].max >
1293 info->micd_ranges[i].max) {
1294 dev_err(arizona->dev,
1295 "MICD ranges must be sorted\n");
1296 ret = -EINVAL;
1297 goto err_input;
1298 }
1299 }
1300 }
1301
1302 /* Disable all buttons by default */
1303 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1304 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1305
1306 /* Set up all the buttons the user specified */
1307 for (i = 0; i < info->num_micd_ranges; i++) {
1308 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1309 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1310 break;
1311
1312 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1313 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1314 info->micd_ranges[i].max);
1315 ret = -EINVAL;
1316 goto err_input;
1317 }
1318
1319 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1320 arizona_micd_levels[j], i);
1321
1322 arizona_micd_set_level(arizona, i, j);
1323 input_set_capability(info->input, EV_KEY,
1324 info->micd_ranges[i].key);
1325
1326 /* Enable reporting of that range */
1327 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1328 1 << i, 1 << i);
1329 }
1330
1331 /* Set all the remaining keys to a maximum */
1332 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1333 arizona_micd_set_level(arizona, i, 0x3f);
1334
Mark Browndab63eb2013-01-11 08:55:36 +09001335 /*
Mark Brown92a49872013-01-11 08:55:39 +09001336 * If we have a clamp use it, activating in conjunction with
1337 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001338 */
1339 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001340 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001341 /* Put the GPIO into input mode with optional pull */
1342 val = 0xc101;
1343 if (arizona->pdata.jd_gpio5_nopull)
1344 val &= ~ARIZONA_GPN_PU;
1345
Mark Brown92a49872013-01-11 08:55:39 +09001346 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001347 val);
Mark Brown92a49872013-01-11 08:55:39 +09001348
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001349 if (arizona->pdata.jd_invert)
1350 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1351 else
1352 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001353 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001354 if (arizona->pdata.jd_invert)
1355 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1356 else
1357 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001358 }
1359
Mark Browndab63eb2013-01-11 08:55:36 +09001360 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001361 ARIZONA_MICD_CLAMP_CONTROL,
1362 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1363
1364 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001365 ARIZONA_JACK_DETECT_DEBOUNCE,
1366 ARIZONA_MICD_CLAMP_DB,
1367 ARIZONA_MICD_CLAMP_DB);
1368 }
1369
Mark Brownf2c32a82012-06-24 12:09:45 +01001370 arizona_extcon_set_mode(info, 0);
1371
1372 pm_runtime_enable(&pdev->dev);
1373 pm_runtime_idle(&pdev->dev);
1374 pm_runtime_get_sync(&pdev->dev);
1375
Mark Brown92a49872013-01-11 08:55:39 +09001376 if (arizona->pdata.jd_gpio5) {
1377 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1378 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1379 } else {
1380 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1381 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1382 }
1383
1384 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001385 "JACKDET rise", arizona_jackdet, info);
1386 if (ret != 0) {
1387 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1388 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001389 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001390 }
1391
Mark Brown92a49872013-01-11 08:55:39 +09001392 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001393 if (ret != 0) {
1394 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1395 ret);
1396 goto err_rise;
1397 }
1398
Mark Brown92a49872013-01-11 08:55:39 +09001399 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001400 "JACKDET fall", arizona_jackdet, info);
1401 if (ret != 0) {
1402 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1403 goto err_rise_wake;
1404 }
1405
Mark Brown92a49872013-01-11 08:55:39 +09001406 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001407 if (ret != 0) {
1408 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1409 ret);
1410 goto err_fall;
1411 }
1412
1413 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1414 "MICDET", arizona_micdet, info);
1415 if (ret != 0) {
1416 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1417 goto err_fall_wake;
1418 }
1419
Mark Brown4f340332013-01-11 08:55:43 +09001420 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1421 "HPDET", arizona_hpdet_irq, info);
1422 if (ret != 0) {
1423 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1424 goto err_micdet;
1425 }
1426
Mark Brownf2c32a82012-06-24 12:09:45 +01001427 arizona_clk32k_enable(arizona);
1428 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1429 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1430 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1431 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1432
Mark Brownb8575a12012-09-07 17:01:15 +08001433 ret = regulator_allow_bypass(info->micvdd, true);
1434 if (ret != 0)
1435 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1436 ret);
1437
Mark Brownf2c32a82012-06-24 12:09:45 +01001438 pm_runtime_put(&pdev->dev);
1439
Mark Brown34efe4d2012-07-20 17:07:29 +01001440 ret = input_register_device(info->input);
1441 if (ret) {
1442 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001443 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001444 }
1445
Mark Brownf2c32a82012-06-24 12:09:45 +01001446 return 0;
1447
Mark Brown4f340332013-01-11 08:55:43 +09001448err_hpdet:
1449 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001450err_micdet:
1451 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001452err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001453 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001454err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001455 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001456err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001457 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001458err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001459 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001460err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001461err_register:
1462 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001463 return ret;
1464}
1465
Bill Pemberton93ed0322012-11-19 13:25:49 -05001466static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001467{
1468 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1469 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001470 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001471
1472 pm_runtime_disable(&pdev->dev);
1473
Mark Browndab63eb2013-01-11 08:55:36 +09001474 regmap_update_bits(arizona->regmap,
1475 ARIZONA_MICD_CLAMP_CONTROL,
1476 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1477
Mark Brown92a49872013-01-11 08:55:39 +09001478 if (arizona->pdata.jd_gpio5) {
1479 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1480 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1481 } else {
1482 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1483 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1484 }
1485
1486 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1487 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1488 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001489 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001490 arizona_free_irq(arizona, jack_irq_rise, info);
1491 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001492 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001493 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1494 ARIZONA_JD1_ENA, 0);
1495 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001496
1497 return 0;
1498}
1499
1500static struct platform_driver arizona_extcon_driver = {
1501 .driver = {
1502 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001503 },
1504 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001505 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001506};
1507
1508module_platform_driver(arizona_extcon_driver);
1509
1510MODULE_DESCRIPTION("Arizona Extcon driver");
1511MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1512MODULE_LICENSE("GPL");
1513MODULE_ALIAS("platform:extcon-arizona");