blob: 7af42cb72e542d45dcf9db3a7b00e489f3e20d88 [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
Charles Keepax4778d442015-06-19 17:23:30 +01001131 device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
1132 &pdata->micd_detect_debounce);
1133
1134 device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
1135 &pdata->micd_bias_start_time);
1136
1137 device_property_read_u32(arizona->dev, "wlf,micd-rate",
1138 &pdata->micd_rate);
1139
1140 device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
1141 &pdata->micd_dbtime);
1142
1143 device_property_read_u32(arizona->dev, "wlf,micd-timeout",
1144 &pdata->micd_timeout);
1145
1146 pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
1147 "wlf,micd-force-micbias");
1148
Inha Song9e86b2a2015-05-04 13:42:13 +09001149 return 0;
1150}
1151
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001152static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001153{
1154 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001155 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001156 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001157 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001158 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001159 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001160 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001161
Mark Brownbbbd46e2013-01-10 19:38:43 +00001162 if (!arizona->dapm || !arizona->dapm->card)
1163 return -EPROBE_DEFER;
1164
Mark Brownf2c32a82012-06-24 12:09:45 +01001165 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001166 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001167 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001168
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001169 if (!dev_get_platdata(arizona->dev))
1170 arizona_extcon_device_get_pdata(arizona);
Inha Song9e86b2a2015-05-04 13:42:13 +09001171
Charles Keepax17271f62014-07-18 12:59:00 +01001172 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001173 if (IS_ERR(info->micvdd)) {
1174 ret = PTR_ERR(info->micvdd);
1175 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001176 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001177 }
1178
1179 mutex_init(&info->lock);
1180 info->arizona = arizona;
1181 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001182 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001183 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001184 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001185 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001186 platform_set_drvdata(pdev, info);
1187
1188 switch (arizona->type) {
1189 case WM5102:
1190 switch (arizona->rev) {
1191 case 0:
1192 info->micd_reva = true;
1193 break;
1194 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001195 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001196 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001197 break;
1198 }
1199 break;
Charles Keepax77438612013-11-14 16:18:25 +00001200 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001201 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001202 switch (arizona->rev) {
1203 case 0 ... 2:
1204 break;
1205 default:
1206 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001207 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001208 break;
1209 }
1210 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001211 default:
1212 break;
1213 }
1214
Chanwoo Choief70a212014-04-21 20:47:31 +09001215 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1216 if (IS_ERR(info->edev)) {
1217 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1218 return -ENOMEM;
1219 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001220
Chanwoo Choief70a212014-04-21 20:47:31 +09001221 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001222 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001223 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001224 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001225 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001226 }
1227
Mark Brown6fed4d82013-04-01 22:03:06 +01001228 info->input = devm_input_allocate_device(&pdev->dev);
1229 if (!info->input) {
1230 dev_err(arizona->dev, "Can't allocate input dev\n");
1231 ret = -ENOMEM;
1232 goto err_register;
1233 }
1234
1235 info->input->name = "Headset";
1236 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001237
Mark Brownf2c32a82012-06-24 12:09:45 +01001238 if (pdata->num_micd_configs) {
1239 info->micd_modes = pdata->micd_configs;
1240 info->micd_num_modes = pdata->num_micd_configs;
1241 } else {
1242 info->micd_modes = micd_default_modes;
1243 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1244 }
1245
1246 if (arizona->pdata.micd_pol_gpio > 0) {
1247 if (info->micd_modes[0].gpio)
1248 mode = GPIOF_OUT_INIT_HIGH;
1249 else
1250 mode = GPIOF_OUT_INIT_LOW;
1251
1252 ret = devm_gpio_request_one(&pdev->dev,
1253 arizona->pdata.micd_pol_gpio,
1254 mode,
1255 "MICD polarity");
1256 if (ret != 0) {
1257 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1258 arizona->pdata.micd_pol_gpio, ret);
1259 goto err_register;
1260 }
1261 }
1262
Mark Brown1eda6aa2013-01-11 08:55:54 +09001263 if (arizona->pdata.hpdet_id_gpio > 0) {
1264 ret = devm_gpio_request_one(&pdev->dev,
1265 arizona->pdata.hpdet_id_gpio,
1266 GPIOF_OUT_INIT_LOW,
1267 "HPDET");
1268 if (ret != 0) {
1269 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1270 arizona->pdata.hpdet_id_gpio, ret);
1271 goto err_register;
1272 }
1273 }
1274
Mark Brownb17e5462013-01-11 08:55:24 +09001275 if (arizona->pdata.micd_bias_start_time)
1276 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1277 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1278 arizona->pdata.micd_bias_start_time
1279 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1280
Mark Brown2e033db2013-01-21 17:36:33 +09001281 if (arizona->pdata.micd_rate)
1282 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1283 ARIZONA_MICD_RATE_MASK,
1284 arizona->pdata.micd_rate
1285 << ARIZONA_MICD_RATE_SHIFT);
1286
1287 if (arizona->pdata.micd_dbtime)
1288 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1289 ARIZONA_MICD_DBTIME_MASK,
1290 arizona->pdata.micd_dbtime
1291 << ARIZONA_MICD_DBTIME_SHIFT);
1292
Mark Brown6fed4d82013-04-01 22:03:06 +01001293 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1294
1295 if (arizona->pdata.num_micd_ranges) {
1296 info->micd_ranges = pdata->micd_ranges;
1297 info->num_micd_ranges = pdata->num_micd_ranges;
1298 } else {
1299 info->micd_ranges = micd_default_ranges;
1300 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1301 }
1302
1303 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1304 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1305 arizona->pdata.num_micd_ranges);
1306 }
1307
1308 if (info->num_micd_ranges > 1) {
1309 for (i = 1; i < info->num_micd_ranges; i++) {
1310 if (info->micd_ranges[i - 1].max >
1311 info->micd_ranges[i].max) {
1312 dev_err(arizona->dev,
1313 "MICD ranges must be sorted\n");
1314 ret = -EINVAL;
1315 goto err_input;
1316 }
1317 }
1318 }
1319
1320 /* Disable all buttons by default */
1321 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1322 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1323
1324 /* Set up all the buttons the user specified */
1325 for (i = 0; i < info->num_micd_ranges; i++) {
1326 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1327 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1328 break;
1329
1330 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1331 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1332 info->micd_ranges[i].max);
1333 ret = -EINVAL;
1334 goto err_input;
1335 }
1336
1337 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1338 arizona_micd_levels[j], i);
1339
1340 arizona_micd_set_level(arizona, i, j);
1341 input_set_capability(info->input, EV_KEY,
1342 info->micd_ranges[i].key);
1343
1344 /* Enable reporting of that range */
1345 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1346 1 << i, 1 << i);
1347 }
1348
1349 /* Set all the remaining keys to a maximum */
1350 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1351 arizona_micd_set_level(arizona, i, 0x3f);
1352
Mark Browndab63eb2013-01-11 08:55:36 +09001353 /*
Mark Brown92a49872013-01-11 08:55:39 +09001354 * If we have a clamp use it, activating in conjunction with
1355 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001356 */
1357 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001358 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001359 /* Put the GPIO into input mode with optional pull */
1360 val = 0xc101;
1361 if (arizona->pdata.jd_gpio5_nopull)
1362 val &= ~ARIZONA_GPN_PU;
1363
Mark Brown92a49872013-01-11 08:55:39 +09001364 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001365 val);
Mark Brown92a49872013-01-11 08:55:39 +09001366
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001367 if (arizona->pdata.jd_invert)
1368 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1369 else
1370 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001371 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001372 if (arizona->pdata.jd_invert)
1373 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1374 else
1375 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001376 }
1377
Mark Browndab63eb2013-01-11 08:55:36 +09001378 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001379 ARIZONA_MICD_CLAMP_CONTROL,
1380 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1381
1382 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001383 ARIZONA_JACK_DETECT_DEBOUNCE,
1384 ARIZONA_MICD_CLAMP_DB,
1385 ARIZONA_MICD_CLAMP_DB);
1386 }
1387
Mark Brownf2c32a82012-06-24 12:09:45 +01001388 arizona_extcon_set_mode(info, 0);
1389
1390 pm_runtime_enable(&pdev->dev);
1391 pm_runtime_idle(&pdev->dev);
1392 pm_runtime_get_sync(&pdev->dev);
1393
Mark Brown92a49872013-01-11 08:55:39 +09001394 if (arizona->pdata.jd_gpio5) {
1395 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1396 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1397 } else {
1398 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1399 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1400 }
1401
1402 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001403 "JACKDET rise", arizona_jackdet, info);
1404 if (ret != 0) {
1405 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1406 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001407 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001408 }
1409
Mark Brown92a49872013-01-11 08:55:39 +09001410 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001411 if (ret != 0) {
1412 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1413 ret);
1414 goto err_rise;
1415 }
1416
Mark Brown92a49872013-01-11 08:55:39 +09001417 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001418 "JACKDET fall", arizona_jackdet, info);
1419 if (ret != 0) {
1420 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1421 goto err_rise_wake;
1422 }
1423
Mark Brown92a49872013-01-11 08:55:39 +09001424 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001425 if (ret != 0) {
1426 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1427 ret);
1428 goto err_fall;
1429 }
1430
1431 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1432 "MICDET", arizona_micdet, info);
1433 if (ret != 0) {
1434 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1435 goto err_fall_wake;
1436 }
1437
Mark Brown4f340332013-01-11 08:55:43 +09001438 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1439 "HPDET", arizona_hpdet_irq, info);
1440 if (ret != 0) {
1441 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1442 goto err_micdet;
1443 }
1444
Mark Brownf2c32a82012-06-24 12:09:45 +01001445 arizona_clk32k_enable(arizona);
1446 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1447 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1448 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1449 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1450
Mark Brownb8575a12012-09-07 17:01:15 +08001451 ret = regulator_allow_bypass(info->micvdd, true);
1452 if (ret != 0)
1453 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1454 ret);
1455
Mark Brownf2c32a82012-06-24 12:09:45 +01001456 pm_runtime_put(&pdev->dev);
1457
Mark Brown34efe4d2012-07-20 17:07:29 +01001458 ret = input_register_device(info->input);
1459 if (ret) {
1460 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001461 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001462 }
1463
Mark Brownf2c32a82012-06-24 12:09:45 +01001464 return 0;
1465
Mark Brown4f340332013-01-11 08:55:43 +09001466err_hpdet:
1467 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001468err_micdet:
1469 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001470err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001471 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001472err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001473 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001474err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001475 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001476err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001477 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001478err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001479err_register:
1480 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001481 return ret;
1482}
1483
Bill Pemberton93ed0322012-11-19 13:25:49 -05001484static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001485{
1486 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1487 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001488 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001489
1490 pm_runtime_disable(&pdev->dev);
1491
Mark Browndab63eb2013-01-11 08:55:36 +09001492 regmap_update_bits(arizona->regmap,
1493 ARIZONA_MICD_CLAMP_CONTROL,
1494 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1495
Mark Brown92a49872013-01-11 08:55:39 +09001496 if (arizona->pdata.jd_gpio5) {
1497 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1498 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1499 } else {
1500 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1501 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1502 }
1503
1504 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1505 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1506 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001507 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001508 arizona_free_irq(arizona, jack_irq_rise, info);
1509 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001510 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001511 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1512 ARIZONA_JD1_ENA, 0);
1513 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001514
1515 return 0;
1516}
1517
1518static struct platform_driver arizona_extcon_driver = {
1519 .driver = {
1520 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001521 },
1522 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001523 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001524};
1525
1526module_platform_driver(arizona_extcon_driver);
1527
1528MODULE_DESCRIPTION("Arizona Extcon driver");
1529MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1530MODULE_LICENSE("GPL");
1531MODULE_ALIAS("platform:extcon-arizona");