blob: eaf0644b55065a1dfa5dd6a7cbf3ca26ea8d6fed [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 Keepaxffae24f2013-11-14 16:18:21 +000051#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
52 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
53 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
54 ARIZONA_MICD_LVL_7)
55
56#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
57
58#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
59
Mark Brownf2c32a82012-06-24 12:09:45 +010060struct arizona_extcon_info {
61 struct device *dev;
62 struct arizona *arizona;
63 struct mutex lock;
64 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010065 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010066
Mark Browna3e20782013-04-01 19:05:27 +010067 u16 last_jackdet;
68
Mark Brownf2c32a82012-06-24 12:09:45 +010069 int micd_mode;
70 const struct arizona_micd_config *micd_modes;
71 int micd_num_modes;
72
Mark Brown6fed4d82013-04-01 22:03:06 +010073 const struct arizona_micd_range *micd_ranges;
74 int num_micd_ranges;
75
Mark Brown7abd4e22013-04-01 19:25:55 +010076 int micd_timeout;
77
Mark Brownf2c32a82012-06-24 12:09:45 +010078 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090079 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010080
Mark Brown0e27bd32013-02-05 21:00:15 +000081 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010082 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010083 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000084
Mark Brown4f340332013-01-11 08:55:43 +090085 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000086 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010087 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090088
Mark Browndd235ee2013-01-11 08:55:51 +090089 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090090 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090091
Mark Brownf2c32a82012-06-24 12:09:45 +010092 bool mic;
93 bool detecting;
94 int jack_flips;
95
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +010096 int hpdet_ip_version;
Mark Brown4f340332013-01-11 08:55:43 +090097
Chanwoo Choief70a212014-04-21 20:47:31 +090098 struct extcon_dev *edev;
Charles Keepax8e5838d2015-06-19 17:23:31 +010099
100 struct gpio_desc *micd_pol_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +0100101};
102
103static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +0100104 { ARIZONA_ACCDET_SRC, 1, 0 },
105 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100106};
107
Mark Brown6fed4d82013-04-01 22:03:06 +0100108static const struct arizona_micd_range micd_default_ranges[] = {
109 { .max = 11, .key = BTN_0 },
110 { .max = 28, .key = BTN_1 },
111 { .max = 54, .key = BTN_2 },
112 { .max = 100, .key = BTN_3 },
113 { .max = 186, .key = BTN_4 },
114 { .max = 430, .key = BTN_5 },
115};
116
117static const int arizona_micd_levels[] = {
118 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
119 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
120 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
121 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
122 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100123};
124
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900125static const unsigned int arizona_cable[] = {
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900126 EXTCON_MECHANICAL,
127 EXTCON_MICROPHONE,
128 EXTCON_HEADPHONE,
129 EXTCON_LINE_OUT,
130 EXTCON_NONE,
Mark Brownf2c32a82012-06-24 12:09:45 +0100131};
132
Mark Brown9dd5e532013-04-01 19:09:45 +0100133static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
134
Charles Keepax112bdfa2015-02-16 15:41:02 +0000135static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
136 bool clamp)
Mark Brown03409072013-02-12 13:00:31 +0000137{
138 struct arizona *arizona = info->arizona;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000139 unsigned int mask = 0, val = 0;
Mark Brown03409072013-02-12 13:00:31 +0000140 int ret;
141
Charles Keepax43f0acd2015-02-16 15:41:03 +0000142 switch (arizona->type) {
143 case WM5110:
Charles Keepax2b51f9c2015-04-30 23:43:37 +0900144 case WM8280:
Charles Keepax43f0acd2015-02-16 15:41:03 +0000145 mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
146 ARIZONA_HP1L_SHRTI;
147 if (clamp)
148 val = ARIZONA_HP1L_SHRTO;
149 else
150 val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
151 break;
152 default:
153 mask = ARIZONA_RMV_SHRT_HP1L;
154 if (clamp)
155 val = ARIZONA_RMV_SHRT_HP1L;
156 break;
157 };
Charles Keepax112bdfa2015-02-16 15:41:02 +0000158
Mark Brown03409072013-02-12 13:00:31 +0000159 mutex_lock(&arizona->dapm->card->dapm_mutex);
160
Charles Keepax112bdfa2015-02-16 15:41:02 +0000161 arizona->hpdet_clamp = clamp;
Mark Browndf8c3db2013-02-22 18:38:03 +0000162
Charles Keepax112bdfa2015-02-16 15:41:02 +0000163 /* Keep the HP output stages disabled while doing the clamp */
164 if (clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000165 ret = regmap_update_bits(arizona->regmap,
166 ARIZONA_OUTPUT_ENABLES_1,
167 ARIZONA_OUT1L_ENA |
168 ARIZONA_OUT1R_ENA, 0);
169 if (ret != 0)
170 dev_warn(arizona->dev,
171 "Failed to disable headphone outputs: %d\n",
172 ret);
Mark Brown03409072013-02-12 13:00:31 +0000173 }
174
Charles Keepax112bdfa2015-02-16 15:41:02 +0000175 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
Charles Keepax43f0acd2015-02-16 15:41:03 +0000176 mask, val);
Mark Browndf8c3db2013-02-22 18:38:03 +0000177 if (ret != 0)
Charles Keepax112bdfa2015-02-16 15:41:02 +0000178 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000179 ret);
180
Charles Keepax112bdfa2015-02-16 15:41:02 +0000181 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
Charles Keepax43f0acd2015-02-16 15:41:03 +0000182 mask, val);
Mark Browndf8c3db2013-02-22 18:38:03 +0000183 if (ret != 0)
Charles Keepax112bdfa2015-02-16 15:41:02 +0000184 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Browndf8c3db2013-02-22 18:38:03 +0000185 ret);
186
Charles Keepax112bdfa2015-02-16 15:41:02 +0000187 /* Restore the desired state while not doing the clamp */
188 if (!clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000189 ret = regmap_update_bits(arizona->regmap,
190 ARIZONA_OUTPUT_ENABLES_1,
191 ARIZONA_OUT1L_ENA |
192 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000193 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000194 dev_warn(arizona->dev,
195 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000196 ret);
197 }
198
199 mutex_unlock(&arizona->dapm->card->dapm_mutex);
200}
201
Mark Brownf2c32a82012-06-24 12:09:45 +0100202static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
203{
204 struct arizona *arizona = info->arizona;
205
Mark Brown6fed4d82013-04-01 22:03:06 +0100206 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800207
Mark Browncd74f7b2012-11-27 16:14:26 +0900208 if (arizona->pdata.micd_pol_gpio > 0)
209 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
210 info->micd_modes[mode].gpio);
Charles Keepax8e5838d2015-06-19 17:23:31 +0100211 else
212 gpiod_set_value_cansleep(info->micd_pol_gpio,
213 info->micd_modes[mode].gpio);
214
Mark Brownf2c32a82012-06-24 12:09:45 +0100215 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
216 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100217 info->micd_modes[mode].bias <<
218 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100219 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
220 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
221
222 info->micd_mode = mode;
223
224 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
225}
226
Mark Brownbbbd46e2013-01-10 19:38:43 +0000227static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
228{
Charles Keepax41024242013-09-23 14:33:59 +0100229 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000230 case 1:
231 return "MICBIAS1";
232 case 2:
233 return "MICBIAS2";
234 case 3:
235 return "MICBIAS3";
236 default:
237 return "MICVDD";
238 }
239}
240
241static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
242{
243 struct arizona *arizona = info->arizona;
244 const char *widget = arizona_extcon_get_micbias(info);
245 struct snd_soc_dapm_context *dapm = arizona->dapm;
246 int ret;
247
Mark Brownbbbd46e2013-01-10 19:38:43 +0000248 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
249 if (ret != 0)
250 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
251 widget, ret);
252
Mark Brownbbbd46e2013-01-10 19:38:43 +0000253 snd_soc_dapm_sync(dapm);
254
255 if (!arizona->pdata.micd_force_micbias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000256 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
257 if (ret != 0)
258 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
259 widget, ret);
260
Mark Brownbbbd46e2013-01-10 19:38:43 +0000261 snd_soc_dapm_sync(dapm);
262 }
263}
264
Mark Brown9b1270c2013-01-11 08:55:46 +0900265static void arizona_start_mic(struct arizona_extcon_info *info)
266{
267 struct arizona *arizona = info->arizona;
268 bool change;
269 int ret;
270
Mark Brown9b1270c2013-01-11 08:55:46 +0900271 /* Microphone detection can't use idle mode */
272 pm_runtime_get(info->dev);
273
Mark Brownbbbd46e2013-01-10 19:38:43 +0000274 if (info->detecting) {
275 ret = regulator_allow_bypass(info->micvdd, false);
276 if (ret != 0) {
277 dev_err(arizona->dev,
278 "Failed to regulate MICVDD: %d\n",
279 ret);
280 }
281 }
282
Mark Brown9b1270c2013-01-11 08:55:46 +0900283 ret = regulator_enable(info->micvdd);
284 if (ret != 0) {
285 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
286 ret);
287 }
288
289 if (info->micd_reva) {
290 regmap_write(arizona->regmap, 0x80, 0x3);
291 regmap_write(arizona->regmap, 0x294, 0);
292 regmap_write(arizona->regmap, 0x80, 0x0);
293 }
294
295 regmap_update_bits(arizona->regmap,
296 ARIZONA_ACCESSORY_DETECT_MODE_1,
297 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
298
Mark Brownbbbd46e2013-01-10 19:38:43 +0000299 arizona_extcon_pulse_micbias(info);
300
Mark Brown9b1270c2013-01-11 08:55:46 +0900301 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
302 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
303 &change);
304 if (!change) {
305 regulator_disable(info->micvdd);
306 pm_runtime_put_autosuspend(info->dev);
307 }
308}
309
310static void arizona_stop_mic(struct arizona_extcon_info *info)
311{
312 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000313 const char *widget = arizona_extcon_get_micbias(info);
314 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900315 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000316 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900317
318 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
319 ARIZONA_MICD_ENA, 0,
320 &change);
321
Mark Brownbbbd46e2013-01-10 19:38:43 +0000322 ret = snd_soc_dapm_disable_pin(dapm, widget);
323 if (ret != 0)
324 dev_warn(arizona->dev,
325 "Failed to disable %s: %d\n",
326 widget, ret);
327
Mark Brownbbbd46e2013-01-10 19:38:43 +0000328 snd_soc_dapm_sync(dapm);
329
Mark Brown9b1270c2013-01-11 08:55:46 +0900330 if (info->micd_reva) {
331 regmap_write(arizona->regmap, 0x80, 0x3);
332 regmap_write(arizona->regmap, 0x294, 2);
333 regmap_write(arizona->regmap, 0x80, 0x0);
334 }
335
Mark Brownbbbd46e2013-01-10 19:38:43 +0000336 ret = regulator_allow_bypass(info->micvdd, true);
337 if (ret != 0) {
338 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
339 ret);
340 }
341
Mark Brown9b1270c2013-01-11 08:55:46 +0900342 if (change) {
343 regulator_disable(info->micvdd);
344 pm_runtime_mark_last_busy(info->dev);
345 pm_runtime_put_autosuspend(info->dev);
346 }
347}
348
Mark Brown4f340332013-01-11 08:55:43 +0900349static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100350 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900351 unsigned int factor_a;
352 unsigned int factor_b;
353} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100354 { 100, 5528, 362464 },
355 { 169, 11084, 6186851 },
356 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900357};
358
Charles Keepax24a279b2014-05-30 13:19:17 +0100359#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
360
Mark Brown4f340332013-01-11 08:55:43 +0900361static struct {
362 int min;
363 int max;
364} arizona_hpdet_c_ranges[] = {
365 { 0, 30 },
366 { 8, 100 },
367 { 100, 1000 },
368 { 1000, 10000 },
369};
370
371static int arizona_hpdet_read(struct arizona_extcon_info *info)
372{
373 struct arizona *arizona = info->arizona;
374 unsigned int val, range;
375 int ret;
376
377 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
378 if (ret != 0) {
379 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
380 ret);
381 return ret;
382 }
383
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100384 switch (info->hpdet_ip_version) {
Mark Brown4f340332013-01-11 08:55:43 +0900385 case 0:
386 if (!(val & ARIZONA_HP_DONE)) {
387 dev_err(arizona->dev, "HPDET did not complete: %x\n",
388 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900389 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900390 }
391
392 val &= ARIZONA_HP_LVL_MASK;
393 break;
394
395 case 1:
396 if (!(val & ARIZONA_HP_DONE_B)) {
397 dev_err(arizona->dev, "HPDET did not complete: %x\n",
398 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900399 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900400 }
401
402 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
403 if (ret != 0) {
404 dev_err(arizona->dev, "Failed to read HP value: %d\n",
405 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900406 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900407 }
408
409 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
410 &range);
411 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
412 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
413
414 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100415 (val < arizona_hpdet_b_ranges[range].threshold ||
416 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900417 range++;
418 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
419 range);
420 regmap_update_bits(arizona->regmap,
421 ARIZONA_HEADPHONE_DETECT_1,
422 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
423 range <<
424 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
425 return -EAGAIN;
426 }
427
428 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100429 if (val < arizona_hpdet_b_ranges[range].threshold ||
430 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900431 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100432 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900433 }
434
435 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
436 val, range);
437
438 val = arizona_hpdet_b_ranges[range].factor_b
439 / ((val * 100) -
440 arizona_hpdet_b_ranges[range].factor_a);
441 break;
442
443 default:
444 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100445 info->hpdet_ip_version);
Mark Brown4f340332013-01-11 08:55:43 +0900446 case 2:
447 if (!(val & ARIZONA_HP_DONE_B)) {
448 dev_err(arizona->dev, "HPDET did not complete: %x\n",
449 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900450 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900451 }
452
453 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000454 /* Convert to ohms, the value is in 0.5 ohm increments */
455 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900456
457 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
458 &range);
459 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
460 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
461
Charles Keepax91414612013-11-14 16:18:24 +0000462 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900463 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
464 (val >= arizona_hpdet_c_ranges[range].max)) {
465 range++;
466 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
467 arizona_hpdet_c_ranges[range].min,
468 arizona_hpdet_c_ranges[range].max);
469 regmap_update_bits(arizona->regmap,
470 ARIZONA_HEADPHONE_DETECT_1,
471 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
472 range <<
473 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
474 return -EAGAIN;
475 }
Charles Keepax91414612013-11-14 16:18:24 +0000476
477 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
478 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
479 arizona_hpdet_c_ranges[range].min);
480 val = arizona_hpdet_c_ranges[range].min;
481 }
Mark Brown4f340332013-01-11 08:55:43 +0900482 }
483
484 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
485 return val;
486}
487
Mark Brown9c2ba272013-02-25 23:42:31 +0000488static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
489 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900490{
491 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900492 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900493
494 /*
495 * If we're using HPDET for accessory identification we need
496 * to take multiple measurements, step through them in sequence.
497 */
498 if (arizona->pdata.hpdet_acc_id) {
499 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900500
501 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000502 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900503 dev_dbg(arizona->dev, "Measuring mic\n");
504
505 regmap_update_bits(arizona->regmap,
506 ARIZONA_ACCESSORY_DETECT_MODE_1,
507 ARIZONA_ACCDET_MODE_MASK |
508 ARIZONA_ACCDET_SRC,
509 ARIZONA_ACCDET_MODE_HPR |
510 info->micd_modes[0].src);
511
512 gpio_set_value_cansleep(id_gpio, 1);
513
Mark Browndd235ee2013-01-11 08:55:51 +0900514 regmap_update_bits(arizona->regmap,
515 ARIZONA_HEADPHONE_DETECT_1,
516 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
517 return -EAGAIN;
518 }
519
520 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000521 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
522 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000523
524 /* Take the headphone impedance for the main report */
525 *reading = info->hpdet_res[0];
526
Mark Brown9dd5e532013-04-01 19:09:45 +0100527 /* Sometimes we get false readings due to slow insert */
528 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
529 dev_dbg(arizona->dev, "Retrying high impedance\n");
530 info->num_hpdet_res = 0;
531 info->hpdet_retried = true;
532 arizona_start_hpdet_acc_id(info);
533 pm_runtime_put(info->dev);
534 return -EAGAIN;
535 }
536
Mark Brown1eda6aa2013-01-11 08:55:54 +0900537 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530538 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900539 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000540 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900541 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000542 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000543 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900544 } else {
545 dev_dbg(arizona->dev, "Detected headphone\n");
546 }
547
548 /* Make sure everything is reset back to the real polarity */
549 regmap_update_bits(arizona->regmap,
550 ARIZONA_ACCESSORY_DETECT_MODE_1,
551 ARIZONA_ACCDET_SRC,
552 info->micd_modes[0].src);
553 }
554
555 return 0;
556}
557
Mark Brown4f340332013-01-11 08:55:43 +0900558static irqreturn_t arizona_hpdet_irq(int irq, void *data)
559{
560 struct arizona_extcon_info *info = data;
561 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900562 int id_gpio = arizona->pdata.hpdet_id_gpio;
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900563 unsigned int report = EXTCON_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900564 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000565 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900566
567 mutex_lock(&info->lock);
568
569 /* If we got a spurious IRQ for some reason then ignore it */
570 if (!info->hpdet_active) {
571 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
572 mutex_unlock(&info->lock);
573 return IRQ_NONE;
574 }
575
576 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900577 ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900578 if (ret < 0) {
579 dev_err(arizona->dev, "Failed to check cable state: %d\n",
580 ret);
581 goto out;
582 } else if (!ret) {
583 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
584 goto done;
585 }
586
587 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900588 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900589 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900590 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900591 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900592 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900593
594 /* Reset back to starting range */
595 regmap_update_bits(arizona->regmap,
596 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900597 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
598 0);
599
Mark Brown9c2ba272013-02-25 23:42:31 +0000600 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900601 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900602 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900603 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900604 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900605
606 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900607 if (reading >= 5000)
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900608 report = EXTCON_LINE_OUT;
Mark Brown4f340332013-01-11 08:55:43 +0900609 else
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900610 report = EXTCON_HEADPHONE;
Mark Brown4f340332013-01-11 08:55:43 +0900611
Chanwoo Choief70a212014-04-21 20:47:31 +0900612 ret = extcon_set_cable_state_(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900613 if (ret != 0)
614 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
615 ret);
616
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000617done:
618 /* Reset back to starting range */
619 regmap_update_bits(arizona->regmap,
620 ARIZONA_HEADPHONE_DETECT_1,
621 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
622 0);
623
Charles Keepax112bdfa2015-02-16 15:41:02 +0000624 arizona_extcon_hp_clamp(info, false);
Mark Brown4f340332013-01-11 08:55:43 +0900625
Mark Brown1eda6aa2013-01-11 08:55:54 +0900626 if (id_gpio)
627 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900628
629 /* Revert back to MICDET mode */
630 regmap_update_bits(arizona->regmap,
631 ARIZONA_ACCESSORY_DETECT_MODE_1,
632 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
633
634 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000635 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900636 arizona_start_mic(info);
637
638 if (info->hpdet_active) {
639 pm_runtime_put_autosuspend(info->dev);
640 info->hpdet_active = false;
641 }
642
Mark Brownbf14ee52013-02-05 20:20:17 +0000643 info->hpdet_done = true;
644
Mark Brown4f340332013-01-11 08:55:43 +0900645out:
646 mutex_unlock(&info->lock);
647
648 return IRQ_HANDLED;
649}
650
651static void arizona_identify_headphone(struct arizona_extcon_info *info)
652{
653 struct arizona *arizona = info->arizona;
654 int ret;
655
Mark Brownbf14ee52013-02-05 20:20:17 +0000656 if (info->hpdet_done)
657 return;
658
Mark Brown4f340332013-01-11 08:55:43 +0900659 dev_dbg(arizona->dev, "Starting HPDET\n");
660
661 /* Make sure we keep the device enabled during the measurement */
662 pm_runtime_get(info->dev);
663
664 info->hpdet_active = true;
665
666 if (info->mic)
667 arizona_stop_mic(info);
668
Charles Keepax112bdfa2015-02-16 15:41:02 +0000669 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900670
671 ret = regmap_update_bits(arizona->regmap,
672 ARIZONA_ACCESSORY_DETECT_MODE_1,
673 ARIZONA_ACCDET_MODE_MASK,
Inha Song9e86b2a2015-05-04 13:42:13 +0900674 arizona->pdata.hpdet_channel);
Mark Brown4f340332013-01-11 08:55:43 +0900675 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900676 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +0900677 goto err;
678 }
679
680 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
681 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
682 if (ret != 0) {
683 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
684 ret);
685 goto err;
686 }
687
688 return;
689
690err:
691 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
692 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
693
694 /* Just report headphone */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900695 ret = extcon_set_cable_state_(info->edev, EXTCON_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 |
Inha Song9e86b2a2015-05-04 13:42:13 +0900725 arizona->pdata.hpdet_channel);
Mark Browndd235ee2013-01-11 08:55:51 +0900726 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900727 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Browndd235ee2013-01-11 08:55:51 +0900728 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 */
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900752 ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900753 if (ret != 0)
754 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
755
Mark Brown4f340332013-01-11 08:55:43 +0900756 info->hpdet_active = false;
757}
758
Mark Brown939c5672013-04-01 19:17:34 +0100759static void arizona_micd_timeout_work(struct work_struct *work)
760{
761 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900762 struct arizona_extcon_info,
763 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100764
765 mutex_lock(&info->lock);
766
767 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
Mark Brown939c5672013-04-01 19:17:34 +0100768
769 info->detecting = false;
770
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100771 arizona_identify_headphone(info);
772
Mark Brown939c5672013-04-01 19:17:34 +0100773 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 Choi2a9de9c2015-04-24 19:16:05 +0900792 ret = extcon_get_cable_state_(info->edev, EXTCON_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");
Charles Keepax57f70ef2015-06-25 16:47:02 +0100832 info->mic = false;
833 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100834 info->detecting = false;
Charles Keepax57f70ef2015-06-25 16:47:02 +0100835 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100836 goto handled;
837 }
838
839 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000840 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100841 info->mic = true;
842 info->detecting = false;
843
Mark Brown4f340332013-01-11 08:55:43 +0900844 arizona_identify_headphone(info);
845
Nikesh Oswal34602482014-05-29 16:27:52 +0100846 ret = extcon_set_cable_state_(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900847 EXTCON_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100848 if (ret != 0)
849 dev_err(arizona->dev, "Headset report failed: %d\n",
850 ret);
851
Mark Brownbbbd46e2013-01-10 19:38:43 +0000852 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100853 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000854 if (ret != 0) {
855 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
856 ret);
857 }
858
Mark Brownf2c32a82012-06-24 12:09:45 +0100859 goto handled;
860 }
861
862 /* If we detected a lower impedence during initial startup
863 * then we probably have the wrong polarity, flip it. Don't
864 * do this for the lowest impedences to speed up detection of
865 * plain headphones. If both polarities report a low
866 * impedence then give up and report headphones.
867 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000868 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800869 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900870 dev_dbg(arizona->dev, "Detected HP/line\n");
Mark Brown9ef2224d2012-06-28 13:08:31 +0100871
Mark Brown4f340332013-01-11 08:55:43 +0900872 info->detecting = false;
873
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100874 arizona_identify_headphone(info);
875
Mark Brown4f340332013-01-11 08:55:43 +0900876 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100877 } else {
878 info->micd_mode++;
879 if (info->micd_mode == info->micd_num_modes)
880 info->micd_mode = 0;
881 arizona_extcon_set_mode(info, info->micd_mode);
882
883 info->jack_flips++;
884 }
885
886 goto handled;
887 }
888
889 /*
890 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100891 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100892 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000893 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100894 if (info->mic) {
895 dev_dbg(arizona->dev, "Mic button detected\n");
896
Mark Brown34efe4d2012-07-20 17:07:29 +0100897 lvl = val & ARIZONA_MICD_LVL_MASK;
898 lvl >>= ARIZONA_MICD_LVL_SHIFT;
899
Mark Brown41a57852013-04-01 19:18:18 +0100900 for (i = 0; i < info->num_micd_ranges; i++)
901 input_report_key(info->input,
902 info->micd_ranges[i].key, 0);
903
Mark Brown6fed4d82013-04-01 22:03:06 +0100904 WARN_ON(!lvl);
905 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
906 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
907 key = info->micd_ranges[ffs(lvl) - 1].key;
908 input_report_key(info->input, key, 1);
909 input_sync(info->input);
910 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100911
Mark Brownf2c32a82012-06-24 12:09:45 +0100912 } else if (info->detecting) {
913 dev_dbg(arizona->dev, "Headphone detected\n");
914 info->detecting = false;
915 arizona_stop_mic(info);
916
Mark Brown4f340332013-01-11 08:55:43 +0900917 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100918 } else {
919 dev_warn(arizona->dev, "Button with no mic: %x\n",
920 val);
921 }
922 } else {
923 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100924 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100925 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100926 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100927 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000928 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100929 }
930
931handled:
Mark Brown939c5672013-04-01 19:17:34 +0100932 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100933 queue_delayed_work(system_power_efficient_wq,
934 &info->micd_timeout_work,
935 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100936
Mark Brownf2c32a82012-06-24 12:09:45 +0100937 pm_runtime_mark_last_busy(info->dev);
938 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100939}
940
941static irqreturn_t arizona_micdet(int irq, void *data)
942{
943 struct arizona_extcon_info *info = data;
944 struct arizona *arizona = info->arizona;
945 int debounce = arizona->pdata.micd_detect_debounce;
946
947 cancel_delayed_work_sync(&info->micd_detect_work);
948 cancel_delayed_work_sync(&info->micd_timeout_work);
949
950 mutex_lock(&info->lock);
951 if (!info->detecting)
952 debounce = 0;
953 mutex_unlock(&info->lock);
954
955 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100956 queue_delayed_work(system_power_efficient_wq,
957 &info->micd_detect_work,
958 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100959 else
960 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100961
962 return IRQ_HANDLED;
963}
964
Mark Brown0e27bd32013-02-05 21:00:15 +0000965static void arizona_hpdet_work(struct work_struct *work)
966{
967 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900968 struct arizona_extcon_info,
969 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000970
971 mutex_lock(&info->lock);
972 arizona_start_hpdet_acc_id(info);
973 mutex_unlock(&info->lock);
974}
975
Mark Brownf2c32a82012-06-24 12:09:45 +0100976static irqreturn_t arizona_jackdet(int irq, void *data)
977{
978 struct arizona_extcon_info *info = data;
979 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900980 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100981 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100982 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100983
Mark Brown939c5672013-04-01 19:17:34 +0100984 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
985 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100986
Mark Browna3e20782013-04-01 19:05:27 +0100987 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000988
Mark Brownf2c32a82012-06-24 12:09:45 +0100989 mutex_lock(&info->lock);
990
Mark Brown92a49872013-01-11 08:55:39 +0900991 if (arizona->pdata.jd_gpio5) {
992 mask = ARIZONA_MICD_CLAMP_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100993 if (arizona->pdata.jd_invert)
994 present = ARIZONA_MICD_CLAMP_STS;
995 else
996 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +0900997 } else {
998 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100999 if (arizona->pdata.jd_invert)
1000 present = 0;
1001 else
1002 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +09001003 }
1004
Mark Brownf2c32a82012-06-24 12:09:45 +01001005 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
1006 if (ret != 0) {
1007 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
1008 ret);
1009 mutex_unlock(&info->lock);
1010 pm_runtime_put_autosuspend(info->dev);
1011 return IRQ_NONE;
1012 }
1013
Mark Browna3e20782013-04-01 19:05:27 +01001014 val &= mask;
1015 if (val == info->last_jackdet) {
1016 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001017 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001018 queue_delayed_work(system_power_efficient_wq,
1019 &info->hpdet_work,
1020 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001021
Chanwoo Choic2275d22013-08-23 10:21:37 +09001022 if (cancelled_mic) {
1023 int micd_timeout = info->micd_timeout;
1024
Mark Browndf9a5ab2013-07-18 22:42:22 +01001025 queue_delayed_work(system_power_efficient_wq,
1026 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001027 msecs_to_jiffies(micd_timeout));
1028 }
Mark Brown939c5672013-04-01 19:17:34 +01001029
Mark Browna3e20782013-04-01 19:05:27 +01001030 goto out;
1031 }
1032 info->last_jackdet = val;
1033
1034 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001035 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choief70a212014-04-21 20:47:31 +09001036 ret = extcon_set_cable_state_(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +09001037 EXTCON_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001038
1039 if (ret != 0)
1040 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1041 ret);
1042
Mark Browndd235ee2013-01-11 08:55:51 +09001043 if (!arizona->pdata.hpdet_acc_id) {
1044 info->detecting = true;
1045 info->mic = false;
1046 info->jack_flips = 0;
1047
1048 arizona_start_mic(info);
1049 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001050 queue_delayed_work(system_power_efficient_wq,
1051 &info->hpdet_work,
1052 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001053 }
Mark Brown4e616872013-01-15 22:09:20 +09001054
1055 regmap_update_bits(arizona->regmap,
1056 ARIZONA_JACK_DETECT_DEBOUNCE,
1057 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001058 } else {
1059 dev_dbg(arizona->dev, "Detected jack removal\n");
1060
1061 arizona_stop_mic(info);
1062
Mark Browndd235ee2013-01-11 08:55:51 +09001063 info->num_hpdet_res = 0;
1064 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1065 info->hpdet_res[i] = 0;
1066 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001067 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001068 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001069
Mark Brown6fed4d82013-04-01 22:03:06 +01001070 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001071 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001072 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001073 input_sync(info->input);
1074
Chanwoo Choief70a212014-04-21 20:47:31 +09001075 ret = extcon_update_state(info->edev, 0xffffffff, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001076 if (ret != 0)
1077 dev_err(arizona->dev, "Removal report failed: %d\n",
1078 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001079
1080 regmap_update_bits(arizona->regmap,
1081 ARIZONA_JACK_DETECT_DEBOUNCE,
1082 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1083 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001084 }
1085
Mark Brown7abd4e22013-04-01 19:25:55 +01001086 if (arizona->pdata.micd_timeout)
1087 info->micd_timeout = arizona->pdata.micd_timeout;
1088 else
1089 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1090
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001091out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001092 /* Clear trig_sts to make sure DCVDD is not forced up */
1093 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1094 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1095 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1096 ARIZONA_JD1_FALL_TRIG_STS |
1097 ARIZONA_JD1_RISE_TRIG_STS);
1098
Mark Brownf2c32a82012-06-24 12:09:45 +01001099 mutex_unlock(&info->lock);
1100
1101 pm_runtime_mark_last_busy(info->dev);
1102 pm_runtime_put_autosuspend(info->dev);
1103
1104 return IRQ_HANDLED;
1105}
1106
Mark Brown6fed4d82013-04-01 22:03:06 +01001107/* Map a level onto a slot in the register bank */
1108static void arizona_micd_set_level(struct arizona *arizona, int index,
1109 unsigned int level)
1110{
1111 int reg;
1112 unsigned int mask;
1113
1114 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1115
1116 if (!(index % 2)) {
1117 mask = 0x3f00;
1118 level <<= 8;
1119 } else {
1120 mask = 0x3f;
1121 }
1122
1123 /* Program the level itself */
1124 regmap_update_bits(arizona->regmap, reg, mask, level);
1125}
1126
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001127static int arizona_extcon_device_get_pdata(struct arizona *arizona)
Inha Song9e86b2a2015-05-04 13:42:13 +09001128{
1129 struct arizona_pdata *pdata = &arizona->pdata;
1130 unsigned int val = ARIZONA_ACCDET_MODE_HPL;
1131
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001132 device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
Inha Song9e86b2a2015-05-04 13:42:13 +09001133 switch (val) {
1134 case ARIZONA_ACCDET_MODE_HPL:
1135 case ARIZONA_ACCDET_MODE_HPR:
1136 pdata->hpdet_channel = val;
1137 break;
1138 default:
1139 dev_err(arizona->dev,
1140 "Wrong wlf,hpdet-channel DT value %d\n", val);
1141 pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
1142 }
1143
Charles Keepax4778d442015-06-19 17:23:30 +01001144 device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
1145 &pdata->micd_detect_debounce);
1146
1147 device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
1148 &pdata->micd_bias_start_time);
1149
1150 device_property_read_u32(arizona->dev, "wlf,micd-rate",
1151 &pdata->micd_rate);
1152
1153 device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
1154 &pdata->micd_dbtime);
1155
1156 device_property_read_u32(arizona->dev, "wlf,micd-timeout",
1157 &pdata->micd_timeout);
1158
1159 pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
1160 "wlf,micd-force-micbias");
1161
Inha Song9e86b2a2015-05-04 13:42:13 +09001162 return 0;
1163}
1164
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001165static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001166{
1167 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001168 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001169 struct arizona_extcon_info *info;
Mark Browne56a0a572013-04-01 19:03:52 +01001170 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001171 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001172 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001173 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001174
Mark Brownbbbd46e2013-01-10 19:38:43 +00001175 if (!arizona->dapm || !arizona->dapm->card)
1176 return -EPROBE_DEFER;
1177
Mark Brownf2c32a82012-06-24 12:09:45 +01001178 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001179 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001180 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001181
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001182 if (!dev_get_platdata(arizona->dev))
1183 arizona_extcon_device_get_pdata(arizona);
Inha Song9e86b2a2015-05-04 13:42:13 +09001184
Charles Keepax17271f62014-07-18 12:59:00 +01001185 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001186 if (IS_ERR(info->micvdd)) {
1187 ret = PTR_ERR(info->micvdd);
1188 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001189 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001190 }
1191
1192 mutex_init(&info->lock);
1193 info->arizona = arizona;
1194 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001195 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001196 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001197 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001198 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001199 platform_set_drvdata(pdev, info);
1200
1201 switch (arizona->type) {
1202 case WM5102:
1203 switch (arizona->rev) {
1204 case 0:
1205 info->micd_reva = true;
1206 break;
1207 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001208 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001209 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001210 break;
1211 }
1212 break;
Charles Keepax77438612013-11-14 16:18:25 +00001213 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001214 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001215 switch (arizona->rev) {
1216 case 0 ... 2:
1217 break;
1218 default:
1219 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001220 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001221 break;
1222 }
1223 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001224 default:
1225 break;
1226 }
1227
Chanwoo Choief70a212014-04-21 20:47:31 +09001228 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1229 if (IS_ERR(info->edev)) {
1230 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1231 return -ENOMEM;
1232 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001233
Chanwoo Choief70a212014-04-21 20:47:31 +09001234 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001235 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001236 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001237 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001238 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001239 }
1240
Mark Brown6fed4d82013-04-01 22:03:06 +01001241 info->input = devm_input_allocate_device(&pdev->dev);
1242 if (!info->input) {
1243 dev_err(arizona->dev, "Can't allocate input dev\n");
1244 ret = -ENOMEM;
1245 goto err_register;
1246 }
1247
1248 info->input->name = "Headset";
1249 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001250
Mark Brownf2c32a82012-06-24 12:09:45 +01001251 if (pdata->num_micd_configs) {
1252 info->micd_modes = pdata->micd_configs;
1253 info->micd_num_modes = pdata->num_micd_configs;
1254 } else {
1255 info->micd_modes = micd_default_modes;
1256 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1257 }
1258
1259 if (arizona->pdata.micd_pol_gpio > 0) {
1260 if (info->micd_modes[0].gpio)
1261 mode = GPIOF_OUT_INIT_HIGH;
1262 else
1263 mode = GPIOF_OUT_INIT_LOW;
1264
1265 ret = devm_gpio_request_one(&pdev->dev,
1266 arizona->pdata.micd_pol_gpio,
1267 mode,
1268 "MICD polarity");
1269 if (ret != 0) {
1270 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1271 arizona->pdata.micd_pol_gpio, ret);
1272 goto err_register;
1273 }
Charles Keepax8e5838d2015-06-19 17:23:31 +01001274 } else {
1275 if (info->micd_modes[0].gpio)
1276 mode = GPIOD_OUT_HIGH;
1277 else
1278 mode = GPIOD_OUT_LOW;
1279
1280 /* We can't use devm here because we need to do the get
1281 * against the MFD device, as that is where the of_node
1282 * will reside, but if we devm against that the GPIO
1283 * will not be freed if the extcon driver is unloaded.
1284 */
1285 info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
1286 "wlf,micd-pol",
1287 GPIOD_OUT_LOW);
1288 if (IS_ERR(info->micd_pol_gpio)) {
1289 ret = PTR_ERR(info->micd_pol_gpio);
1290 dev_err(arizona->dev,
1291 "Failed to get microphone polarity GPIO: %d\n",
1292 ret);
1293 goto err_register;
1294 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001295 }
1296
Mark Brown1eda6aa2013-01-11 08:55:54 +09001297 if (arizona->pdata.hpdet_id_gpio > 0) {
1298 ret = devm_gpio_request_one(&pdev->dev,
1299 arizona->pdata.hpdet_id_gpio,
1300 GPIOF_OUT_INIT_LOW,
1301 "HPDET");
1302 if (ret != 0) {
1303 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1304 arizona->pdata.hpdet_id_gpio, ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001305 goto err_gpio;
Mark Brown1eda6aa2013-01-11 08:55:54 +09001306 }
1307 }
1308
Mark Brownb17e5462013-01-11 08:55:24 +09001309 if (arizona->pdata.micd_bias_start_time)
1310 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1311 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1312 arizona->pdata.micd_bias_start_time
1313 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1314
Mark Brown2e033db2013-01-21 17:36:33 +09001315 if (arizona->pdata.micd_rate)
1316 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1317 ARIZONA_MICD_RATE_MASK,
1318 arizona->pdata.micd_rate
1319 << ARIZONA_MICD_RATE_SHIFT);
1320
1321 if (arizona->pdata.micd_dbtime)
1322 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1323 ARIZONA_MICD_DBTIME_MASK,
1324 arizona->pdata.micd_dbtime
1325 << ARIZONA_MICD_DBTIME_SHIFT);
1326
Mark Brown6fed4d82013-04-01 22:03:06 +01001327 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1328
1329 if (arizona->pdata.num_micd_ranges) {
1330 info->micd_ranges = pdata->micd_ranges;
1331 info->num_micd_ranges = pdata->num_micd_ranges;
1332 } else {
1333 info->micd_ranges = micd_default_ranges;
1334 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1335 }
1336
1337 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1338 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1339 arizona->pdata.num_micd_ranges);
1340 }
1341
1342 if (info->num_micd_ranges > 1) {
1343 for (i = 1; i < info->num_micd_ranges; i++) {
1344 if (info->micd_ranges[i - 1].max >
1345 info->micd_ranges[i].max) {
1346 dev_err(arizona->dev,
1347 "MICD ranges must be sorted\n");
1348 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001349 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001350 }
1351 }
1352 }
1353
1354 /* Disable all buttons by default */
1355 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1356 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1357
1358 /* Set up all the buttons the user specified */
1359 for (i = 0; i < info->num_micd_ranges; i++) {
1360 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1361 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1362 break;
1363
1364 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1365 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1366 info->micd_ranges[i].max);
1367 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001368 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001369 }
1370
1371 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1372 arizona_micd_levels[j], i);
1373
1374 arizona_micd_set_level(arizona, i, j);
1375 input_set_capability(info->input, EV_KEY,
1376 info->micd_ranges[i].key);
1377
1378 /* Enable reporting of that range */
1379 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1380 1 << i, 1 << i);
1381 }
1382
1383 /* Set all the remaining keys to a maximum */
1384 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1385 arizona_micd_set_level(arizona, i, 0x3f);
1386
Mark Browndab63eb2013-01-11 08:55:36 +09001387 /*
Mark Brown92a49872013-01-11 08:55:39 +09001388 * If we have a clamp use it, activating in conjunction with
1389 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001390 */
1391 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001392 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a572013-04-01 19:03:52 +01001393 /* Put the GPIO into input mode with optional pull */
1394 val = 0xc101;
1395 if (arizona->pdata.jd_gpio5_nopull)
1396 val &= ~ARIZONA_GPN_PU;
1397
Mark Brown92a49872013-01-11 08:55:39 +09001398 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a572013-04-01 19:03:52 +01001399 val);
Mark Brown92a49872013-01-11 08:55:39 +09001400
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001401 if (arizona->pdata.jd_invert)
1402 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1403 else
1404 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001405 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001406 if (arizona->pdata.jd_invert)
1407 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1408 else
1409 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001410 }
1411
Mark Browndab63eb2013-01-11 08:55:36 +09001412 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001413 ARIZONA_MICD_CLAMP_CONTROL,
1414 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1415
1416 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001417 ARIZONA_JACK_DETECT_DEBOUNCE,
1418 ARIZONA_MICD_CLAMP_DB,
1419 ARIZONA_MICD_CLAMP_DB);
1420 }
1421
Mark Brownf2c32a82012-06-24 12:09:45 +01001422 arizona_extcon_set_mode(info, 0);
1423
1424 pm_runtime_enable(&pdev->dev);
1425 pm_runtime_idle(&pdev->dev);
1426 pm_runtime_get_sync(&pdev->dev);
1427
Mark Brown92a49872013-01-11 08:55:39 +09001428 if (arizona->pdata.jd_gpio5) {
1429 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1430 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1431 } else {
1432 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1433 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1434 }
1435
1436 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001437 "JACKDET rise", arizona_jackdet, info);
1438 if (ret != 0) {
1439 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1440 ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001441 goto err_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +01001442 }
1443
Mark Brown92a49872013-01-11 08:55:39 +09001444 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001445 if (ret != 0) {
1446 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1447 ret);
1448 goto err_rise;
1449 }
1450
Mark Brown92a49872013-01-11 08:55:39 +09001451 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001452 "JACKDET fall", arizona_jackdet, info);
1453 if (ret != 0) {
1454 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1455 goto err_rise_wake;
1456 }
1457
Mark Brown92a49872013-01-11 08:55:39 +09001458 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001459 if (ret != 0) {
1460 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1461 ret);
1462 goto err_fall;
1463 }
1464
1465 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1466 "MICDET", arizona_micdet, info);
1467 if (ret != 0) {
1468 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1469 goto err_fall_wake;
1470 }
1471
Mark Brown4f340332013-01-11 08:55:43 +09001472 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1473 "HPDET", arizona_hpdet_irq, info);
1474 if (ret != 0) {
1475 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1476 goto err_micdet;
1477 }
1478
Mark Brownf2c32a82012-06-24 12:09:45 +01001479 arizona_clk32k_enable(arizona);
1480 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1481 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1482 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1483 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1484
Mark Brownb8575a12012-09-07 17:01:15 +08001485 ret = regulator_allow_bypass(info->micvdd, true);
1486 if (ret != 0)
1487 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1488 ret);
1489
Mark Brownf2c32a82012-06-24 12:09:45 +01001490 pm_runtime_put(&pdev->dev);
1491
Mark Brown34efe4d2012-07-20 17:07:29 +01001492 ret = input_register_device(info->input);
1493 if (ret) {
1494 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001495 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001496 }
1497
Mark Brownf2c32a82012-06-24 12:09:45 +01001498 return 0;
1499
Mark Brown4f340332013-01-11 08:55:43 +09001500err_hpdet:
1501 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001502err_micdet:
1503 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001504err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001505 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001506err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001507 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001508err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001509 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001510err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001511 arizona_free_irq(arizona, jack_irq_rise, info);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001512err_gpio:
1513 gpiod_put(info->micd_pol_gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +01001514err_register:
1515 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001516 return ret;
1517}
1518
Bill Pemberton93ed0322012-11-19 13:25:49 -05001519static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001520{
1521 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1522 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001523 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001524
Charles Keepax8e5838d2015-06-19 17:23:31 +01001525 gpiod_put(info->micd_pol_gpio);
1526
Mark Brownf2c32a82012-06-24 12:09:45 +01001527 pm_runtime_disable(&pdev->dev);
1528
Mark Browndab63eb2013-01-11 08:55:36 +09001529 regmap_update_bits(arizona->regmap,
1530 ARIZONA_MICD_CLAMP_CONTROL,
1531 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1532
Mark Brown92a49872013-01-11 08:55:39 +09001533 if (arizona->pdata.jd_gpio5) {
1534 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1535 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1536 } else {
1537 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1538 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1539 }
1540
1541 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1542 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1543 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001544 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001545 arizona_free_irq(arizona, jack_irq_rise, info);
1546 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001547 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001548 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1549 ARIZONA_JD1_ENA, 0);
1550 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001551
1552 return 0;
1553}
1554
1555static struct platform_driver arizona_extcon_driver = {
1556 .driver = {
1557 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001558 },
1559 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001560 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001561};
1562
1563module_platform_driver(arizona_extcon_driver);
1564
1565MODULE_DESCRIPTION("Arizona Extcon driver");
1566MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1567MODULE_LICENSE("GPL");
1568MODULE_ALIAS("platform:extcon-arizona");