blob: 830c5f94bc189ed3cced7a4dd02f93b490046f84 [file] [log] [blame]
Mark Brownf2c32a82012-06-24 12:09:45 +01001/*
2 * extcon-arizona.c - Extcon driver Wolfson Arizona devices
3 *
4 * Copyright (C) 2012 Wolfson Microelectronics plc
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/i2c.h>
20#include <linux/slab.h>
21#include <linux/interrupt.h>
22#include <linux/err.h>
23#include <linux/gpio.h>
Mark Brown34efe4d2012-07-20 17:07:29 +010024#include <linux/input.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010025#include <linux/platform_device.h>
26#include <linux/pm_runtime.h>
27#include <linux/regulator/consumer.h>
28#include <linux/extcon.h>
29
Mark Brownbbbd46e2013-01-10 19:38:43 +000030#include <sound/soc.h>
31
Mark Brownf2c32a82012-06-24 12:09:45 +010032#include <linux/mfd/arizona/core.h>
33#include <linux/mfd/arizona/pdata.h>
34#include <linux/mfd/arizona/registers.h>
35
Mark Brown6fed4d82013-04-01 22:03:06 +010036#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010037
Mark Brown4f340332013-01-11 08:55:43 +090038#define ARIZONA_ACCDET_MODE_MIC 0
39#define ARIZONA_ACCDET_MODE_HPL 1
40#define ARIZONA_ACCDET_MODE_HPR 2
41
Richard Fitzgeralda288d642014-05-23 12:54:57 +010042#define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
43#define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
44#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
45#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
46
Mark Brown9dd5e532013-04-01 19:09:45 +010047#define ARIZONA_HPDET_MAX 10000
48
Mark Brown2643fd62013-04-01 19:07:28 +010049#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010050#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010051
Charles Keepaxffae24f2013-11-14 16:18:21 +000052#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
53 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
54 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
55 ARIZONA_MICD_LVL_7)
56
57#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
58
59#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
60
Mark Brownf2c32a82012-06-24 12:09:45 +010061struct arizona_extcon_info {
62 struct device *dev;
63 struct arizona *arizona;
64 struct mutex lock;
65 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010066 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010067
Mark Browna3e20782013-04-01 19:05:27 +010068 u16 last_jackdet;
69
Mark Brownf2c32a82012-06-24 12:09:45 +010070 int micd_mode;
71 const struct arizona_micd_config *micd_modes;
72 int micd_num_modes;
73
Mark Brown6fed4d82013-04-01 22:03:06 +010074 const struct arizona_micd_range *micd_ranges;
75 int num_micd_ranges;
76
Mark Brown7abd4e22013-04-01 19:25:55 +010077 int micd_timeout;
78
Mark Brownf2c32a82012-06-24 12:09:45 +010079 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090080 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010081
Mark Brown0e27bd32013-02-05 21:00:15 +000082 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010083 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010084 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000085
Mark Brown4f340332013-01-11 08:55:43 +090086 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000087 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010088 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090089
Mark Browndd235ee2013-01-11 08:55:51 +090090 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090091 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090092
Mark Brownf2c32a82012-06-24 12:09:45 +010093 bool mic;
94 bool detecting;
95 int jack_flips;
96
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +010097 int hpdet_ip_version;
Mark Brown4f340332013-01-11 08:55:43 +090098
Chanwoo Choief70a212014-04-21 20:47:31 +090099 struct extcon_dev *edev;
Mark Brownf2c32a82012-06-24 12:09:45 +0100100};
101
102static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +0100103 { ARIZONA_ACCDET_SRC, 1, 0 },
104 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100105};
106
Mark Brown6fed4d82013-04-01 22:03:06 +0100107static const struct arizona_micd_range micd_default_ranges[] = {
108 { .max = 11, .key = BTN_0 },
109 { .max = 28, .key = BTN_1 },
110 { .max = 54, .key = BTN_2 },
111 { .max = 100, .key = BTN_3 },
112 { .max = 186, .key = BTN_4 },
113 { .max = 430, .key = BTN_5 },
114};
115
116static const int arizona_micd_levels[] = {
117 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
118 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
119 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
120 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
121 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100122};
123
Mark Brown325c6422012-06-28 13:08:30 +0100124#define ARIZONA_CABLE_MECHANICAL 0
125#define ARIZONA_CABLE_MICROPHONE 1
126#define ARIZONA_CABLE_HEADPHONE 2
Mark Brown4f340332013-01-11 08:55:43 +0900127#define ARIZONA_CABLE_LINEOUT 3
Mark Brownf2c32a82012-06-24 12:09:45 +0100128
129static const char *arizona_cable[] = {
Mark Brown325c6422012-06-28 13:08:30 +0100130 "Mechanical",
131 "Microphone",
132 "Headphone",
Mark Brown4f340332013-01-11 08:55:43 +0900133 "Line-out",
Mark Brownf2c32a82012-06-24 12:09:45 +0100134 NULL,
135};
136
Mark Brown9dd5e532013-04-01 19:09:45 +0100137static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
138
Charles Keepax112bdfa2015-02-16 15:41:02 +0000139static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
140 bool clamp)
Mark Brown03409072013-02-12 13:00:31 +0000141{
142 struct arizona *arizona = info->arizona;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000143 unsigned int mask = 0, val = 0;
Mark Brown03409072013-02-12 13:00:31 +0000144 int ret;
145
Charles Keepax43f0acd2015-02-16 15:41:03 +0000146 switch (arizona->type) {
147 case WM5110:
148 mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
149 ARIZONA_HP1L_SHRTI;
150 if (clamp)
151 val = ARIZONA_HP1L_SHRTO;
152 else
153 val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
154 break;
155 default:
156 mask = ARIZONA_RMV_SHRT_HP1L;
157 if (clamp)
158 val = ARIZONA_RMV_SHRT_HP1L;
159 break;
160 };
Charles Keepax112bdfa2015-02-16 15:41:02 +0000161
Mark Brown03409072013-02-12 13:00:31 +0000162 mutex_lock(&arizona->dapm->card->dapm_mutex);
163
Charles Keepax112bdfa2015-02-16 15:41:02 +0000164 arizona->hpdet_clamp = clamp;
Mark Browndf8c3db2013-02-22 18:38:03 +0000165
Charles Keepax112bdfa2015-02-16 15:41:02 +0000166 /* Keep the HP output stages disabled while doing the clamp */
167 if (clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000168 ret = regmap_update_bits(arizona->regmap,
169 ARIZONA_OUTPUT_ENABLES_1,
170 ARIZONA_OUT1L_ENA |
171 ARIZONA_OUT1R_ENA, 0);
172 if (ret != 0)
173 dev_warn(arizona->dev,
174 "Failed to disable headphone outputs: %d\n",
175 ret);
Mark Brown03409072013-02-12 13:00:31 +0000176 }
177
Charles Keepax112bdfa2015-02-16 15:41:02 +0000178 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
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 Brown03409072013-02-12 13:00:31 +0000182 ret);
183
Charles Keepax112bdfa2015-02-16 15:41:02 +0000184 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
Charles Keepax43f0acd2015-02-16 15:41:03 +0000185 mask, val);
Mark Browndf8c3db2013-02-22 18:38:03 +0000186 if (ret != 0)
Charles Keepax112bdfa2015-02-16 15:41:02 +0000187 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Browndf8c3db2013-02-22 18:38:03 +0000188 ret);
189
Charles Keepax112bdfa2015-02-16 15:41:02 +0000190 /* Restore the desired state while not doing the clamp */
191 if (!clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000192 ret = regmap_update_bits(arizona->regmap,
193 ARIZONA_OUTPUT_ENABLES_1,
194 ARIZONA_OUT1L_ENA |
195 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000196 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000197 dev_warn(arizona->dev,
198 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000199 ret);
200 }
201
202 mutex_unlock(&arizona->dapm->card->dapm_mutex);
203}
204
Mark Brownf2c32a82012-06-24 12:09:45 +0100205static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
206{
207 struct arizona *arizona = info->arizona;
208
Mark Brown6fed4d82013-04-01 22:03:06 +0100209 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800210
Mark Browncd74f7b2012-11-27 16:14:26 +0900211 if (arizona->pdata.micd_pol_gpio > 0)
212 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
213 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100214 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
215 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100216 info->micd_modes[mode].bias <<
217 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100218 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
219 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
220
221 info->micd_mode = mode;
222
223 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
224}
225
Mark Brownbbbd46e2013-01-10 19:38:43 +0000226static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
227{
Charles Keepax41024242013-09-23 14:33:59 +0100228 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000229 case 1:
230 return "MICBIAS1";
231 case 2:
232 return "MICBIAS2";
233 case 3:
234 return "MICBIAS3";
235 default:
236 return "MICVDD";
237 }
238}
239
240static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
241{
242 struct arizona *arizona = info->arizona;
243 const char *widget = arizona_extcon_get_micbias(info);
244 struct snd_soc_dapm_context *dapm = arizona->dapm;
245 int ret;
246
Mark Brownbbbd46e2013-01-10 19:38:43 +0000247 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
248 if (ret != 0)
249 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
250 widget, ret);
251
Mark Brownbbbd46e2013-01-10 19:38:43 +0000252 snd_soc_dapm_sync(dapm);
253
254 if (!arizona->pdata.micd_force_micbias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000255 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
256 if (ret != 0)
257 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
258 widget, ret);
259
Mark Brownbbbd46e2013-01-10 19:38:43 +0000260 snd_soc_dapm_sync(dapm);
261 }
262}
263
Mark Brown9b1270c2013-01-11 08:55:46 +0900264static void arizona_start_mic(struct arizona_extcon_info *info)
265{
266 struct arizona *arizona = info->arizona;
267 bool change;
268 int ret;
269
Mark Brown9b1270c2013-01-11 08:55:46 +0900270 /* Microphone detection can't use idle mode */
271 pm_runtime_get(info->dev);
272
Mark Brownbbbd46e2013-01-10 19:38:43 +0000273 if (info->detecting) {
274 ret = regulator_allow_bypass(info->micvdd, false);
275 if (ret != 0) {
276 dev_err(arizona->dev,
277 "Failed to regulate MICVDD: %d\n",
278 ret);
279 }
280 }
281
Mark Brown9b1270c2013-01-11 08:55:46 +0900282 ret = regulator_enable(info->micvdd);
283 if (ret != 0) {
284 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
285 ret);
286 }
287
288 if (info->micd_reva) {
289 regmap_write(arizona->regmap, 0x80, 0x3);
290 regmap_write(arizona->regmap, 0x294, 0);
291 regmap_write(arizona->regmap, 0x80, 0x0);
292 }
293
294 regmap_update_bits(arizona->regmap,
295 ARIZONA_ACCESSORY_DETECT_MODE_1,
296 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
297
Mark Brownbbbd46e2013-01-10 19:38:43 +0000298 arizona_extcon_pulse_micbias(info);
299
Mark Brown9b1270c2013-01-11 08:55:46 +0900300 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
301 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
302 &change);
303 if (!change) {
304 regulator_disable(info->micvdd);
305 pm_runtime_put_autosuspend(info->dev);
306 }
307}
308
309static void arizona_stop_mic(struct arizona_extcon_info *info)
310{
311 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000312 const char *widget = arizona_extcon_get_micbias(info);
313 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900314 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000315 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900316
317 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
318 ARIZONA_MICD_ENA, 0,
319 &change);
320
Mark Brownbbbd46e2013-01-10 19:38:43 +0000321 ret = snd_soc_dapm_disable_pin(dapm, widget);
322 if (ret != 0)
323 dev_warn(arizona->dev,
324 "Failed to disable %s: %d\n",
325 widget, ret);
326
Mark Brownbbbd46e2013-01-10 19:38:43 +0000327 snd_soc_dapm_sync(dapm);
328
Mark Brown9b1270c2013-01-11 08:55:46 +0900329 if (info->micd_reva) {
330 regmap_write(arizona->regmap, 0x80, 0x3);
331 regmap_write(arizona->regmap, 0x294, 2);
332 regmap_write(arizona->regmap, 0x80, 0x0);
333 }
334
Mark Brownbbbd46e2013-01-10 19:38:43 +0000335 ret = regulator_allow_bypass(info->micvdd, true);
336 if (ret != 0) {
337 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
338 ret);
339 }
340
Mark Brown9b1270c2013-01-11 08:55:46 +0900341 if (change) {
342 regulator_disable(info->micvdd);
343 pm_runtime_mark_last_busy(info->dev);
344 pm_runtime_put_autosuspend(info->dev);
345 }
346}
347
Mark Brown4f340332013-01-11 08:55:43 +0900348static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100349 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900350 unsigned int factor_a;
351 unsigned int factor_b;
352} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100353 { 100, 5528, 362464 },
354 { 169, 11084, 6186851 },
355 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900356};
357
Charles Keepax24a279b2014-05-30 13:19:17 +0100358#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
359
Mark Brown4f340332013-01-11 08:55:43 +0900360static struct {
361 int min;
362 int max;
363} arizona_hpdet_c_ranges[] = {
364 { 0, 30 },
365 { 8, 100 },
366 { 100, 1000 },
367 { 1000, 10000 },
368};
369
370static int arizona_hpdet_read(struct arizona_extcon_info *info)
371{
372 struct arizona *arizona = info->arizona;
373 unsigned int val, range;
374 int ret;
375
376 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
377 if (ret != 0) {
378 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
379 ret);
380 return ret;
381 }
382
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100383 switch (info->hpdet_ip_version) {
Mark Brown4f340332013-01-11 08:55:43 +0900384 case 0:
385 if (!(val & ARIZONA_HP_DONE)) {
386 dev_err(arizona->dev, "HPDET did not complete: %x\n",
387 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900388 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900389 }
390
391 val &= ARIZONA_HP_LVL_MASK;
392 break;
393
394 case 1:
395 if (!(val & ARIZONA_HP_DONE_B)) {
396 dev_err(arizona->dev, "HPDET did not complete: %x\n",
397 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900398 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900399 }
400
401 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
402 if (ret != 0) {
403 dev_err(arizona->dev, "Failed to read HP value: %d\n",
404 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900405 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900406 }
407
408 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
409 &range);
410 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
411 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
412
413 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100414 (val < arizona_hpdet_b_ranges[range].threshold ||
415 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900416 range++;
417 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
418 range);
419 regmap_update_bits(arizona->regmap,
420 ARIZONA_HEADPHONE_DETECT_1,
421 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
422 range <<
423 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
424 return -EAGAIN;
425 }
426
427 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100428 if (val < arizona_hpdet_b_ranges[range].threshold ||
429 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900430 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100431 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900432 }
433
434 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
435 val, range);
436
437 val = arizona_hpdet_b_ranges[range].factor_b
438 / ((val * 100) -
439 arizona_hpdet_b_ranges[range].factor_a);
440 break;
441
442 default:
443 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100444 info->hpdet_ip_version);
Mark Brown4f340332013-01-11 08:55:43 +0900445 case 2:
446 if (!(val & ARIZONA_HP_DONE_B)) {
447 dev_err(arizona->dev, "HPDET did not complete: %x\n",
448 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900449 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900450 }
451
452 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000453 /* Convert to ohms, the value is in 0.5 ohm increments */
454 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900455
456 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
457 &range);
458 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
459 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
460
Charles Keepax91414612013-11-14 16:18:24 +0000461 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900462 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
463 (val >= arizona_hpdet_c_ranges[range].max)) {
464 range++;
465 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
466 arizona_hpdet_c_ranges[range].min,
467 arizona_hpdet_c_ranges[range].max);
468 regmap_update_bits(arizona->regmap,
469 ARIZONA_HEADPHONE_DETECT_1,
470 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
471 range <<
472 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
473 return -EAGAIN;
474 }
Charles Keepax91414612013-11-14 16:18:24 +0000475
476 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
477 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
478 arizona_hpdet_c_ranges[range].min);
479 val = arizona_hpdet_c_ranges[range].min;
480 }
Mark Brown4f340332013-01-11 08:55:43 +0900481 }
482
483 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
484 return val;
485}
486
Mark Brown9c2ba272013-02-25 23:42:31 +0000487static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
488 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900489{
490 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900491 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900492
493 /*
494 * If we're using HPDET for accessory identification we need
495 * to take multiple measurements, step through them in sequence.
496 */
497 if (arizona->pdata.hpdet_acc_id) {
498 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900499
500 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000501 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900502 dev_dbg(arizona->dev, "Measuring mic\n");
503
504 regmap_update_bits(arizona->regmap,
505 ARIZONA_ACCESSORY_DETECT_MODE_1,
506 ARIZONA_ACCDET_MODE_MASK |
507 ARIZONA_ACCDET_SRC,
508 ARIZONA_ACCDET_MODE_HPR |
509 info->micd_modes[0].src);
510
511 gpio_set_value_cansleep(id_gpio, 1);
512
Mark Browndd235ee2013-01-11 08:55:51 +0900513 regmap_update_bits(arizona->regmap,
514 ARIZONA_HEADPHONE_DETECT_1,
515 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
516 return -EAGAIN;
517 }
518
519 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000520 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
521 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000522
523 /* Take the headphone impedance for the main report */
524 *reading = info->hpdet_res[0];
525
Mark Brown9dd5e532013-04-01 19:09:45 +0100526 /* Sometimes we get false readings due to slow insert */
527 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
528 dev_dbg(arizona->dev, "Retrying high impedance\n");
529 info->num_hpdet_res = 0;
530 info->hpdet_retried = true;
531 arizona_start_hpdet_acc_id(info);
532 pm_runtime_put(info->dev);
533 return -EAGAIN;
534 }
535
Mark Brown1eda6aa2013-01-11 08:55:54 +0900536 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530537 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900538 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000539 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900540 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000541 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000542 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900543 } else {
544 dev_dbg(arizona->dev, "Detected headphone\n");
545 }
546
547 /* Make sure everything is reset back to the real polarity */
548 regmap_update_bits(arizona->regmap,
549 ARIZONA_ACCESSORY_DETECT_MODE_1,
550 ARIZONA_ACCDET_SRC,
551 info->micd_modes[0].src);
552 }
553
554 return 0;
555}
556
Mark Brown4f340332013-01-11 08:55:43 +0900557static irqreturn_t arizona_hpdet_irq(int irq, void *data)
558{
559 struct arizona_extcon_info *info = data;
560 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900561 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900562 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900563 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000564 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900565
566 mutex_lock(&info->lock);
567
568 /* If we got a spurious IRQ for some reason then ignore it */
569 if (!info->hpdet_active) {
570 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
571 mutex_unlock(&info->lock);
572 return IRQ_NONE;
573 }
574
575 /* If the cable was removed while measuring ignore the result */
Chanwoo Choief70a212014-04-21 20:47:31 +0900576 ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900577 if (ret < 0) {
578 dev_err(arizona->dev, "Failed to check cable state: %d\n",
579 ret);
580 goto out;
581 } else if (!ret) {
582 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
583 goto done;
584 }
585
586 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900587 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900588 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900589 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900590 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900591 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900592
593 /* Reset back to starting range */
594 regmap_update_bits(arizona->regmap,
595 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900596 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
597 0);
598
Mark Brown9c2ba272013-02-25 23:42:31 +0000599 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900600 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900601 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900602 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900603 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900604
605 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900606 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900607 report = ARIZONA_CABLE_LINEOUT;
608 else
609 report = ARIZONA_CABLE_HEADPHONE;
610
Chanwoo Choief70a212014-04-21 20:47:31 +0900611 ret = extcon_set_cable_state_(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900612 if (ret != 0)
613 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
614 ret);
615
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000616done:
617 /* Reset back to starting range */
618 regmap_update_bits(arizona->regmap,
619 ARIZONA_HEADPHONE_DETECT_1,
620 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
621 0);
622
Charles Keepax112bdfa2015-02-16 15:41:02 +0000623 arizona_extcon_hp_clamp(info, false);
Mark Brown4f340332013-01-11 08:55:43 +0900624
Mark Brown1eda6aa2013-01-11 08:55:54 +0900625 if (id_gpio)
626 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900627
628 /* Revert back to MICDET mode */
629 regmap_update_bits(arizona->regmap,
630 ARIZONA_ACCESSORY_DETECT_MODE_1,
631 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
632
633 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000634 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900635 arizona_start_mic(info);
636
637 if (info->hpdet_active) {
638 pm_runtime_put_autosuspend(info->dev);
639 info->hpdet_active = false;
640 }
641
Mark Brownbf14ee52013-02-05 20:20:17 +0000642 info->hpdet_done = true;
643
Mark Brown4f340332013-01-11 08:55:43 +0900644out:
645 mutex_unlock(&info->lock);
646
647 return IRQ_HANDLED;
648}
649
650static void arizona_identify_headphone(struct arizona_extcon_info *info)
651{
652 struct arizona *arizona = info->arizona;
653 int ret;
654
Mark Brownbf14ee52013-02-05 20:20:17 +0000655 if (info->hpdet_done)
656 return;
657
Mark Brown4f340332013-01-11 08:55:43 +0900658 dev_dbg(arizona->dev, "Starting HPDET\n");
659
660 /* Make sure we keep the device enabled during the measurement */
661 pm_runtime_get(info->dev);
662
663 info->hpdet_active = true;
664
665 if (info->mic)
666 arizona_stop_mic(info);
667
Charles Keepax112bdfa2015-02-16 15:41:02 +0000668 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900669
670 ret = regmap_update_bits(arizona->regmap,
671 ARIZONA_ACCESSORY_DETECT_MODE_1,
672 ARIZONA_ACCDET_MODE_MASK,
673 ARIZONA_ACCDET_MODE_HPL);
674 if (ret != 0) {
675 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
676 goto err;
677 }
678
679 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
680 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
681 if (ret != 0) {
682 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
683 ret);
684 goto err;
685 }
686
687 return;
688
689err:
690 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
691 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
692
693 /* Just report headphone */
Nikesh Oswal34602482014-05-29 16:27:52 +0100694 ret = extcon_set_cable_state_(info->edev,
695 ARIZONA_CABLE_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900696 if (ret != 0)
697 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
698
699 if (info->mic)
700 arizona_start_mic(info);
701
702 info->hpdet_active = false;
703}
Mark Browndd235ee2013-01-11 08:55:51 +0900704
705static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
706{
707 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000708 int hp_reading = 32;
709 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900710 int ret;
711
712 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
713
714 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000715 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900716
717 info->hpdet_active = true;
718
Charles Keepax112bdfa2015-02-16 15:41:02 +0000719 arizona_extcon_hp_clamp(info, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900720
721 ret = regmap_update_bits(arizona->regmap,
722 ARIZONA_ACCESSORY_DETECT_MODE_1,
723 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
724 info->micd_modes[0].src |
725 ARIZONA_ACCDET_MODE_HPL);
726 if (ret != 0) {
727 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
728 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900729 }
730
Mark Brown9c2ba272013-02-25 23:42:31 +0000731 if (arizona->pdata.hpdet_acc_id_line) {
732 ret = regmap_update_bits(arizona->regmap,
733 ARIZONA_HEADPHONE_DETECT_1,
734 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
735 if (ret != 0) {
736 dev_err(arizona->dev,
737 "Can't start HPDETL measurement: %d\n",
738 ret);
739 goto err;
740 }
741 } else {
742 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900743 }
744
745 return;
746
747err:
748 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
749 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
750
751 /* Just report headphone */
Nikesh Oswal34602482014-05-29 16:27:52 +0100752 ret = extcon_set_cable_state_(info->edev,
753 ARIZONA_CABLE_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900754 if (ret != 0)
755 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
756
Mark Brown4f340332013-01-11 08:55:43 +0900757 info->hpdet_active = false;
758}
759
Mark Brown939c5672013-04-01 19:17:34 +0100760static void arizona_micd_timeout_work(struct work_struct *work)
761{
762 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900763 struct arizona_extcon_info,
764 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100765
766 mutex_lock(&info->lock);
767
768 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
769 arizona_identify_headphone(info);
770
771 info->detecting = false;
772
773 arizona_stop_mic(info);
774
775 mutex_unlock(&info->lock);
776}
777
Mark Browncd59e792013-04-01 19:21:48 +0100778static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100779{
Mark Browncd59e792013-04-01 19:21:48 +0100780 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900781 struct arizona_extcon_info,
782 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100783 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100784 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100785 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100786
Mark Brown939c5672013-04-01 19:17:34 +0100787 cancel_delayed_work_sync(&info->micd_timeout_work);
788
Mark Brownf2c32a82012-06-24 12:09:45 +0100789 mutex_lock(&info->lock);
790
Charles Keepax31a847e2013-11-14 16:18:23 +0000791 /* If the cable was removed while measuring ignore the result */
Chanwoo Choief70a212014-04-21 20:47:31 +0900792 ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000793 if (ret < 0) {
794 dev_err(arizona->dev, "Failed to check cable state: %d\n",
795 ret);
796 mutex_unlock(&info->lock);
797 return;
798 } else if (!ret) {
799 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
800 mutex_unlock(&info->lock);
801 return;
802 }
803
Charles Keepaxffae24f2013-11-14 16:18:21 +0000804 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100805 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
806 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900807 dev_err(arizona->dev,
808 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100809 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100810 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100811 }
812
813 dev_dbg(arizona->dev, "MICDET: %x\n", val);
814
815 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900816 dev_warn(arizona->dev,
817 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100818 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100819 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100820 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100821 }
822
Charles Keepaxffae24f2013-11-14 16:18:21 +0000823 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100824 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100825 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100826 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100827 }
828
829 /* Due to jack detect this should never happen */
830 if (!(val & ARIZONA_MICD_STS)) {
831 dev_warn(arizona->dev, "Detected open circuit\n");
832 info->detecting = false;
833 goto handled;
834 }
835
836 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000837 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Mark Brown4f340332013-01-11 08:55:43 +0900838 arizona_identify_headphone(info);
839
Nikesh Oswal34602482014-05-29 16:27:52 +0100840 ret = extcon_set_cable_state_(info->edev,
841 ARIZONA_CABLE_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100842
843 if (ret != 0)
844 dev_err(arizona->dev, "Headset report failed: %d\n",
845 ret);
846
Mark Brownbbbd46e2013-01-10 19:38:43 +0000847 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100848 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000849 if (ret != 0) {
850 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
851 ret);
852 }
853
Mark Brownf2c32a82012-06-24 12:09:45 +0100854 info->mic = true;
855 info->detecting = false;
856 goto handled;
857 }
858
859 /* If we detected a lower impedence during initial startup
860 * then we probably have the wrong polarity, flip it. Don't
861 * do this for the lowest impedences to speed up detection of
862 * plain headphones. If both polarities report a low
863 * impedence then give up and report headphones.
864 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000865 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800866 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900867 dev_dbg(arizona->dev, "Detected HP/line\n");
868 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100869
Mark Brown4f340332013-01-11 08:55:43 +0900870 info->detecting = false;
871
872 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100873 } else {
874 info->micd_mode++;
875 if (info->micd_mode == info->micd_num_modes)
876 info->micd_mode = 0;
877 arizona_extcon_set_mode(info, info->micd_mode);
878
879 info->jack_flips++;
880 }
881
882 goto handled;
883 }
884
885 /*
886 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100887 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100888 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000889 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100890 if (info->mic) {
891 dev_dbg(arizona->dev, "Mic button detected\n");
892
Mark Brown34efe4d2012-07-20 17:07:29 +0100893 lvl = val & ARIZONA_MICD_LVL_MASK;
894 lvl >>= ARIZONA_MICD_LVL_SHIFT;
895
Mark Brown41a57852013-04-01 19:18:18 +0100896 for (i = 0; i < info->num_micd_ranges; i++)
897 input_report_key(info->input,
898 info->micd_ranges[i].key, 0);
899
Mark Brown6fed4d82013-04-01 22:03:06 +0100900 WARN_ON(!lvl);
901 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
902 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
903 key = info->micd_ranges[ffs(lvl) - 1].key;
904 input_report_key(info->input, key, 1);
905 input_sync(info->input);
906 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100907
Mark Brownf2c32a82012-06-24 12:09:45 +0100908 } else if (info->detecting) {
909 dev_dbg(arizona->dev, "Headphone detected\n");
910 info->detecting = false;
911 arizona_stop_mic(info);
912
Mark Brown4f340332013-01-11 08:55:43 +0900913 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100914 } else {
915 dev_warn(arizona->dev, "Button with no mic: %x\n",
916 val);
917 }
918 } else {
919 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100920 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100921 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100922 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100923 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000924 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100925 }
926
927handled:
Mark Brown939c5672013-04-01 19:17:34 +0100928 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100929 queue_delayed_work(system_power_efficient_wq,
930 &info->micd_timeout_work,
931 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100932
Mark Brownf2c32a82012-06-24 12:09:45 +0100933 pm_runtime_mark_last_busy(info->dev);
934 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100935}
936
937static irqreturn_t arizona_micdet(int irq, void *data)
938{
939 struct arizona_extcon_info *info = data;
940 struct arizona *arizona = info->arizona;
941 int debounce = arizona->pdata.micd_detect_debounce;
942
943 cancel_delayed_work_sync(&info->micd_detect_work);
944 cancel_delayed_work_sync(&info->micd_timeout_work);
945
946 mutex_lock(&info->lock);
947 if (!info->detecting)
948 debounce = 0;
949 mutex_unlock(&info->lock);
950
951 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100952 queue_delayed_work(system_power_efficient_wq,
953 &info->micd_detect_work,
954 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100955 else
956 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100957
958 return IRQ_HANDLED;
959}
960
Mark Brown0e27bd32013-02-05 21:00:15 +0000961static void arizona_hpdet_work(struct work_struct *work)
962{
963 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900964 struct arizona_extcon_info,
965 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000966
967 mutex_lock(&info->lock);
968 arizona_start_hpdet_acc_id(info);
969 mutex_unlock(&info->lock);
970}
971
Mark Brownf2c32a82012-06-24 12:09:45 +0100972static irqreturn_t arizona_jackdet(int irq, void *data)
973{
974 struct arizona_extcon_info *info = data;
975 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900976 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100977 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100978 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100979
Mark Brown939c5672013-04-01 19:17:34 +0100980 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
981 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100982
Mark Browna3e20782013-04-01 19:05:27 +0100983 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000984
Mark Brownf2c32a82012-06-24 12:09:45 +0100985 mutex_lock(&info->lock);
986
Mark Brown92a49872013-01-11 08:55:39 +0900987 if (arizona->pdata.jd_gpio5) {
988 mask = ARIZONA_MICD_CLAMP_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100989 if (arizona->pdata.jd_invert)
990 present = ARIZONA_MICD_CLAMP_STS;
991 else
992 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +0900993 } else {
994 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100995 if (arizona->pdata.jd_invert)
996 present = 0;
997 else
998 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +0900999 }
1000
Mark Brownf2c32a82012-06-24 12:09:45 +01001001 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
1002 if (ret != 0) {
1003 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
1004 ret);
1005 mutex_unlock(&info->lock);
1006 pm_runtime_put_autosuspend(info->dev);
1007 return IRQ_NONE;
1008 }
1009
Mark Browna3e20782013-04-01 19:05:27 +01001010 val &= mask;
1011 if (val == info->last_jackdet) {
1012 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001013 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001014 queue_delayed_work(system_power_efficient_wq,
1015 &info->hpdet_work,
1016 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001017
Chanwoo Choic2275d22013-08-23 10:21:37 +09001018 if (cancelled_mic) {
1019 int micd_timeout = info->micd_timeout;
1020
Mark Browndf9a5ab2013-07-18 22:42:22 +01001021 queue_delayed_work(system_power_efficient_wq,
1022 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001023 msecs_to_jiffies(micd_timeout));
1024 }
Mark Brown939c5672013-04-01 19:17:34 +01001025
Mark Browna3e20782013-04-01 19:05:27 +01001026 goto out;
1027 }
1028 info->last_jackdet = val;
1029
1030 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001031 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choief70a212014-04-21 20:47:31 +09001032 ret = extcon_set_cable_state_(info->edev,
Mark Brown325c6422012-06-28 13:08:30 +01001033 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001034
1035 if (ret != 0)
1036 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1037 ret);
1038
Mark Browndd235ee2013-01-11 08:55:51 +09001039 if (!arizona->pdata.hpdet_acc_id) {
1040 info->detecting = true;
1041 info->mic = false;
1042 info->jack_flips = 0;
1043
1044 arizona_start_mic(info);
1045 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001046 queue_delayed_work(system_power_efficient_wq,
1047 &info->hpdet_work,
1048 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001049 }
Mark Brown4e616872013-01-15 22:09:20 +09001050
1051 regmap_update_bits(arizona->regmap,
1052 ARIZONA_JACK_DETECT_DEBOUNCE,
1053 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001054 } else {
1055 dev_dbg(arizona->dev, "Detected jack removal\n");
1056
1057 arizona_stop_mic(info);
1058
Mark Browndd235ee2013-01-11 08:55:51 +09001059 info->num_hpdet_res = 0;
1060 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1061 info->hpdet_res[i] = 0;
1062 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001063 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001064 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001065
Mark Brown6fed4d82013-04-01 22:03:06 +01001066 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001067 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001068 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001069 input_sync(info->input);
1070
Chanwoo Choief70a212014-04-21 20:47:31 +09001071 ret = extcon_update_state(info->edev, 0xffffffff, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001072 if (ret != 0)
1073 dev_err(arizona->dev, "Removal report failed: %d\n",
1074 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001075
1076 regmap_update_bits(arizona->regmap,
1077 ARIZONA_JACK_DETECT_DEBOUNCE,
1078 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1079 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001080 }
1081
Mark Brown7abd4e22013-04-01 19:25:55 +01001082 if (arizona->pdata.micd_timeout)
1083 info->micd_timeout = arizona->pdata.micd_timeout;
1084 else
1085 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1086
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001087out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001088 /* Clear trig_sts to make sure DCVDD is not forced up */
1089 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1090 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1091 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1092 ARIZONA_JD1_FALL_TRIG_STS |
1093 ARIZONA_JD1_RISE_TRIG_STS);
1094
Mark Brownf2c32a82012-06-24 12:09:45 +01001095 mutex_unlock(&info->lock);
1096
1097 pm_runtime_mark_last_busy(info->dev);
1098 pm_runtime_put_autosuspend(info->dev);
1099
1100 return IRQ_HANDLED;
1101}
1102
Mark Brown6fed4d82013-04-01 22:03:06 +01001103/* Map a level onto a slot in the register bank */
1104static void arizona_micd_set_level(struct arizona *arizona, int index,
1105 unsigned int level)
1106{
1107 int reg;
1108 unsigned int mask;
1109
1110 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1111
1112 if (!(index % 2)) {
1113 mask = 0x3f00;
1114 level <<= 8;
1115 } else {
1116 mask = 0x3f;
1117 }
1118
1119 /* Program the level itself */
1120 regmap_update_bits(arizona->regmap, reg, mask, level);
1121}
1122
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001123static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001124{
1125 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001126 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001127 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001128 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001129 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001130 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001131 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001132
Mark Brownbbbd46e2013-01-10 19:38:43 +00001133 if (!arizona->dapm || !arizona->dapm->card)
1134 return -EPROBE_DEFER;
1135
Mark Brownf2c32a82012-06-24 12:09:45 +01001136 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001137 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001138 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001139
Charles Keepax17271f62014-07-18 12:59:00 +01001140 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001141 if (IS_ERR(info->micvdd)) {
1142 ret = PTR_ERR(info->micvdd);
1143 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001144 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001145 }
1146
1147 mutex_init(&info->lock);
1148 info->arizona = arizona;
1149 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001150 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001151 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001152 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001153 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001154 platform_set_drvdata(pdev, info);
1155
1156 switch (arizona->type) {
1157 case WM5102:
1158 switch (arizona->rev) {
1159 case 0:
1160 info->micd_reva = true;
1161 break;
1162 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001163 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001164 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001165 break;
1166 }
1167 break;
Charles Keepax77438612013-11-14 16:18:25 +00001168 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001169 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001170 switch (arizona->rev) {
1171 case 0 ... 2:
1172 break;
1173 default:
1174 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001175 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001176 break;
1177 }
1178 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001179 default:
1180 break;
1181 }
1182
Chanwoo Choief70a212014-04-21 20:47:31 +09001183 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1184 if (IS_ERR(info->edev)) {
1185 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1186 return -ENOMEM;
1187 }
1188 info->edev->name = "Headset Jack";
Mark Brownf2c32a82012-06-24 12:09:45 +01001189
Chanwoo Choief70a212014-04-21 20:47:31 +09001190 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001191 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001192 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001193 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001194 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001195 }
1196
Mark Brown6fed4d82013-04-01 22:03:06 +01001197 info->input = devm_input_allocate_device(&pdev->dev);
1198 if (!info->input) {
1199 dev_err(arizona->dev, "Can't allocate input dev\n");
1200 ret = -ENOMEM;
1201 goto err_register;
1202 }
1203
1204 info->input->name = "Headset";
1205 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001206
Mark Brownf2c32a82012-06-24 12:09:45 +01001207 if (pdata->num_micd_configs) {
1208 info->micd_modes = pdata->micd_configs;
1209 info->micd_num_modes = pdata->num_micd_configs;
1210 } else {
1211 info->micd_modes = micd_default_modes;
1212 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1213 }
1214
1215 if (arizona->pdata.micd_pol_gpio > 0) {
1216 if (info->micd_modes[0].gpio)
1217 mode = GPIOF_OUT_INIT_HIGH;
1218 else
1219 mode = GPIOF_OUT_INIT_LOW;
1220
1221 ret = devm_gpio_request_one(&pdev->dev,
1222 arizona->pdata.micd_pol_gpio,
1223 mode,
1224 "MICD polarity");
1225 if (ret != 0) {
1226 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1227 arizona->pdata.micd_pol_gpio, ret);
1228 goto err_register;
1229 }
1230 }
1231
Mark Brown1eda6aa2013-01-11 08:55:54 +09001232 if (arizona->pdata.hpdet_id_gpio > 0) {
1233 ret = devm_gpio_request_one(&pdev->dev,
1234 arizona->pdata.hpdet_id_gpio,
1235 GPIOF_OUT_INIT_LOW,
1236 "HPDET");
1237 if (ret != 0) {
1238 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1239 arizona->pdata.hpdet_id_gpio, ret);
1240 goto err_register;
1241 }
1242 }
1243
Mark Brownb17e5462013-01-11 08:55:24 +09001244 if (arizona->pdata.micd_bias_start_time)
1245 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1246 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1247 arizona->pdata.micd_bias_start_time
1248 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1249
Mark Brown2e033db2013-01-21 17:36:33 +09001250 if (arizona->pdata.micd_rate)
1251 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1252 ARIZONA_MICD_RATE_MASK,
1253 arizona->pdata.micd_rate
1254 << ARIZONA_MICD_RATE_SHIFT);
1255
1256 if (arizona->pdata.micd_dbtime)
1257 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1258 ARIZONA_MICD_DBTIME_MASK,
1259 arizona->pdata.micd_dbtime
1260 << ARIZONA_MICD_DBTIME_SHIFT);
1261
Mark Brown6fed4d82013-04-01 22:03:06 +01001262 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1263
1264 if (arizona->pdata.num_micd_ranges) {
1265 info->micd_ranges = pdata->micd_ranges;
1266 info->num_micd_ranges = pdata->num_micd_ranges;
1267 } else {
1268 info->micd_ranges = micd_default_ranges;
1269 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1270 }
1271
1272 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1273 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1274 arizona->pdata.num_micd_ranges);
1275 }
1276
1277 if (info->num_micd_ranges > 1) {
1278 for (i = 1; i < info->num_micd_ranges; i++) {
1279 if (info->micd_ranges[i - 1].max >
1280 info->micd_ranges[i].max) {
1281 dev_err(arizona->dev,
1282 "MICD ranges must be sorted\n");
1283 ret = -EINVAL;
1284 goto err_input;
1285 }
1286 }
1287 }
1288
1289 /* Disable all buttons by default */
1290 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1291 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1292
1293 /* Set up all the buttons the user specified */
1294 for (i = 0; i < info->num_micd_ranges; i++) {
1295 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1296 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1297 break;
1298
1299 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1300 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1301 info->micd_ranges[i].max);
1302 ret = -EINVAL;
1303 goto err_input;
1304 }
1305
1306 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1307 arizona_micd_levels[j], i);
1308
1309 arizona_micd_set_level(arizona, i, j);
1310 input_set_capability(info->input, EV_KEY,
1311 info->micd_ranges[i].key);
1312
1313 /* Enable reporting of that range */
1314 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1315 1 << i, 1 << i);
1316 }
1317
1318 /* Set all the remaining keys to a maximum */
1319 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1320 arizona_micd_set_level(arizona, i, 0x3f);
1321
Mark Browndab63eb2013-01-11 08:55:36 +09001322 /*
Mark Brown92a49872013-01-11 08:55:39 +09001323 * If we have a clamp use it, activating in conjunction with
1324 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001325 */
1326 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001327 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001328 /* Put the GPIO into input mode with optional pull */
1329 val = 0xc101;
1330 if (arizona->pdata.jd_gpio5_nopull)
1331 val &= ~ARIZONA_GPN_PU;
1332
Mark Brown92a49872013-01-11 08:55:39 +09001333 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001334 val);
Mark Brown92a49872013-01-11 08:55:39 +09001335
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001336 if (arizona->pdata.jd_invert)
1337 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1338 else
1339 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001340 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001341 if (arizona->pdata.jd_invert)
1342 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1343 else
1344 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001345 }
1346
Mark Browndab63eb2013-01-11 08:55:36 +09001347 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001348 ARIZONA_MICD_CLAMP_CONTROL,
1349 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1350
1351 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001352 ARIZONA_JACK_DETECT_DEBOUNCE,
1353 ARIZONA_MICD_CLAMP_DB,
1354 ARIZONA_MICD_CLAMP_DB);
1355 }
1356
Mark Brownf2c32a82012-06-24 12:09:45 +01001357 arizona_extcon_set_mode(info, 0);
1358
1359 pm_runtime_enable(&pdev->dev);
1360 pm_runtime_idle(&pdev->dev);
1361 pm_runtime_get_sync(&pdev->dev);
1362
Mark Brown92a49872013-01-11 08:55:39 +09001363 if (arizona->pdata.jd_gpio5) {
1364 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1365 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1366 } else {
1367 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1368 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1369 }
1370
1371 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001372 "JACKDET rise", arizona_jackdet, info);
1373 if (ret != 0) {
1374 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1375 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001376 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001377 }
1378
Mark Brown92a49872013-01-11 08:55:39 +09001379 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001380 if (ret != 0) {
1381 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1382 ret);
1383 goto err_rise;
1384 }
1385
Mark Brown92a49872013-01-11 08:55:39 +09001386 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001387 "JACKDET fall", arizona_jackdet, info);
1388 if (ret != 0) {
1389 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1390 goto err_rise_wake;
1391 }
1392
Mark Brown92a49872013-01-11 08:55:39 +09001393 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001394 if (ret != 0) {
1395 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1396 ret);
1397 goto err_fall;
1398 }
1399
1400 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1401 "MICDET", arizona_micdet, info);
1402 if (ret != 0) {
1403 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1404 goto err_fall_wake;
1405 }
1406
Mark Brown4f340332013-01-11 08:55:43 +09001407 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1408 "HPDET", arizona_hpdet_irq, info);
1409 if (ret != 0) {
1410 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1411 goto err_micdet;
1412 }
1413
Mark Brownf2c32a82012-06-24 12:09:45 +01001414 arizona_clk32k_enable(arizona);
1415 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1416 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1417 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1418 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1419
Mark Brownb8575a12012-09-07 17:01:15 +08001420 ret = regulator_allow_bypass(info->micvdd, true);
1421 if (ret != 0)
1422 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1423 ret);
1424
Mark Brownf2c32a82012-06-24 12:09:45 +01001425 pm_runtime_put(&pdev->dev);
1426
Mark Brown34efe4d2012-07-20 17:07:29 +01001427 ret = input_register_device(info->input);
1428 if (ret) {
1429 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001430 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001431 }
1432
Mark Brownf2c32a82012-06-24 12:09:45 +01001433 return 0;
1434
Mark Brown4f340332013-01-11 08:55:43 +09001435err_hpdet:
1436 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001437err_micdet:
1438 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001439err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001440 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001441err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001442 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001443err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001444 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001445err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001446 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001447err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001448err_register:
1449 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001450 return ret;
1451}
1452
Bill Pemberton93ed0322012-11-19 13:25:49 -05001453static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001454{
1455 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1456 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001457 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001458
1459 pm_runtime_disable(&pdev->dev);
1460
Mark Browndab63eb2013-01-11 08:55:36 +09001461 regmap_update_bits(arizona->regmap,
1462 ARIZONA_MICD_CLAMP_CONTROL,
1463 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1464
Mark Brown92a49872013-01-11 08:55:39 +09001465 if (arizona->pdata.jd_gpio5) {
1466 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1467 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1468 } else {
1469 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1470 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1471 }
1472
1473 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1474 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1475 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001476 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001477 arizona_free_irq(arizona, jack_irq_rise, info);
1478 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001479 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001480 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1481 ARIZONA_JD1_ENA, 0);
1482 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001483
1484 return 0;
1485}
1486
1487static struct platform_driver arizona_extcon_driver = {
1488 .driver = {
1489 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001490 },
1491 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001492 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001493};
1494
1495module_platform_driver(arizona_extcon_driver);
1496
1497MODULE_DESCRIPTION("Arizona Extcon driver");
1498MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1499MODULE_LICENSE("GPL");
1500MODULE_ALIAS("platform:extcon-arizona");