blob: 2336de66f442b6faa0218e10ae478128b4ff14d1 [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");
832 info->detecting = false;
833 goto handled;
834 }
835
836 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000837 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100838 info->mic = true;
839 info->detecting = false;
840
Mark Brown4f340332013-01-11 08:55:43 +0900841 arizona_identify_headphone(info);
842
Nikesh Oswal34602482014-05-29 16:27:52 +0100843 ret = extcon_set_cable_state_(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900844 EXTCON_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100845 if (ret != 0)
846 dev_err(arizona->dev, "Headset report failed: %d\n",
847 ret);
848
Mark Brownbbbd46e2013-01-10 19:38:43 +0000849 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100850 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000851 if (ret != 0) {
852 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
853 ret);
854 }
855
Mark Brownf2c32a82012-06-24 12:09:45 +0100856 goto handled;
857 }
858
859 /* If we detected a lower impedence during initial startup
860 * then we probably have the wrong polarity, flip it. Don't
861 * do this for the lowest impedences to speed up detection of
862 * plain headphones. If both polarities report a low
863 * impedence then give up and report headphones.
864 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000865 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800866 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900867 dev_dbg(arizona->dev, "Detected HP/line\n");
Mark Brown9ef2224d2012-06-28 13:08:31 +0100868
Mark Brown4f340332013-01-11 08:55:43 +0900869 info->detecting = false;
870
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100871 arizona_identify_headphone(info);
872
Mark Brown4f340332013-01-11 08:55:43 +0900873 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100874 } else {
875 info->micd_mode++;
876 if (info->micd_mode == info->micd_num_modes)
877 info->micd_mode = 0;
878 arizona_extcon_set_mode(info, info->micd_mode);
879
880 info->jack_flips++;
881 }
882
883 goto handled;
884 }
885
886 /*
887 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100888 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100889 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000890 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100891 if (info->mic) {
892 dev_dbg(arizona->dev, "Mic button detected\n");
893
Mark Brown34efe4d2012-07-20 17:07:29 +0100894 lvl = val & ARIZONA_MICD_LVL_MASK;
895 lvl >>= ARIZONA_MICD_LVL_SHIFT;
896
Mark Brown41a57852013-04-01 19:18:18 +0100897 for (i = 0; i < info->num_micd_ranges; i++)
898 input_report_key(info->input,
899 info->micd_ranges[i].key, 0);
900
Mark Brown6fed4d82013-04-01 22:03:06 +0100901 WARN_ON(!lvl);
902 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
903 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
904 key = info->micd_ranges[ffs(lvl) - 1].key;
905 input_report_key(info->input, key, 1);
906 input_sync(info->input);
907 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100908
Mark Brownf2c32a82012-06-24 12:09:45 +0100909 } else if (info->detecting) {
910 dev_dbg(arizona->dev, "Headphone detected\n");
911 info->detecting = false;
912 arizona_stop_mic(info);
913
Mark Brown4f340332013-01-11 08:55:43 +0900914 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100915 } else {
916 dev_warn(arizona->dev, "Button with no mic: %x\n",
917 val);
918 }
919 } else {
920 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100921 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100922 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100923 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100924 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000925 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100926 }
927
928handled:
Mark Brown939c5672013-04-01 19:17:34 +0100929 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100930 queue_delayed_work(system_power_efficient_wq,
931 &info->micd_timeout_work,
932 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100933
Mark Brownf2c32a82012-06-24 12:09:45 +0100934 pm_runtime_mark_last_busy(info->dev);
935 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100936}
937
938static irqreturn_t arizona_micdet(int irq, void *data)
939{
940 struct arizona_extcon_info *info = data;
941 struct arizona *arizona = info->arizona;
942 int debounce = arizona->pdata.micd_detect_debounce;
943
944 cancel_delayed_work_sync(&info->micd_detect_work);
945 cancel_delayed_work_sync(&info->micd_timeout_work);
946
947 mutex_lock(&info->lock);
948 if (!info->detecting)
949 debounce = 0;
950 mutex_unlock(&info->lock);
951
952 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100953 queue_delayed_work(system_power_efficient_wq,
954 &info->micd_detect_work,
955 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100956 else
957 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100958
959 return IRQ_HANDLED;
960}
961
Mark Brown0e27bd32013-02-05 21:00:15 +0000962static void arizona_hpdet_work(struct work_struct *work)
963{
964 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900965 struct arizona_extcon_info,
966 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000967
968 mutex_lock(&info->lock);
969 arizona_start_hpdet_acc_id(info);
970 mutex_unlock(&info->lock);
971}
972
Mark Brownf2c32a82012-06-24 12:09:45 +0100973static irqreturn_t arizona_jackdet(int irq, void *data)
974{
975 struct arizona_extcon_info *info = data;
976 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900977 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100978 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100979 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100980
Mark Brown939c5672013-04-01 19:17:34 +0100981 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
982 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100983
Mark Browna3e20782013-04-01 19:05:27 +0100984 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000985
Mark Brownf2c32a82012-06-24 12:09:45 +0100986 mutex_lock(&info->lock);
987
Mark Brown92a49872013-01-11 08:55:39 +0900988 if (arizona->pdata.jd_gpio5) {
989 mask = ARIZONA_MICD_CLAMP_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100990 if (arizona->pdata.jd_invert)
991 present = ARIZONA_MICD_CLAMP_STS;
992 else
993 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +0900994 } else {
995 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +0100996 if (arizona->pdata.jd_invert)
997 present = 0;
998 else
999 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +09001000 }
1001
Mark Brownf2c32a82012-06-24 12:09:45 +01001002 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
1003 if (ret != 0) {
1004 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
1005 ret);
1006 mutex_unlock(&info->lock);
1007 pm_runtime_put_autosuspend(info->dev);
1008 return IRQ_NONE;
1009 }
1010
Mark Browna3e20782013-04-01 19:05:27 +01001011 val &= mask;
1012 if (val == info->last_jackdet) {
1013 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001014 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001015 queue_delayed_work(system_power_efficient_wq,
1016 &info->hpdet_work,
1017 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001018
Chanwoo Choic2275d22013-08-23 10:21:37 +09001019 if (cancelled_mic) {
1020 int micd_timeout = info->micd_timeout;
1021
Mark Browndf9a5ab2013-07-18 22:42:22 +01001022 queue_delayed_work(system_power_efficient_wq,
1023 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001024 msecs_to_jiffies(micd_timeout));
1025 }
Mark Brown939c5672013-04-01 19:17:34 +01001026
Mark Browna3e20782013-04-01 19:05:27 +01001027 goto out;
1028 }
1029 info->last_jackdet = val;
1030
1031 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001032 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choief70a212014-04-21 20:47:31 +09001033 ret = extcon_set_cable_state_(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +09001034 EXTCON_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001035
1036 if (ret != 0)
1037 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1038 ret);
1039
Mark Browndd235ee2013-01-11 08:55:51 +09001040 if (!arizona->pdata.hpdet_acc_id) {
1041 info->detecting = true;
1042 info->mic = false;
1043 info->jack_flips = 0;
1044
1045 arizona_start_mic(info);
1046 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001047 queue_delayed_work(system_power_efficient_wq,
1048 &info->hpdet_work,
1049 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001050 }
Mark Brown4e616872013-01-15 22:09:20 +09001051
1052 regmap_update_bits(arizona->regmap,
1053 ARIZONA_JACK_DETECT_DEBOUNCE,
1054 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001055 } else {
1056 dev_dbg(arizona->dev, "Detected jack removal\n");
1057
1058 arizona_stop_mic(info);
1059
Mark Browndd235ee2013-01-11 08:55:51 +09001060 info->num_hpdet_res = 0;
1061 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1062 info->hpdet_res[i] = 0;
1063 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001064 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001065 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001066
Mark Brown6fed4d82013-04-01 22:03:06 +01001067 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001068 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001069 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001070 input_sync(info->input);
1071
Chanwoo Choief70a212014-04-21 20:47:31 +09001072 ret = extcon_update_state(info->edev, 0xffffffff, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001073 if (ret != 0)
1074 dev_err(arizona->dev, "Removal report failed: %d\n",
1075 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001076
1077 regmap_update_bits(arizona->regmap,
1078 ARIZONA_JACK_DETECT_DEBOUNCE,
1079 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1080 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001081 }
1082
Mark Brown7abd4e22013-04-01 19:25:55 +01001083 if (arizona->pdata.micd_timeout)
1084 info->micd_timeout = arizona->pdata.micd_timeout;
1085 else
1086 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1087
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001088out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001089 /* Clear trig_sts to make sure DCVDD is not forced up */
1090 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1091 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1092 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1093 ARIZONA_JD1_FALL_TRIG_STS |
1094 ARIZONA_JD1_RISE_TRIG_STS);
1095
Mark Brownf2c32a82012-06-24 12:09:45 +01001096 mutex_unlock(&info->lock);
1097
1098 pm_runtime_mark_last_busy(info->dev);
1099 pm_runtime_put_autosuspend(info->dev);
1100
1101 return IRQ_HANDLED;
1102}
1103
Mark Brown6fed4d82013-04-01 22:03:06 +01001104/* Map a level onto a slot in the register bank */
1105static void arizona_micd_set_level(struct arizona *arizona, int index,
1106 unsigned int level)
1107{
1108 int reg;
1109 unsigned int mask;
1110
1111 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1112
1113 if (!(index % 2)) {
1114 mask = 0x3f00;
1115 level <<= 8;
1116 } else {
1117 mask = 0x3f;
1118 }
1119
1120 /* Program the level itself */
1121 regmap_update_bits(arizona->regmap, reg, mask, level);
1122}
1123
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001124static int arizona_extcon_device_get_pdata(struct arizona *arizona)
Inha Song9e86b2a2015-05-04 13:42:13 +09001125{
1126 struct arizona_pdata *pdata = &arizona->pdata;
1127 unsigned int val = ARIZONA_ACCDET_MODE_HPL;
1128
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001129 device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
Inha Song9e86b2a2015-05-04 13:42:13 +09001130 switch (val) {
1131 case ARIZONA_ACCDET_MODE_HPL:
1132 case ARIZONA_ACCDET_MODE_HPR:
1133 pdata->hpdet_channel = val;
1134 break;
1135 default:
1136 dev_err(arizona->dev,
1137 "Wrong wlf,hpdet-channel DT value %d\n", val);
1138 pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
1139 }
1140
Charles Keepax4778d442015-06-19 17:23:30 +01001141 device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
1142 &pdata->micd_detect_debounce);
1143
1144 device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
1145 &pdata->micd_bias_start_time);
1146
1147 device_property_read_u32(arizona->dev, "wlf,micd-rate",
1148 &pdata->micd_rate);
1149
1150 device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
1151 &pdata->micd_dbtime);
1152
1153 device_property_read_u32(arizona->dev, "wlf,micd-timeout",
1154 &pdata->micd_timeout);
1155
1156 pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
1157 "wlf,micd-force-micbias");
1158
Inha Song9e86b2a2015-05-04 13:42:13 +09001159 return 0;
1160}
1161
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001162static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001163{
1164 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001165 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001166 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001167 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001168 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001169 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001170 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001171
Mark Brownbbbd46e2013-01-10 19:38:43 +00001172 if (!arizona->dapm || !arizona->dapm->card)
1173 return -EPROBE_DEFER;
1174
Mark Brownf2c32a82012-06-24 12:09:45 +01001175 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001176 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001177 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001178
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001179 if (!dev_get_platdata(arizona->dev))
1180 arizona_extcon_device_get_pdata(arizona);
Inha Song9e86b2a2015-05-04 13:42:13 +09001181
Charles Keepax17271f62014-07-18 12:59:00 +01001182 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001183 if (IS_ERR(info->micvdd)) {
1184 ret = PTR_ERR(info->micvdd);
1185 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001186 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001187 }
1188
1189 mutex_init(&info->lock);
1190 info->arizona = arizona;
1191 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001192 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001193 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001194 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001195 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001196 platform_set_drvdata(pdev, info);
1197
1198 switch (arizona->type) {
1199 case WM5102:
1200 switch (arizona->rev) {
1201 case 0:
1202 info->micd_reva = true;
1203 break;
1204 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001205 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001206 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001207 break;
1208 }
1209 break;
Charles Keepax77438612013-11-14 16:18:25 +00001210 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001211 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001212 switch (arizona->rev) {
1213 case 0 ... 2:
1214 break;
1215 default:
1216 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001217 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001218 break;
1219 }
1220 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001221 default:
1222 break;
1223 }
1224
Chanwoo Choief70a212014-04-21 20:47:31 +09001225 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1226 if (IS_ERR(info->edev)) {
1227 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1228 return -ENOMEM;
1229 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001230
Chanwoo Choief70a212014-04-21 20:47:31 +09001231 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001232 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001233 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001234 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001235 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001236 }
1237
Mark Brown6fed4d82013-04-01 22:03:06 +01001238 info->input = devm_input_allocate_device(&pdev->dev);
1239 if (!info->input) {
1240 dev_err(arizona->dev, "Can't allocate input dev\n");
1241 ret = -ENOMEM;
1242 goto err_register;
1243 }
1244
1245 info->input->name = "Headset";
1246 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001247
Mark Brownf2c32a82012-06-24 12:09:45 +01001248 if (pdata->num_micd_configs) {
1249 info->micd_modes = pdata->micd_configs;
1250 info->micd_num_modes = pdata->num_micd_configs;
1251 } else {
1252 info->micd_modes = micd_default_modes;
1253 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1254 }
1255
1256 if (arizona->pdata.micd_pol_gpio > 0) {
1257 if (info->micd_modes[0].gpio)
1258 mode = GPIOF_OUT_INIT_HIGH;
1259 else
1260 mode = GPIOF_OUT_INIT_LOW;
1261
1262 ret = devm_gpio_request_one(&pdev->dev,
1263 arizona->pdata.micd_pol_gpio,
1264 mode,
1265 "MICD polarity");
1266 if (ret != 0) {
1267 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1268 arizona->pdata.micd_pol_gpio, ret);
1269 goto err_register;
1270 }
Charles Keepax8e5838d2015-06-19 17:23:31 +01001271 } else {
1272 if (info->micd_modes[0].gpio)
1273 mode = GPIOD_OUT_HIGH;
1274 else
1275 mode = GPIOD_OUT_LOW;
1276
1277 /* We can't use devm here because we need to do the get
1278 * against the MFD device, as that is where the of_node
1279 * will reside, but if we devm against that the GPIO
1280 * will not be freed if the extcon driver is unloaded.
1281 */
1282 info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
1283 "wlf,micd-pol",
1284 GPIOD_OUT_LOW);
1285 if (IS_ERR(info->micd_pol_gpio)) {
1286 ret = PTR_ERR(info->micd_pol_gpio);
1287 dev_err(arizona->dev,
1288 "Failed to get microphone polarity GPIO: %d\n",
1289 ret);
1290 goto err_register;
1291 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001292 }
1293
Mark Brown1eda6aa2013-01-11 08:55:54 +09001294 if (arizona->pdata.hpdet_id_gpio > 0) {
1295 ret = devm_gpio_request_one(&pdev->dev,
1296 arizona->pdata.hpdet_id_gpio,
1297 GPIOF_OUT_INIT_LOW,
1298 "HPDET");
1299 if (ret != 0) {
1300 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1301 arizona->pdata.hpdet_id_gpio, ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001302 goto err_gpio;
Mark Brown1eda6aa2013-01-11 08:55:54 +09001303 }
1304 }
1305
Mark Brownb17e5462013-01-11 08:55:24 +09001306 if (arizona->pdata.micd_bias_start_time)
1307 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1308 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1309 arizona->pdata.micd_bias_start_time
1310 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1311
Mark Brown2e033db2013-01-21 17:36:33 +09001312 if (arizona->pdata.micd_rate)
1313 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1314 ARIZONA_MICD_RATE_MASK,
1315 arizona->pdata.micd_rate
1316 << ARIZONA_MICD_RATE_SHIFT);
1317
1318 if (arizona->pdata.micd_dbtime)
1319 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1320 ARIZONA_MICD_DBTIME_MASK,
1321 arizona->pdata.micd_dbtime
1322 << ARIZONA_MICD_DBTIME_SHIFT);
1323
Mark Brown6fed4d82013-04-01 22:03:06 +01001324 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1325
1326 if (arizona->pdata.num_micd_ranges) {
1327 info->micd_ranges = pdata->micd_ranges;
1328 info->num_micd_ranges = pdata->num_micd_ranges;
1329 } else {
1330 info->micd_ranges = micd_default_ranges;
1331 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1332 }
1333
1334 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1335 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1336 arizona->pdata.num_micd_ranges);
1337 }
1338
1339 if (info->num_micd_ranges > 1) {
1340 for (i = 1; i < info->num_micd_ranges; i++) {
1341 if (info->micd_ranges[i - 1].max >
1342 info->micd_ranges[i].max) {
1343 dev_err(arizona->dev,
1344 "MICD ranges must be sorted\n");
1345 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001346 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001347 }
1348 }
1349 }
1350
1351 /* Disable all buttons by default */
1352 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1353 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1354
1355 /* Set up all the buttons the user specified */
1356 for (i = 0; i < info->num_micd_ranges; i++) {
1357 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1358 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1359 break;
1360
1361 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1362 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1363 info->micd_ranges[i].max);
1364 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001365 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001366 }
1367
1368 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1369 arizona_micd_levels[j], i);
1370
1371 arizona_micd_set_level(arizona, i, j);
1372 input_set_capability(info->input, EV_KEY,
1373 info->micd_ranges[i].key);
1374
1375 /* Enable reporting of that range */
1376 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1377 1 << i, 1 << i);
1378 }
1379
1380 /* Set all the remaining keys to a maximum */
1381 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1382 arizona_micd_set_level(arizona, i, 0x3f);
1383
Mark Browndab63eb2013-01-11 08:55:36 +09001384 /*
Mark Brown92a49872013-01-11 08:55:39 +09001385 * If we have a clamp use it, activating in conjunction with
1386 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001387 */
1388 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001389 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001390 /* Put the GPIO into input mode with optional pull */
1391 val = 0xc101;
1392 if (arizona->pdata.jd_gpio5_nopull)
1393 val &= ~ARIZONA_GPN_PU;
1394
Mark Brown92a49872013-01-11 08:55:39 +09001395 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001396 val);
Mark Brown92a49872013-01-11 08:55:39 +09001397
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001398 if (arizona->pdata.jd_invert)
1399 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1400 else
1401 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001402 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001403 if (arizona->pdata.jd_invert)
1404 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1405 else
1406 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001407 }
1408
Mark Browndab63eb2013-01-11 08:55:36 +09001409 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001410 ARIZONA_MICD_CLAMP_CONTROL,
1411 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1412
1413 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001414 ARIZONA_JACK_DETECT_DEBOUNCE,
1415 ARIZONA_MICD_CLAMP_DB,
1416 ARIZONA_MICD_CLAMP_DB);
1417 }
1418
Mark Brownf2c32a82012-06-24 12:09:45 +01001419 arizona_extcon_set_mode(info, 0);
1420
1421 pm_runtime_enable(&pdev->dev);
1422 pm_runtime_idle(&pdev->dev);
1423 pm_runtime_get_sync(&pdev->dev);
1424
Mark Brown92a49872013-01-11 08:55:39 +09001425 if (arizona->pdata.jd_gpio5) {
1426 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1427 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1428 } else {
1429 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1430 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1431 }
1432
1433 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001434 "JACKDET rise", arizona_jackdet, info);
1435 if (ret != 0) {
1436 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1437 ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001438 goto err_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +01001439 }
1440
Mark Brown92a49872013-01-11 08:55:39 +09001441 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001442 if (ret != 0) {
1443 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1444 ret);
1445 goto err_rise;
1446 }
1447
Mark Brown92a49872013-01-11 08:55:39 +09001448 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001449 "JACKDET fall", arizona_jackdet, info);
1450 if (ret != 0) {
1451 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1452 goto err_rise_wake;
1453 }
1454
Mark Brown92a49872013-01-11 08:55:39 +09001455 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001456 if (ret != 0) {
1457 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1458 ret);
1459 goto err_fall;
1460 }
1461
1462 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1463 "MICDET", arizona_micdet, info);
1464 if (ret != 0) {
1465 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1466 goto err_fall_wake;
1467 }
1468
Mark Brown4f340332013-01-11 08:55:43 +09001469 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1470 "HPDET", arizona_hpdet_irq, info);
1471 if (ret != 0) {
1472 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1473 goto err_micdet;
1474 }
1475
Mark Brownf2c32a82012-06-24 12:09:45 +01001476 arizona_clk32k_enable(arizona);
1477 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1478 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1479 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1480 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1481
Mark Brownb8575a12012-09-07 17:01:15 +08001482 ret = regulator_allow_bypass(info->micvdd, true);
1483 if (ret != 0)
1484 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1485 ret);
1486
Mark Brownf2c32a82012-06-24 12:09:45 +01001487 pm_runtime_put(&pdev->dev);
1488
Mark Brown34efe4d2012-07-20 17:07:29 +01001489 ret = input_register_device(info->input);
1490 if (ret) {
1491 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001492 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001493 }
1494
Mark Brownf2c32a82012-06-24 12:09:45 +01001495 return 0;
1496
Mark Brown4f340332013-01-11 08:55:43 +09001497err_hpdet:
1498 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001499err_micdet:
1500 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001501err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001502 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001503err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001504 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001505err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001506 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001507err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001508 arizona_free_irq(arizona, jack_irq_rise, info);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001509err_gpio:
1510 gpiod_put(info->micd_pol_gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +01001511err_register:
1512 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001513 return ret;
1514}
1515
Bill Pemberton93ed0322012-11-19 13:25:49 -05001516static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001517{
1518 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1519 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001520 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001521
Charles Keepax8e5838d2015-06-19 17:23:31 +01001522 gpiod_put(info->micd_pol_gpio);
1523
Mark Brownf2c32a82012-06-24 12:09:45 +01001524 pm_runtime_disable(&pdev->dev);
1525
Mark Browndab63eb2013-01-11 08:55:36 +09001526 regmap_update_bits(arizona->regmap,
1527 ARIZONA_MICD_CLAMP_CONTROL,
1528 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1529
Mark Brown92a49872013-01-11 08:55:39 +09001530 if (arizona->pdata.jd_gpio5) {
1531 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1532 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1533 } else {
1534 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1535 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1536 }
1537
1538 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1539 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1540 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001541 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001542 arizona_free_irq(arizona, jack_irq_rise, info);
1543 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001544 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001545 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1546 ARIZONA_JD1_ENA, 0);
1547 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001548
1549 return 0;
1550}
1551
1552static struct platform_driver arizona_extcon_driver = {
1553 .driver = {
1554 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001555 },
1556 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001557 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001558};
1559
1560module_platform_driver(arizona_extcon_driver);
1561
1562MODULE_DESCRIPTION("Arizona Extcon driver");
1563MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1564MODULE_LICENSE("GPL");
1565MODULE_ALIAS("platform:extcon-arizona");