blob: 4b9f09cc38d879899b18314509d20a7292f81fa6 [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>
Charles Keepax8e5838d2015-06-19 17:23:31 +010023#include <linux/gpio/consumer.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010024#include <linux/gpio.h>
Mark Brown34efe4d2012-07-20 17:07:29 +010025#include <linux/input.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010026#include <linux/platform_device.h>
27#include <linux/pm_runtime.h>
Charles Keepaxfeffb0c2015-06-19 17:23:29 +010028#include <linux/property.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010029#include <linux/regulator/consumer.h>
30#include <linux/extcon.h>
31
Mark Brownbbbd46e2013-01-10 19:38:43 +000032#include <sound/soc.h>
33
Mark Brownf2c32a82012-06-24 12:09:45 +010034#include <linux/mfd/arizona/core.h>
35#include <linux/mfd/arizona/pdata.h>
36#include <linux/mfd/arizona/registers.h>
Inha Song9e86b2a2015-05-04 13:42:13 +090037#include <dt-bindings/mfd/arizona.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010038
Mark Brown6fed4d82013-04-01 22:03:06 +010039#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010040
Richard Fitzgeralda288d642014-05-23 12:54:57 +010041#define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
42#define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
43#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
44#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
45
Mark Brown9dd5e532013-04-01 19:09:45 +010046#define ARIZONA_HPDET_MAX 10000
47
Mark Brown2643fd62013-04-01 19:07:28 +010048#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010049#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010050
Charles Keepaxbb327e92015-06-30 13:32:39 +010051#define MICD_DBTIME_TWO_READINGS 2
52#define MICD_DBTIME_FOUR_READINGS 4
53
Charles Keepaxffae24f2013-11-14 16:18:21 +000054#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
55 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
56 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
57 ARIZONA_MICD_LVL_7)
58
59#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
60
61#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
62
Mark Brownf2c32a82012-06-24 12:09:45 +010063struct arizona_extcon_info {
64 struct device *dev;
65 struct arizona *arizona;
66 struct mutex lock;
67 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010068 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010069
Mark Browna3e20782013-04-01 19:05:27 +010070 u16 last_jackdet;
71
Mark Brownf2c32a82012-06-24 12:09:45 +010072 int micd_mode;
73 const struct arizona_micd_config *micd_modes;
74 int micd_num_modes;
75
Mark Brown6fed4d82013-04-01 22:03:06 +010076 const struct arizona_micd_range *micd_ranges;
77 int num_micd_ranges;
78
Mark Brown7abd4e22013-04-01 19:25:55 +010079 int micd_timeout;
80
Mark Brownf2c32a82012-06-24 12:09:45 +010081 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090082 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010083
Mark Brown0e27bd32013-02-05 21:00:15 +000084 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010085 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010086 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000087
Mark Brown4f340332013-01-11 08:55:43 +090088 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000089 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010090 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090091
Mark Browndd235ee2013-01-11 08:55:51 +090092 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090093 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090094
Mark Brownf2c32a82012-06-24 12:09:45 +010095 bool mic;
96 bool detecting;
97 int jack_flips;
98
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +010099 int hpdet_ip_version;
Mark Brown4f340332013-01-11 08:55:43 +0900100
Chanwoo Choief70a212014-04-21 20:47:31 +0900101 struct extcon_dev *edev;
Charles Keepax8e5838d2015-06-19 17:23:31 +0100102
103 struct gpio_desc *micd_pol_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +0100104};
105
106static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +0100107 { ARIZONA_ACCDET_SRC, 1, 0 },
108 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100109};
110
Mark Brown6fed4d82013-04-01 22:03:06 +0100111static const struct arizona_micd_range micd_default_ranges[] = {
112 { .max = 11, .key = BTN_0 },
113 { .max = 28, .key = BTN_1 },
114 { .max = 54, .key = BTN_2 },
115 { .max = 100, .key = BTN_3 },
116 { .max = 186, .key = BTN_4 },
117 { .max = 430, .key = BTN_5 },
118};
119
120static const int arizona_micd_levels[] = {
121 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
122 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
123 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
124 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
125 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100126};
127
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900128static const unsigned int arizona_cable[] = {
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900129 EXTCON_MECHANICAL,
130 EXTCON_MICROPHONE,
131 EXTCON_HEADPHONE,
132 EXTCON_LINE_OUT,
133 EXTCON_NONE,
Mark Brownf2c32a82012-06-24 12:09:45 +0100134};
135
Mark Brown9dd5e532013-04-01 19:09:45 +0100136static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
137
Charles Keepax112bdfa2015-02-16 15:41:02 +0000138static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
139 bool clamp)
Mark Brown03409072013-02-12 13:00:31 +0000140{
141 struct arizona *arizona = info->arizona;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000142 unsigned int mask = 0, val = 0;
Mark Brown03409072013-02-12 13:00:31 +0000143 int ret;
144
Charles Keepax43f0acd2015-02-16 15:41:03 +0000145 switch (arizona->type) {
146 case WM5110:
Charles Keepax2b51f9c2015-04-30 23:43:37 +0900147 case WM8280:
Charles Keepax43f0acd2015-02-16 15:41:03 +0000148 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);
Charles Keepax8e5838d2015-06-19 17:23:31 +0100214 else
215 gpiod_set_value_cansleep(info->micd_pol_gpio,
216 info->micd_modes[mode].gpio);
217
Mark Brownf2c32a82012-06-24 12:09:45 +0100218 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
219 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100220 info->micd_modes[mode].bias <<
221 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100222 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
223 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
224
225 info->micd_mode = mode;
226
227 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
228}
229
Mark Brownbbbd46e2013-01-10 19:38:43 +0000230static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
231{
Charles Keepax41024242013-09-23 14:33:59 +0100232 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000233 case 1:
234 return "MICBIAS1";
235 case 2:
236 return "MICBIAS2";
237 case 3:
238 return "MICBIAS3";
239 default:
240 return "MICVDD";
241 }
242}
243
244static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
245{
246 struct arizona *arizona = info->arizona;
247 const char *widget = arizona_extcon_get_micbias(info);
248 struct snd_soc_dapm_context *dapm = arizona->dapm;
249 int ret;
250
Mark Brownbbbd46e2013-01-10 19:38:43 +0000251 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
252 if (ret != 0)
253 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
254 widget, ret);
255
Mark Brownbbbd46e2013-01-10 19:38:43 +0000256 snd_soc_dapm_sync(dapm);
257
258 if (!arizona->pdata.micd_force_micbias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000259 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
260 if (ret != 0)
261 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
262 widget, ret);
263
Mark Brownbbbd46e2013-01-10 19:38:43 +0000264 snd_soc_dapm_sync(dapm);
265 }
266}
267
Mark Brown9b1270c2013-01-11 08:55:46 +0900268static void arizona_start_mic(struct arizona_extcon_info *info)
269{
270 struct arizona *arizona = info->arizona;
271 bool change;
272 int ret;
273
Mark Brown9b1270c2013-01-11 08:55:46 +0900274 /* Microphone detection can't use idle mode */
275 pm_runtime_get(info->dev);
276
Mark Brownbbbd46e2013-01-10 19:38:43 +0000277 if (info->detecting) {
278 ret = regulator_allow_bypass(info->micvdd, false);
279 if (ret != 0) {
280 dev_err(arizona->dev,
281 "Failed to regulate MICVDD: %d\n",
282 ret);
283 }
284 }
285
Mark Brown9b1270c2013-01-11 08:55:46 +0900286 ret = regulator_enable(info->micvdd);
287 if (ret != 0) {
288 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
289 ret);
290 }
291
292 if (info->micd_reva) {
293 regmap_write(arizona->regmap, 0x80, 0x3);
294 regmap_write(arizona->regmap, 0x294, 0);
295 regmap_write(arizona->regmap, 0x80, 0x0);
296 }
297
298 regmap_update_bits(arizona->regmap,
299 ARIZONA_ACCESSORY_DETECT_MODE_1,
300 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
301
Mark Brownbbbd46e2013-01-10 19:38:43 +0000302 arizona_extcon_pulse_micbias(info);
303
Mark Brown9b1270c2013-01-11 08:55:46 +0900304 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
305 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
306 &change);
307 if (!change) {
308 regulator_disable(info->micvdd);
309 pm_runtime_put_autosuspend(info->dev);
310 }
311}
312
313static void arizona_stop_mic(struct arizona_extcon_info *info)
314{
315 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000316 const char *widget = arizona_extcon_get_micbias(info);
317 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900318 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000319 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900320
321 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
322 ARIZONA_MICD_ENA, 0,
323 &change);
324
Mark Brownbbbd46e2013-01-10 19:38:43 +0000325 ret = snd_soc_dapm_disable_pin(dapm, widget);
326 if (ret != 0)
327 dev_warn(arizona->dev,
328 "Failed to disable %s: %d\n",
329 widget, ret);
330
Mark Brownbbbd46e2013-01-10 19:38:43 +0000331 snd_soc_dapm_sync(dapm);
332
Mark Brown9b1270c2013-01-11 08:55:46 +0900333 if (info->micd_reva) {
334 regmap_write(arizona->regmap, 0x80, 0x3);
335 regmap_write(arizona->regmap, 0x294, 2);
336 regmap_write(arizona->regmap, 0x80, 0x0);
337 }
338
Mark Brownbbbd46e2013-01-10 19:38:43 +0000339 ret = regulator_allow_bypass(info->micvdd, true);
340 if (ret != 0) {
341 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
342 ret);
343 }
344
Mark Brown9b1270c2013-01-11 08:55:46 +0900345 if (change) {
346 regulator_disable(info->micvdd);
347 pm_runtime_mark_last_busy(info->dev);
348 pm_runtime_put_autosuspend(info->dev);
349 }
350}
351
Mark Brown4f340332013-01-11 08:55:43 +0900352static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100353 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900354 unsigned int factor_a;
355 unsigned int factor_b;
356} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100357 { 100, 5528, 362464 },
358 { 169, 11084, 6186851 },
359 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900360};
361
Charles Keepax24a279b2014-05-30 13:19:17 +0100362#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
363
Mark Brown4f340332013-01-11 08:55:43 +0900364static struct {
365 int min;
366 int max;
367} arizona_hpdet_c_ranges[] = {
368 { 0, 30 },
369 { 8, 100 },
370 { 100, 1000 },
371 { 1000, 10000 },
372};
373
374static int arizona_hpdet_read(struct arizona_extcon_info *info)
375{
376 struct arizona *arizona = info->arizona;
377 unsigned int val, range;
378 int ret;
379
380 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
381 if (ret != 0) {
382 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
383 ret);
384 return ret;
385 }
386
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100387 switch (info->hpdet_ip_version) {
Mark Brown4f340332013-01-11 08:55:43 +0900388 case 0:
389 if (!(val & ARIZONA_HP_DONE)) {
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 val &= ARIZONA_HP_LVL_MASK;
396 break;
397
398 case 1:
399 if (!(val & ARIZONA_HP_DONE_B)) {
400 dev_err(arizona->dev, "HPDET did not complete: %x\n",
401 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900402 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900403 }
404
405 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
406 if (ret != 0) {
407 dev_err(arizona->dev, "Failed to read HP value: %d\n",
408 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900409 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900410 }
411
412 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
413 &range);
414 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
415 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
416
417 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100418 (val < arizona_hpdet_b_ranges[range].threshold ||
419 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900420 range++;
421 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
422 range);
423 regmap_update_bits(arizona->regmap,
424 ARIZONA_HEADPHONE_DETECT_1,
425 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
426 range <<
427 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
428 return -EAGAIN;
429 }
430
431 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100432 if (val < arizona_hpdet_b_ranges[range].threshold ||
433 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900434 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100435 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900436 }
437
438 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
439 val, range);
440
441 val = arizona_hpdet_b_ranges[range].factor_b
442 / ((val * 100) -
443 arizona_hpdet_b_ranges[range].factor_a);
444 break;
445
446 default:
447 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100448 info->hpdet_ip_version);
Mark Brown4f340332013-01-11 08:55:43 +0900449 case 2:
450 if (!(val & ARIZONA_HP_DONE_B)) {
451 dev_err(arizona->dev, "HPDET did not complete: %x\n",
452 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900453 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900454 }
455
456 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000457 /* Convert to ohms, the value is in 0.5 ohm increments */
458 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900459
460 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
461 &range);
462 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
463 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
464
Charles Keepax91414612013-11-14 16:18:24 +0000465 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900466 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
467 (val >= arizona_hpdet_c_ranges[range].max)) {
468 range++;
469 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
470 arizona_hpdet_c_ranges[range].min,
471 arizona_hpdet_c_ranges[range].max);
472 regmap_update_bits(arizona->regmap,
473 ARIZONA_HEADPHONE_DETECT_1,
474 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
475 range <<
476 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
477 return -EAGAIN;
478 }
Charles Keepax91414612013-11-14 16:18:24 +0000479
480 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
481 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
482 arizona_hpdet_c_ranges[range].min);
483 val = arizona_hpdet_c_ranges[range].min;
484 }
Mark Brown4f340332013-01-11 08:55:43 +0900485 }
486
487 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
488 return val;
489}
490
Mark Brown9c2ba272013-02-25 23:42:31 +0000491static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
492 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900493{
494 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900495 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900496
497 /*
498 * If we're using HPDET for accessory identification we need
499 * to take multiple measurements, step through them in sequence.
500 */
501 if (arizona->pdata.hpdet_acc_id) {
502 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900503
504 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000505 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900506 dev_dbg(arizona->dev, "Measuring mic\n");
507
508 regmap_update_bits(arizona->regmap,
509 ARIZONA_ACCESSORY_DETECT_MODE_1,
510 ARIZONA_ACCDET_MODE_MASK |
511 ARIZONA_ACCDET_SRC,
512 ARIZONA_ACCDET_MODE_HPR |
513 info->micd_modes[0].src);
514
515 gpio_set_value_cansleep(id_gpio, 1);
516
Mark Browndd235ee2013-01-11 08:55:51 +0900517 regmap_update_bits(arizona->regmap,
518 ARIZONA_HEADPHONE_DETECT_1,
519 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
520 return -EAGAIN;
521 }
522
523 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000524 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
525 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000526
527 /* Take the headphone impedance for the main report */
528 *reading = info->hpdet_res[0];
529
Mark Brown9dd5e532013-04-01 19:09:45 +0100530 /* Sometimes we get false readings due to slow insert */
531 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
532 dev_dbg(arizona->dev, "Retrying high impedance\n");
533 info->num_hpdet_res = 0;
534 info->hpdet_retried = true;
535 arizona_start_hpdet_acc_id(info);
536 pm_runtime_put(info->dev);
537 return -EAGAIN;
538 }
539
Mark Brown1eda6aa2013-01-11 08:55:54 +0900540 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530541 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900542 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000543 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900544 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000545 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000546 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900547 } else {
548 dev_dbg(arizona->dev, "Detected headphone\n");
549 }
550
551 /* Make sure everything is reset back to the real polarity */
552 regmap_update_bits(arizona->regmap,
553 ARIZONA_ACCESSORY_DETECT_MODE_1,
554 ARIZONA_ACCDET_SRC,
555 info->micd_modes[0].src);
556 }
557
558 return 0;
559}
560
Mark Brown4f340332013-01-11 08:55:43 +0900561static irqreturn_t arizona_hpdet_irq(int irq, void *data)
562{
563 struct arizona_extcon_info *info = data;
564 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900565 int id_gpio = arizona->pdata.hpdet_id_gpio;
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900566 unsigned int report = EXTCON_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900567 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000568 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900569
570 mutex_lock(&info->lock);
571
572 /* If we got a spurious IRQ for some reason then ignore it */
573 if (!info->hpdet_active) {
574 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
575 mutex_unlock(&info->lock);
576 return IRQ_NONE;
577 }
578
579 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900580 ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900581 if (ret < 0) {
582 dev_err(arizona->dev, "Failed to check cable state: %d\n",
583 ret);
584 goto out;
585 } else if (!ret) {
586 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
587 goto done;
588 }
589
590 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900591 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900592 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900593 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900594 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900595 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900596
597 /* Reset back to starting range */
598 regmap_update_bits(arizona->regmap,
599 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900600 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
601 0);
602
Mark Brown9c2ba272013-02-25 23:42:31 +0000603 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900604 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900605 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900606 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900607 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900608
609 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900610 if (reading >= 5000)
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900611 report = EXTCON_LINE_OUT;
Mark Brown4f340332013-01-11 08:55:43 +0900612 else
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900613 report = EXTCON_HEADPHONE;
Mark Brown4f340332013-01-11 08:55:43 +0900614
Chanwoo Choief70a212014-04-21 20:47:31 +0900615 ret = extcon_set_cable_state_(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900616 if (ret != 0)
617 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
618 ret);
619
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000620done:
621 /* Reset back to starting range */
622 regmap_update_bits(arizona->regmap,
623 ARIZONA_HEADPHONE_DETECT_1,
624 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
625 0);
626
Charles Keepax112bdfa2015-02-16 15:41:02 +0000627 arizona_extcon_hp_clamp(info, false);
Mark Brown4f340332013-01-11 08:55:43 +0900628
Mark Brown1eda6aa2013-01-11 08:55:54 +0900629 if (id_gpio)
630 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900631
632 /* Revert back to MICDET mode */
633 regmap_update_bits(arizona->regmap,
634 ARIZONA_ACCESSORY_DETECT_MODE_1,
635 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
636
637 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000638 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900639 arizona_start_mic(info);
640
641 if (info->hpdet_active) {
642 pm_runtime_put_autosuspend(info->dev);
643 info->hpdet_active = false;
644 }
645
Mark Brownbf14ee52013-02-05 20:20:17 +0000646 info->hpdet_done = true;
647
Mark Brown4f340332013-01-11 08:55:43 +0900648out:
649 mutex_unlock(&info->lock);
650
651 return IRQ_HANDLED;
652}
653
654static void arizona_identify_headphone(struct arizona_extcon_info *info)
655{
656 struct arizona *arizona = info->arizona;
657 int ret;
658
Mark Brownbf14ee52013-02-05 20:20:17 +0000659 if (info->hpdet_done)
660 return;
661
Mark Brown4f340332013-01-11 08:55:43 +0900662 dev_dbg(arizona->dev, "Starting HPDET\n");
663
664 /* Make sure we keep the device enabled during the measurement */
665 pm_runtime_get(info->dev);
666
667 info->hpdet_active = true;
668
669 if (info->mic)
670 arizona_stop_mic(info);
671
Charles Keepax112bdfa2015-02-16 15:41:02 +0000672 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900673
674 ret = regmap_update_bits(arizona->regmap,
675 ARIZONA_ACCESSORY_DETECT_MODE_1,
676 ARIZONA_ACCDET_MODE_MASK,
Inha Song9e86b2a2015-05-04 13:42:13 +0900677 arizona->pdata.hpdet_channel);
Mark Brown4f340332013-01-11 08:55:43 +0900678 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900679 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +0900680 goto err;
681 }
682
683 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
684 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
685 if (ret != 0) {
686 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
687 ret);
688 goto err;
689 }
690
691 return;
692
693err:
694 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
695 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
696
697 /* Just report headphone */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900698 ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900699 if (ret != 0)
700 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
701
702 if (info->mic)
703 arizona_start_mic(info);
704
705 info->hpdet_active = false;
706}
Mark Browndd235ee2013-01-11 08:55:51 +0900707
708static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
709{
710 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000711 int hp_reading = 32;
712 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900713 int ret;
714
715 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
716
717 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000718 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900719
720 info->hpdet_active = true;
721
Charles Keepax112bdfa2015-02-16 15:41:02 +0000722 arizona_extcon_hp_clamp(info, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900723
724 ret = regmap_update_bits(arizona->regmap,
725 ARIZONA_ACCESSORY_DETECT_MODE_1,
726 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
727 info->micd_modes[0].src |
Inha Song9e86b2a2015-05-04 13:42:13 +0900728 arizona->pdata.hpdet_channel);
Mark Browndd235ee2013-01-11 08:55:51 +0900729 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900730 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Browndd235ee2013-01-11 08:55:51 +0900731 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900732 }
733
Mark Brown9c2ba272013-02-25 23:42:31 +0000734 if (arizona->pdata.hpdet_acc_id_line) {
735 ret = regmap_update_bits(arizona->regmap,
736 ARIZONA_HEADPHONE_DETECT_1,
737 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
738 if (ret != 0) {
739 dev_err(arizona->dev,
740 "Can't start HPDETL measurement: %d\n",
741 ret);
742 goto err;
743 }
744 } else {
745 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900746 }
747
748 return;
749
750err:
751 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
752 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
753
754 /* Just report headphone */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900755 ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900756 if (ret != 0)
757 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
758
Mark Brown4f340332013-01-11 08:55:43 +0900759 info->hpdet_active = false;
760}
761
Mark Brown939c5672013-04-01 19:17:34 +0100762static void arizona_micd_timeout_work(struct work_struct *work)
763{
764 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900765 struct arizona_extcon_info,
766 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100767
768 mutex_lock(&info->lock);
769
770 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
Mark Brown939c5672013-04-01 19:17:34 +0100771
772 info->detecting = false;
773
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100774 arizona_identify_headphone(info);
775
Mark Brown939c5672013-04-01 19:17:34 +0100776 arizona_stop_mic(info);
777
778 mutex_unlock(&info->lock);
779}
780
Mark Browncd59e792013-04-01 19:21:48 +0100781static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100782{
Mark Browncd59e792013-04-01 19:21:48 +0100783 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900784 struct arizona_extcon_info,
785 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100786 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100787 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100788 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100789
Mark Brown939c5672013-04-01 19:17:34 +0100790 cancel_delayed_work_sync(&info->micd_timeout_work);
791
Mark Brownf2c32a82012-06-24 12:09:45 +0100792 mutex_lock(&info->lock);
793
Charles Keepax31a847e2013-11-14 16:18:23 +0000794 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900795 ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000796 if (ret < 0) {
797 dev_err(arizona->dev, "Failed to check cable state: %d\n",
798 ret);
799 mutex_unlock(&info->lock);
800 return;
801 } else if (!ret) {
802 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
803 mutex_unlock(&info->lock);
804 return;
805 }
806
Charles Keepaxffae24f2013-11-14 16:18:21 +0000807 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100808 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
809 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900810 dev_err(arizona->dev,
811 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100812 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100813 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100814 }
815
816 dev_dbg(arizona->dev, "MICDET: %x\n", val);
817
818 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900819 dev_warn(arizona->dev,
820 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100821 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100822 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100823 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100824 }
825
Charles Keepaxffae24f2013-11-14 16:18:21 +0000826 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100827 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100828 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100829 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100830 }
831
832 /* Due to jack detect this should never happen */
833 if (!(val & ARIZONA_MICD_STS)) {
834 dev_warn(arizona->dev, "Detected open circuit\n");
Charles Keepax57f70ef2015-06-25 16:47:02 +0100835 info->mic = false;
836 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100837 info->detecting = false;
Charles Keepax57f70ef2015-06-25 16:47:02 +0100838 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100839 goto handled;
840 }
841
842 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000843 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100844 info->mic = true;
845 info->detecting = false;
846
Mark Brown4f340332013-01-11 08:55:43 +0900847 arizona_identify_headphone(info);
848
Nikesh Oswal34602482014-05-29 16:27:52 +0100849 ret = extcon_set_cable_state_(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900850 EXTCON_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100851 if (ret != 0)
852 dev_err(arizona->dev, "Headset report failed: %d\n",
853 ret);
854
Mark Brownbbbd46e2013-01-10 19:38:43 +0000855 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100856 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000857 if (ret != 0) {
858 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
859 ret);
860 }
861
Mark Brownf2c32a82012-06-24 12:09:45 +0100862 goto handled;
863 }
864
865 /* If we detected a lower impedence during initial startup
866 * then we probably have the wrong polarity, flip it. Don't
867 * do this for the lowest impedences to speed up detection of
868 * plain headphones. If both polarities report a low
869 * impedence then give up and report headphones.
870 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000871 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800872 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900873 dev_dbg(arizona->dev, "Detected HP/line\n");
Mark Brown9ef2224d2012-06-28 13:08:31 +0100874
Mark Brown4f340332013-01-11 08:55:43 +0900875 info->detecting = false;
876
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100877 arizona_identify_headphone(info);
878
Mark Brown4f340332013-01-11 08:55:43 +0900879 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100880 } else {
881 info->micd_mode++;
882 if (info->micd_mode == info->micd_num_modes)
883 info->micd_mode = 0;
884 arizona_extcon_set_mode(info, info->micd_mode);
885
886 info->jack_flips++;
887 }
888
889 goto handled;
890 }
891
892 /*
893 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100894 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100895 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000896 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100897 if (info->mic) {
898 dev_dbg(arizona->dev, "Mic button detected\n");
899
Mark Brown34efe4d2012-07-20 17:07:29 +0100900 lvl = val & ARIZONA_MICD_LVL_MASK;
901 lvl >>= ARIZONA_MICD_LVL_SHIFT;
902
Mark Brown41a57852013-04-01 19:18:18 +0100903 for (i = 0; i < info->num_micd_ranges; i++)
904 input_report_key(info->input,
905 info->micd_ranges[i].key, 0);
906
Mark Brown6fed4d82013-04-01 22:03:06 +0100907 WARN_ON(!lvl);
908 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
909 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
910 key = info->micd_ranges[ffs(lvl) - 1].key;
911 input_report_key(info->input, key, 1);
912 input_sync(info->input);
913 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100914
Mark Brownf2c32a82012-06-24 12:09:45 +0100915 } else if (info->detecting) {
916 dev_dbg(arizona->dev, "Headphone detected\n");
917 info->detecting = false;
918 arizona_stop_mic(info);
919
Mark Brown4f340332013-01-11 08:55:43 +0900920 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100921 } else {
922 dev_warn(arizona->dev, "Button with no mic: %x\n",
923 val);
924 }
925 } else {
926 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100927 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100928 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100929 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100930 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000931 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100932 }
933
934handled:
Mark Brown939c5672013-04-01 19:17:34 +0100935 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100936 queue_delayed_work(system_power_efficient_wq,
937 &info->micd_timeout_work,
938 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100939
Mark Brownf2c32a82012-06-24 12:09:45 +0100940 pm_runtime_mark_last_busy(info->dev);
941 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100942}
943
944static irqreturn_t arizona_micdet(int irq, void *data)
945{
946 struct arizona_extcon_info *info = data;
947 struct arizona *arizona = info->arizona;
948 int debounce = arizona->pdata.micd_detect_debounce;
949
950 cancel_delayed_work_sync(&info->micd_detect_work);
951 cancel_delayed_work_sync(&info->micd_timeout_work);
952
953 mutex_lock(&info->lock);
954 if (!info->detecting)
955 debounce = 0;
956 mutex_unlock(&info->lock);
957
958 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100959 queue_delayed_work(system_power_efficient_wq,
960 &info->micd_detect_work,
961 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100962 else
963 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100964
965 return IRQ_HANDLED;
966}
967
Mark Brown0e27bd32013-02-05 21:00:15 +0000968static void arizona_hpdet_work(struct work_struct *work)
969{
970 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900971 struct arizona_extcon_info,
972 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000973
974 mutex_lock(&info->lock);
975 arizona_start_hpdet_acc_id(info);
976 mutex_unlock(&info->lock);
977}
978
Mark Brownf2c32a82012-06-24 12:09:45 +0100979static irqreturn_t arizona_jackdet(int irq, void *data)
980{
981 struct arizona_extcon_info *info = data;
982 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900983 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100984 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100985 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100986
Mark Brown939c5672013-04-01 19:17:34 +0100987 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
988 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100989
Mark Browna3e20782013-04-01 19:05:27 +0100990 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000991
Mark Brownf2c32a82012-06-24 12:09:45 +0100992 mutex_lock(&info->lock);
993
Mark Brown92a49872013-01-11 08:55:39 +0900994 if (arizona->pdata.jd_gpio5) {
995 mask = ARIZONA_MICD_CLAMP_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100996 if (arizona->pdata.jd_invert)
997 present = ARIZONA_MICD_CLAMP_STS;
998 else
999 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +09001000 } else {
1001 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001002 if (arizona->pdata.jd_invert)
1003 present = 0;
1004 else
1005 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +09001006 }
1007
Mark Brownf2c32a82012-06-24 12:09:45 +01001008 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
1009 if (ret != 0) {
1010 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
1011 ret);
1012 mutex_unlock(&info->lock);
1013 pm_runtime_put_autosuspend(info->dev);
1014 return IRQ_NONE;
1015 }
1016
Mark Browna3e20782013-04-01 19:05:27 +01001017 val &= mask;
1018 if (val == info->last_jackdet) {
1019 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001020 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001021 queue_delayed_work(system_power_efficient_wq,
1022 &info->hpdet_work,
1023 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001024
Chanwoo Choic2275d22013-08-23 10:21:37 +09001025 if (cancelled_mic) {
1026 int micd_timeout = info->micd_timeout;
1027
Mark Browndf9a5ab2013-07-18 22:42:22 +01001028 queue_delayed_work(system_power_efficient_wq,
1029 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001030 msecs_to_jiffies(micd_timeout));
1031 }
Mark Brown939c5672013-04-01 19:17:34 +01001032
Mark Browna3e20782013-04-01 19:05:27 +01001033 goto out;
1034 }
1035 info->last_jackdet = val;
1036
1037 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001038 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choief70a212014-04-21 20:47:31 +09001039 ret = extcon_set_cable_state_(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +09001040 EXTCON_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001041
1042 if (ret != 0)
1043 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1044 ret);
1045
Mark Browndd235ee2013-01-11 08:55:51 +09001046 if (!arizona->pdata.hpdet_acc_id) {
1047 info->detecting = true;
1048 info->mic = false;
1049 info->jack_flips = 0;
1050
1051 arizona_start_mic(info);
1052 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001053 queue_delayed_work(system_power_efficient_wq,
1054 &info->hpdet_work,
1055 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001056 }
Mark Brown4e616872013-01-15 22:09:20 +09001057
1058 regmap_update_bits(arizona->regmap,
1059 ARIZONA_JACK_DETECT_DEBOUNCE,
1060 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001061 } else {
1062 dev_dbg(arizona->dev, "Detected jack removal\n");
1063
1064 arizona_stop_mic(info);
1065
Mark Browndd235ee2013-01-11 08:55:51 +09001066 info->num_hpdet_res = 0;
1067 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1068 info->hpdet_res[i] = 0;
1069 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001070 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001071 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001072
Mark Brown6fed4d82013-04-01 22:03:06 +01001073 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001074 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001075 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001076 input_sync(info->input);
1077
Chanwoo Choief70a212014-04-21 20:47:31 +09001078 ret = extcon_update_state(info->edev, 0xffffffff, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001079 if (ret != 0)
1080 dev_err(arizona->dev, "Removal report failed: %d\n",
1081 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001082
1083 regmap_update_bits(arizona->regmap,
1084 ARIZONA_JACK_DETECT_DEBOUNCE,
1085 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1086 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001087 }
1088
Mark Brown7abd4e22013-04-01 19:25:55 +01001089 if (arizona->pdata.micd_timeout)
1090 info->micd_timeout = arizona->pdata.micd_timeout;
1091 else
1092 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1093
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001094out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001095 /* Clear trig_sts to make sure DCVDD is not forced up */
1096 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1097 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1098 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1099 ARIZONA_JD1_FALL_TRIG_STS |
1100 ARIZONA_JD1_RISE_TRIG_STS);
1101
Mark Brownf2c32a82012-06-24 12:09:45 +01001102 mutex_unlock(&info->lock);
1103
1104 pm_runtime_mark_last_busy(info->dev);
1105 pm_runtime_put_autosuspend(info->dev);
1106
1107 return IRQ_HANDLED;
1108}
1109
Mark Brown6fed4d82013-04-01 22:03:06 +01001110/* Map a level onto a slot in the register bank */
1111static void arizona_micd_set_level(struct arizona *arizona, int index,
1112 unsigned int level)
1113{
1114 int reg;
1115 unsigned int mask;
1116
1117 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1118
1119 if (!(index % 2)) {
1120 mask = 0x3f00;
1121 level <<= 8;
1122 } else {
1123 mask = 0x3f;
1124 }
1125
1126 /* Program the level itself */
1127 regmap_update_bits(arizona->regmap, reg, mask, level);
1128}
1129
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001130static int arizona_extcon_device_get_pdata(struct arizona *arizona)
Inha Song9e86b2a2015-05-04 13:42:13 +09001131{
1132 struct arizona_pdata *pdata = &arizona->pdata;
1133 unsigned int val = ARIZONA_ACCDET_MODE_HPL;
1134
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001135 device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
Inha Song9e86b2a2015-05-04 13:42:13 +09001136 switch (val) {
1137 case ARIZONA_ACCDET_MODE_HPL:
1138 case ARIZONA_ACCDET_MODE_HPR:
1139 pdata->hpdet_channel = val;
1140 break;
1141 default:
1142 dev_err(arizona->dev,
1143 "Wrong wlf,hpdet-channel DT value %d\n", val);
1144 pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
1145 }
1146
Charles Keepax4778d442015-06-19 17:23:30 +01001147 device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
1148 &pdata->micd_detect_debounce);
1149
1150 device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
1151 &pdata->micd_bias_start_time);
1152
1153 device_property_read_u32(arizona->dev, "wlf,micd-rate",
1154 &pdata->micd_rate);
1155
1156 device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
1157 &pdata->micd_dbtime);
1158
1159 device_property_read_u32(arizona->dev, "wlf,micd-timeout",
1160 &pdata->micd_timeout);
1161
1162 pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
1163 "wlf,micd-force-micbias");
1164
Inha Song9e86b2a2015-05-04 13:42:13 +09001165 return 0;
1166}
1167
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001168static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001169{
1170 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001171 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001172 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001173 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001174 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001175 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001176 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001177
Mark Brownbbbd46e2013-01-10 19:38:43 +00001178 if (!arizona->dapm || !arizona->dapm->card)
1179 return -EPROBE_DEFER;
1180
Mark Brownf2c32a82012-06-24 12:09:45 +01001181 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001182 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001183 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001184
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001185 if (!dev_get_platdata(arizona->dev))
1186 arizona_extcon_device_get_pdata(arizona);
Inha Song9e86b2a2015-05-04 13:42:13 +09001187
Charles Keepax17271f62014-07-18 12:59:00 +01001188 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001189 if (IS_ERR(info->micvdd)) {
1190 ret = PTR_ERR(info->micvdd);
1191 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001192 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001193 }
1194
1195 mutex_init(&info->lock);
1196 info->arizona = arizona;
1197 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001198 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001199 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001200 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001201 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001202 platform_set_drvdata(pdev, info);
1203
1204 switch (arizona->type) {
1205 case WM5102:
1206 switch (arizona->rev) {
1207 case 0:
1208 info->micd_reva = true;
1209 break;
1210 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001211 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001212 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001213 break;
1214 }
1215 break;
Charles Keepax77438612013-11-14 16:18:25 +00001216 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001217 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001218 switch (arizona->rev) {
1219 case 0 ... 2:
1220 break;
1221 default:
1222 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001223 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001224 break;
1225 }
1226 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001227 default:
1228 break;
1229 }
1230
Chanwoo Choief70a212014-04-21 20:47:31 +09001231 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1232 if (IS_ERR(info->edev)) {
1233 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1234 return -ENOMEM;
1235 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001236
Chanwoo Choief70a212014-04-21 20:47:31 +09001237 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001238 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001239 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001240 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001241 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001242 }
1243
Mark Brown6fed4d82013-04-01 22:03:06 +01001244 info->input = devm_input_allocate_device(&pdev->dev);
1245 if (!info->input) {
1246 dev_err(arizona->dev, "Can't allocate input dev\n");
1247 ret = -ENOMEM;
1248 goto err_register;
1249 }
1250
1251 info->input->name = "Headset";
1252 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001253
Mark Brownf2c32a82012-06-24 12:09:45 +01001254 if (pdata->num_micd_configs) {
1255 info->micd_modes = pdata->micd_configs;
1256 info->micd_num_modes = pdata->num_micd_configs;
1257 } else {
1258 info->micd_modes = micd_default_modes;
1259 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1260 }
1261
1262 if (arizona->pdata.micd_pol_gpio > 0) {
1263 if (info->micd_modes[0].gpio)
1264 mode = GPIOF_OUT_INIT_HIGH;
1265 else
1266 mode = GPIOF_OUT_INIT_LOW;
1267
1268 ret = devm_gpio_request_one(&pdev->dev,
1269 arizona->pdata.micd_pol_gpio,
1270 mode,
1271 "MICD polarity");
1272 if (ret != 0) {
1273 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1274 arizona->pdata.micd_pol_gpio, ret);
1275 goto err_register;
1276 }
Charles Keepax8e5838d2015-06-19 17:23:31 +01001277 } else {
1278 if (info->micd_modes[0].gpio)
1279 mode = GPIOD_OUT_HIGH;
1280 else
1281 mode = GPIOD_OUT_LOW;
1282
1283 /* We can't use devm here because we need to do the get
1284 * against the MFD device, as that is where the of_node
1285 * will reside, but if we devm against that the GPIO
1286 * will not be freed if the extcon driver is unloaded.
1287 */
1288 info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
1289 "wlf,micd-pol",
1290 GPIOD_OUT_LOW);
1291 if (IS_ERR(info->micd_pol_gpio)) {
1292 ret = PTR_ERR(info->micd_pol_gpio);
1293 dev_err(arizona->dev,
1294 "Failed to get microphone polarity GPIO: %d\n",
1295 ret);
1296 goto err_register;
1297 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001298 }
1299
Mark Brown1eda6aa2013-01-11 08:55:54 +09001300 if (arizona->pdata.hpdet_id_gpio > 0) {
1301 ret = devm_gpio_request_one(&pdev->dev,
1302 arizona->pdata.hpdet_id_gpio,
1303 GPIOF_OUT_INIT_LOW,
1304 "HPDET");
1305 if (ret != 0) {
1306 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1307 arizona->pdata.hpdet_id_gpio, ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001308 goto err_gpio;
Mark Brown1eda6aa2013-01-11 08:55:54 +09001309 }
1310 }
1311
Mark Brownb17e5462013-01-11 08:55:24 +09001312 if (arizona->pdata.micd_bias_start_time)
1313 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1314 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1315 arizona->pdata.micd_bias_start_time
1316 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1317
Mark Brown2e033db2013-01-21 17:36:33 +09001318 if (arizona->pdata.micd_rate)
1319 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1320 ARIZONA_MICD_RATE_MASK,
1321 arizona->pdata.micd_rate
1322 << ARIZONA_MICD_RATE_SHIFT);
1323
Charles Keepaxbb327e92015-06-30 13:32:39 +01001324 switch (arizona->pdata.micd_dbtime) {
1325 case MICD_DBTIME_FOUR_READINGS:
Mark Brown2e033db2013-01-21 17:36:33 +09001326 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1327 ARIZONA_MICD_DBTIME_MASK,
Charles Keepaxbb327e92015-06-30 13:32:39 +01001328 ARIZONA_MICD_DBTIME);
1329 break;
1330 case MICD_DBTIME_TWO_READINGS:
1331 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1332 ARIZONA_MICD_DBTIME_MASK, 0);
1333 break;
1334 default:
1335 break;
1336 }
Mark Brown2e033db2013-01-21 17:36:33 +09001337
Mark Brown6fed4d82013-04-01 22:03:06 +01001338 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1339
1340 if (arizona->pdata.num_micd_ranges) {
1341 info->micd_ranges = pdata->micd_ranges;
1342 info->num_micd_ranges = pdata->num_micd_ranges;
1343 } else {
1344 info->micd_ranges = micd_default_ranges;
1345 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1346 }
1347
1348 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1349 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1350 arizona->pdata.num_micd_ranges);
1351 }
1352
1353 if (info->num_micd_ranges > 1) {
1354 for (i = 1; i < info->num_micd_ranges; i++) {
1355 if (info->micd_ranges[i - 1].max >
1356 info->micd_ranges[i].max) {
1357 dev_err(arizona->dev,
1358 "MICD ranges must be sorted\n");
1359 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001360 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001361 }
1362 }
1363 }
1364
1365 /* Disable all buttons by default */
1366 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1367 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1368
1369 /* Set up all the buttons the user specified */
1370 for (i = 0; i < info->num_micd_ranges; i++) {
1371 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1372 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1373 break;
1374
1375 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1376 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1377 info->micd_ranges[i].max);
1378 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001379 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001380 }
1381
1382 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1383 arizona_micd_levels[j], i);
1384
1385 arizona_micd_set_level(arizona, i, j);
1386 input_set_capability(info->input, EV_KEY,
1387 info->micd_ranges[i].key);
1388
1389 /* Enable reporting of that range */
1390 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1391 1 << i, 1 << i);
1392 }
1393
1394 /* Set all the remaining keys to a maximum */
1395 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1396 arizona_micd_set_level(arizona, i, 0x3f);
1397
Mark Browndab63eb2013-01-11 08:55:36 +09001398 /*
Mark Brown92a49872013-01-11 08:55:39 +09001399 * If we have a clamp use it, activating in conjunction with
1400 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001401 */
1402 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001403 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001404 /* Put the GPIO into input mode with optional pull */
1405 val = 0xc101;
1406 if (arizona->pdata.jd_gpio5_nopull)
1407 val &= ~ARIZONA_GPN_PU;
1408
Mark Brown92a49872013-01-11 08:55:39 +09001409 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001410 val);
Mark Brown92a49872013-01-11 08:55:39 +09001411
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001412 if (arizona->pdata.jd_invert)
1413 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1414 else
1415 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001416 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001417 if (arizona->pdata.jd_invert)
1418 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1419 else
1420 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001421 }
1422
Mark Browndab63eb2013-01-11 08:55:36 +09001423 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001424 ARIZONA_MICD_CLAMP_CONTROL,
1425 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1426
1427 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001428 ARIZONA_JACK_DETECT_DEBOUNCE,
1429 ARIZONA_MICD_CLAMP_DB,
1430 ARIZONA_MICD_CLAMP_DB);
1431 }
1432
Mark Brownf2c32a82012-06-24 12:09:45 +01001433 arizona_extcon_set_mode(info, 0);
1434
1435 pm_runtime_enable(&pdev->dev);
1436 pm_runtime_idle(&pdev->dev);
1437 pm_runtime_get_sync(&pdev->dev);
1438
Mark Brown92a49872013-01-11 08:55:39 +09001439 if (arizona->pdata.jd_gpio5) {
1440 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1441 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1442 } else {
1443 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1444 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1445 }
1446
1447 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001448 "JACKDET rise", arizona_jackdet, info);
1449 if (ret != 0) {
1450 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1451 ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001452 goto err_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +01001453 }
1454
Mark Brown92a49872013-01-11 08:55:39 +09001455 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001456 if (ret != 0) {
1457 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1458 ret);
1459 goto err_rise;
1460 }
1461
Mark Brown92a49872013-01-11 08:55:39 +09001462 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001463 "JACKDET fall", arizona_jackdet, info);
1464 if (ret != 0) {
1465 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1466 goto err_rise_wake;
1467 }
1468
Mark Brown92a49872013-01-11 08:55:39 +09001469 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001470 if (ret != 0) {
1471 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1472 ret);
1473 goto err_fall;
1474 }
1475
1476 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1477 "MICDET", arizona_micdet, info);
1478 if (ret != 0) {
1479 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1480 goto err_fall_wake;
1481 }
1482
Mark Brown4f340332013-01-11 08:55:43 +09001483 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1484 "HPDET", arizona_hpdet_irq, info);
1485 if (ret != 0) {
1486 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1487 goto err_micdet;
1488 }
1489
Mark Brownf2c32a82012-06-24 12:09:45 +01001490 arizona_clk32k_enable(arizona);
1491 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1492 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1493 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1494 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1495
Mark Brownb8575a12012-09-07 17:01:15 +08001496 ret = regulator_allow_bypass(info->micvdd, true);
1497 if (ret != 0)
1498 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1499 ret);
1500
Mark Brownf2c32a82012-06-24 12:09:45 +01001501 pm_runtime_put(&pdev->dev);
1502
Mark Brown34efe4d2012-07-20 17:07:29 +01001503 ret = input_register_device(info->input);
1504 if (ret) {
1505 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001506 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001507 }
1508
Mark Brownf2c32a82012-06-24 12:09:45 +01001509 return 0;
1510
Mark Brown4f340332013-01-11 08:55:43 +09001511err_hpdet:
1512 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001513err_micdet:
1514 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001515err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001516 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001517err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001518 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001519err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001520 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001521err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001522 arizona_free_irq(arizona, jack_irq_rise, info);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001523err_gpio:
1524 gpiod_put(info->micd_pol_gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +01001525err_register:
1526 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001527 return ret;
1528}
1529
Bill Pemberton93ed0322012-11-19 13:25:49 -05001530static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001531{
1532 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1533 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001534 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001535
Charles Keepax8e5838d2015-06-19 17:23:31 +01001536 gpiod_put(info->micd_pol_gpio);
1537
Mark Brownf2c32a82012-06-24 12:09:45 +01001538 pm_runtime_disable(&pdev->dev);
1539
Mark Browndab63eb2013-01-11 08:55:36 +09001540 regmap_update_bits(arizona->regmap,
1541 ARIZONA_MICD_CLAMP_CONTROL,
1542 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1543
Mark Brown92a49872013-01-11 08:55:39 +09001544 if (arizona->pdata.jd_gpio5) {
1545 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1546 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1547 } else {
1548 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1549 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1550 }
1551
1552 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1553 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1554 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001555 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001556 arizona_free_irq(arizona, jack_irq_rise, info);
1557 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001558 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001559 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1560 ARIZONA_JD1_ENA, 0);
1561 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001562
1563 return 0;
1564}
1565
1566static struct platform_driver arizona_extcon_driver = {
1567 .driver = {
1568 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001569 },
1570 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001571 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001572};
1573
1574module_platform_driver(arizona_extcon_driver);
1575
1576MODULE_DESCRIPTION("Arizona Extcon driver");
1577MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1578MODULE_LICENSE("GPL");
1579MODULE_ALIAS("platform:extcon-arizona");