blob: ed78b7c26627e7df5ebfeeb76841d13bee952246 [file] [log] [blame]
Mark Brownf2c32a82012-06-24 12:09:45 +01001/*
2 * extcon-arizona.c - Extcon driver Wolfson Arizona devices
3 *
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +01004 * Copyright (C) 2012-2014 Wolfson Microelectronics plc
Mark Brownf2c32a82012-06-24 12:09:45 +01005 *
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
Charles Keepaxf719ae32015-09-16 10:42:18 +010046#define ARIZONA_TST_CAP_DEFAULT 0x3
47#define ARIZONA_TST_CAP_CLAMP 0x1
48
Mark Brown9dd5e532013-04-01 19:09:45 +010049#define ARIZONA_HPDET_MAX 10000
50
Mark Brown2643fd62013-04-01 19:07:28 +010051#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010052#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010053
Charles Keepaxdf8b6772015-09-16 10:42:16 +010054#define QUICK_HEADPHONE_MAX_OHM 3
55#define MICROPHONE_MIN_OHM 1257
56#define MICROPHONE_MAX_OHM 30000
57
Charles Keepaxbb327e92015-06-30 13:32:39 +010058#define MICD_DBTIME_TWO_READINGS 2
59#define MICD_DBTIME_FOUR_READINGS 4
60
Charles Keepaxffae24f2013-11-14 16:18:21 +000061#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
62 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
63 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
64 ARIZONA_MICD_LVL_7)
65
66#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
67
68#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
69
Mark Brownf2c32a82012-06-24 12:09:45 +010070struct arizona_extcon_info {
71 struct device *dev;
72 struct arizona *arizona;
73 struct mutex lock;
74 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010075 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010076
Mark Browna3e20782013-04-01 19:05:27 +010077 u16 last_jackdet;
78
Mark Brownf2c32a82012-06-24 12:09:45 +010079 int micd_mode;
80 const struct arizona_micd_config *micd_modes;
81 int micd_num_modes;
82
Mark Brown6fed4d82013-04-01 22:03:06 +010083 const struct arizona_micd_range *micd_ranges;
84 int num_micd_ranges;
85
Mark Brown7abd4e22013-04-01 19:25:55 +010086 int micd_timeout;
87
Mark Brownf2c32a82012-06-24 12:09:45 +010088 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090089 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010090
Mark Brown0e27bd32013-02-05 21:00:15 +000091 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010092 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010093 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000094
Mark Brown4f340332013-01-11 08:55:43 +090095 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000096 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010097 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090098
Mark Browndd235ee2013-01-11 08:55:51 +090099 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900100 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +0900101
Mark Brownf2c32a82012-06-24 12:09:45 +0100102 bool mic;
103 bool detecting;
104 int jack_flips;
105
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100106 int hpdet_ip_version;
Mark Brown4f340332013-01-11 08:55:43 +0900107
Chanwoo Choief70a212014-04-21 20:47:31 +0900108 struct extcon_dev *edev;
Charles Keepax8e5838d2015-06-19 17:23:31 +0100109
110 struct gpio_desc *micd_pol_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +0100111};
112
113static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +0100114 { ARIZONA_ACCDET_SRC, 1, 0 },
115 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100116};
117
Mark Brown6fed4d82013-04-01 22:03:06 +0100118static const struct arizona_micd_range micd_default_ranges[] = {
119 { .max = 11, .key = BTN_0 },
120 { .max = 28, .key = BTN_1 },
121 { .max = 54, .key = BTN_2 },
122 { .max = 100, .key = BTN_3 },
123 { .max = 186, .key = BTN_4 },
124 { .max = 430, .key = BTN_5 },
125};
126
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100127/* The number of levels in arizona_micd_levels valid for button thresholds */
128#define ARIZONA_NUM_MICD_BUTTON_LEVELS 64
129
Mark Brown6fed4d82013-04-01 22:03:06 +0100130static const int arizona_micd_levels[] = {
131 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
132 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
133 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
134 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100135 1257, 30000,
Mark Brown34efe4d2012-07-20 17:07:29 +0100136};
137
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900138static const unsigned int arizona_cable[] = {
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900139 EXTCON_MECHANICAL,
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900140 EXTCON_JACK_MICROPHONE,
141 EXTCON_JACK_HEADPHONE,
142 EXTCON_JACK_LINE_OUT,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900143 EXTCON_NONE,
Mark Brownf2c32a82012-06-24 12:09:45 +0100144};
145
Mark Brown9dd5e532013-04-01 19:09:45 +0100146static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
147
Charles Keepax112bdfa2015-02-16 15:41:02 +0000148static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
149 bool clamp)
Mark Brown03409072013-02-12 13:00:31 +0000150{
151 struct arizona *arizona = info->arizona;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000152 unsigned int mask = 0, val = 0;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100153 unsigned int cap_sel = 0;
Mark Brown03409072013-02-12 13:00:31 +0000154 int ret;
155
Charles Keepax43f0acd2015-02-16 15:41:03 +0000156 switch (arizona->type) {
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100157 case WM8998:
158 case WM1814:
159 mask = 0;
160 break;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000161 case WM5110:
Charles Keepax2b51f9c2015-04-30 23:43:37 +0900162 case WM8280:
Charles Keepax43f0acd2015-02-16 15:41:03 +0000163 mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
164 ARIZONA_HP1L_SHRTI;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100165 if (clamp) {
Charles Keepax43f0acd2015-02-16 15:41:03 +0000166 val = ARIZONA_HP1L_SHRTO;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100167 cap_sel = ARIZONA_TST_CAP_CLAMP;
168 } else {
Charles Keepax43f0acd2015-02-16 15:41:03 +0000169 val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100170 cap_sel = ARIZONA_TST_CAP_DEFAULT;
171 }
172
173 ret = regmap_update_bits(arizona->regmap,
174 ARIZONA_HP_TEST_CTRL_1,
175 ARIZONA_HP1_TST_CAP_SEL_MASK,
176 cap_sel);
177 if (ret != 0)
178 dev_warn(arizona->dev,
179 "Failed to set TST_CAP_SEL: %d\n", ret);
Charles Keepax43f0acd2015-02-16 15:41:03 +0000180 break;
181 default:
182 mask = ARIZONA_RMV_SHRT_HP1L;
183 if (clamp)
184 val = ARIZONA_RMV_SHRT_HP1L;
185 break;
Charles Keepaxc19dc202016-07-19 13:23:56 +0100186 }
Charles Keepax112bdfa2015-02-16 15:41:02 +0000187
Charles Keepax03bf1ad2015-12-29 16:32:03 +0000188 snd_soc_dapm_mutex_lock(arizona->dapm);
Mark Brown03409072013-02-12 13:00:31 +0000189
Charles Keepax112bdfa2015-02-16 15:41:02 +0000190 arizona->hpdet_clamp = clamp;
Mark Browndf8c3db2013-02-22 18:38:03 +0000191
Charles Keepax112bdfa2015-02-16 15:41:02 +0000192 /* Keep the HP output stages disabled while doing the clamp */
193 if (clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000194 ret = regmap_update_bits(arizona->regmap,
195 ARIZONA_OUTPUT_ENABLES_1,
196 ARIZONA_OUT1L_ENA |
197 ARIZONA_OUT1R_ENA, 0);
198 if (ret != 0)
199 dev_warn(arizona->dev,
200 "Failed to disable headphone outputs: %d\n",
201 ret);
Mark Brown03409072013-02-12 13:00:31 +0000202 }
203
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100204 if (mask) {
205 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
206 mask, val);
207 if (ret != 0)
208 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000209 ret);
210
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100211 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
212 mask, val);
213 if (ret != 0)
214 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
215 ret);
216 }
Mark Browndf8c3db2013-02-22 18:38:03 +0000217
Charles Keepax112bdfa2015-02-16 15:41:02 +0000218 /* Restore the desired state while not doing the clamp */
219 if (!clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000220 ret = regmap_update_bits(arizona->regmap,
221 ARIZONA_OUTPUT_ENABLES_1,
222 ARIZONA_OUT1L_ENA |
223 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000224 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000225 dev_warn(arizona->dev,
226 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000227 ret);
228 }
229
Charles Keepax03bf1ad2015-12-29 16:32:03 +0000230 snd_soc_dapm_mutex_unlock(arizona->dapm);
Mark Brown03409072013-02-12 13:00:31 +0000231}
232
Mark Brownf2c32a82012-06-24 12:09:45 +0100233static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
234{
235 struct arizona *arizona = info->arizona;
236
Mark Brown6fed4d82013-04-01 22:03:06 +0100237 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800238
Charles Keepax6c467a12016-11-25 13:44:36 +0000239 gpiod_set_value_cansleep(info->micd_pol_gpio,
240 info->micd_modes[mode].gpio);
Charles Keepax8e5838d2015-06-19 17:23:31 +0100241
Mark Brownf2c32a82012-06-24 12:09:45 +0100242 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
243 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100244 info->micd_modes[mode].bias <<
245 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100246 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
247 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
248
249 info->micd_mode = mode;
250
251 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
252}
253
Mark Brownbbbd46e2013-01-10 19:38:43 +0000254static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
255{
Charles Keepax41024242013-09-23 14:33:59 +0100256 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000257 case 1:
258 return "MICBIAS1";
259 case 2:
260 return "MICBIAS2";
261 case 3:
262 return "MICBIAS3";
263 default:
264 return "MICVDD";
265 }
266}
267
268static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
269{
270 struct arizona *arizona = info->arizona;
271 const char *widget = arizona_extcon_get_micbias(info);
272 struct snd_soc_dapm_context *dapm = arizona->dapm;
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000273 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000274 int ret;
275
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000276 ret = snd_soc_component_force_enable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000277 if (ret != 0)
278 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
279 widget, ret);
280
Mark Brownbbbd46e2013-01-10 19:38:43 +0000281 snd_soc_dapm_sync(dapm);
282
283 if (!arizona->pdata.micd_force_micbias) {
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000284 ret = snd_soc_component_disable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000285 if (ret != 0)
286 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
287 widget, ret);
288
Mark Brownbbbd46e2013-01-10 19:38:43 +0000289 snd_soc_dapm_sync(dapm);
290 }
291}
292
Mark Brown9b1270c2013-01-11 08:55:46 +0900293static void arizona_start_mic(struct arizona_extcon_info *info)
294{
295 struct arizona *arizona = info->arizona;
296 bool change;
297 int ret;
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100298 unsigned int mode;
Mark Brown9b1270c2013-01-11 08:55:46 +0900299
Mark Brown9b1270c2013-01-11 08:55:46 +0900300 /* Microphone detection can't use idle mode */
301 pm_runtime_get(info->dev);
302
Mark Brownbbbd46e2013-01-10 19:38:43 +0000303 if (info->detecting) {
304 ret = regulator_allow_bypass(info->micvdd, false);
305 if (ret != 0) {
306 dev_err(arizona->dev,
307 "Failed to regulate MICVDD: %d\n",
308 ret);
309 }
310 }
311
Mark Brown9b1270c2013-01-11 08:55:46 +0900312 ret = regulator_enable(info->micvdd);
313 if (ret != 0) {
314 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
315 ret);
316 }
317
318 if (info->micd_reva) {
319 regmap_write(arizona->regmap, 0x80, 0x3);
320 regmap_write(arizona->regmap, 0x294, 0);
321 regmap_write(arizona->regmap, 0x80, 0x0);
322 }
323
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100324 if (info->detecting && arizona->pdata.micd_software_compare)
325 mode = ARIZONA_ACCDET_MODE_ADC;
326 else
327 mode = ARIZONA_ACCDET_MODE_MIC;
328
Mark Brown9b1270c2013-01-11 08:55:46 +0900329 regmap_update_bits(arizona->regmap,
330 ARIZONA_ACCESSORY_DETECT_MODE_1,
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100331 ARIZONA_ACCDET_MODE_MASK, mode);
Mark Brown9b1270c2013-01-11 08:55:46 +0900332
Mark Brownbbbd46e2013-01-10 19:38:43 +0000333 arizona_extcon_pulse_micbias(info);
334
Mark Brown9b1270c2013-01-11 08:55:46 +0900335 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
336 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
337 &change);
338 if (!change) {
339 regulator_disable(info->micvdd);
340 pm_runtime_put_autosuspend(info->dev);
341 }
342}
343
344static void arizona_stop_mic(struct arizona_extcon_info *info)
345{
346 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000347 const char *widget = arizona_extcon_get_micbias(info);
348 struct snd_soc_dapm_context *dapm = arizona->dapm;
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000349 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
Mark Brown9b1270c2013-01-11 08:55:46 +0900350 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000351 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900352
353 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
354 ARIZONA_MICD_ENA, 0,
355 &change);
356
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000357 ret = snd_soc_component_disable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000358 if (ret != 0)
359 dev_warn(arizona->dev,
360 "Failed to disable %s: %d\n",
361 widget, ret);
362
Mark Brownbbbd46e2013-01-10 19:38:43 +0000363 snd_soc_dapm_sync(dapm);
364
Mark Brown9b1270c2013-01-11 08:55:46 +0900365 if (info->micd_reva) {
366 regmap_write(arizona->regmap, 0x80, 0x3);
367 regmap_write(arizona->regmap, 0x294, 2);
368 regmap_write(arizona->regmap, 0x80, 0x0);
369 }
370
Mark Brownbbbd46e2013-01-10 19:38:43 +0000371 ret = regulator_allow_bypass(info->micvdd, true);
372 if (ret != 0) {
373 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
374 ret);
375 }
376
Mark Brown9b1270c2013-01-11 08:55:46 +0900377 if (change) {
378 regulator_disable(info->micvdd);
379 pm_runtime_mark_last_busy(info->dev);
380 pm_runtime_put_autosuspend(info->dev);
381 }
382}
383
Mark Brown4f340332013-01-11 08:55:43 +0900384static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100385 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900386 unsigned int factor_a;
387 unsigned int factor_b;
388} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100389 { 100, 5528, 362464 },
390 { 169, 11084, 6186851 },
391 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900392};
393
Charles Keepax24a279b2014-05-30 13:19:17 +0100394#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
395
Mark Brown4f340332013-01-11 08:55:43 +0900396static struct {
397 int min;
398 int max;
399} arizona_hpdet_c_ranges[] = {
400 { 0, 30 },
401 { 8, 100 },
402 { 100, 1000 },
403 { 1000, 10000 },
404};
405
406static int arizona_hpdet_read(struct arizona_extcon_info *info)
407{
408 struct arizona *arizona = info->arizona;
409 unsigned int val, range;
410 int ret;
411
412 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
413 if (ret != 0) {
414 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
415 ret);
416 return ret;
417 }
418
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100419 switch (info->hpdet_ip_version) {
Mark Brown4f340332013-01-11 08:55:43 +0900420 case 0:
421 if (!(val & ARIZONA_HP_DONE)) {
422 dev_err(arizona->dev, "HPDET did not complete: %x\n",
423 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900424 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900425 }
426
427 val &= ARIZONA_HP_LVL_MASK;
428 break;
429
430 case 1:
431 if (!(val & ARIZONA_HP_DONE_B)) {
432 dev_err(arizona->dev, "HPDET did not complete: %x\n",
433 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900434 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900435 }
436
437 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
438 if (ret != 0) {
439 dev_err(arizona->dev, "Failed to read HP value: %d\n",
440 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900441 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900442 }
443
444 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
445 &range);
446 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
447 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
448
449 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100450 (val < arizona_hpdet_b_ranges[range].threshold ||
451 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900452 range++;
453 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
454 range);
455 regmap_update_bits(arizona->regmap,
456 ARIZONA_HEADPHONE_DETECT_1,
457 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
458 range <<
459 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
460 return -EAGAIN;
461 }
462
463 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100464 if (val < arizona_hpdet_b_ranges[range].threshold ||
465 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900466 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100467 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900468 }
469
470 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
471 val, range);
472
473 val = arizona_hpdet_b_ranges[range].factor_b
474 / ((val * 100) -
475 arizona_hpdet_b_ranges[range].factor_a);
476 break;
477
Mark Brown4f340332013-01-11 08:55:43 +0900478 case 2:
479 if (!(val & ARIZONA_HP_DONE_B)) {
480 dev_err(arizona->dev, "HPDET did not complete: %x\n",
481 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900482 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900483 }
484
485 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000486 /* Convert to ohms, the value is in 0.5 ohm increments */
487 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900488
489 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
490 &range);
491 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
492 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
493
Charles Keepax91414612013-11-14 16:18:24 +0000494 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900495 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
496 (val >= arizona_hpdet_c_ranges[range].max)) {
497 range++;
498 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
499 arizona_hpdet_c_ranges[range].min,
500 arizona_hpdet_c_ranges[range].max);
501 regmap_update_bits(arizona->regmap,
502 ARIZONA_HEADPHONE_DETECT_1,
503 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
504 range <<
505 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
506 return -EAGAIN;
507 }
Charles Keepax91414612013-11-14 16:18:24 +0000508
509 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
510 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
511 arizona_hpdet_c_ranges[range].min);
512 val = arizona_hpdet_c_ranges[range].min;
513 }
Chanwoo Choie9844b22015-09-29 19:06:31 +0900514 break;
515
516 default:
517 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
518 info->hpdet_ip_version);
519 return -EINVAL;
Mark Brown4f340332013-01-11 08:55:43 +0900520 }
521
522 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
523 return val;
524}
525
Mark Brown9c2ba272013-02-25 23:42:31 +0000526static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
527 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900528{
529 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900530 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900531
532 /*
533 * If we're using HPDET for accessory identification we need
534 * to take multiple measurements, step through them in sequence.
535 */
536 if (arizona->pdata.hpdet_acc_id) {
537 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900538
539 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000540 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900541 dev_dbg(arizona->dev, "Measuring mic\n");
542
543 regmap_update_bits(arizona->regmap,
544 ARIZONA_ACCESSORY_DETECT_MODE_1,
545 ARIZONA_ACCDET_MODE_MASK |
546 ARIZONA_ACCDET_SRC,
547 ARIZONA_ACCDET_MODE_HPR |
548 info->micd_modes[0].src);
549
550 gpio_set_value_cansleep(id_gpio, 1);
551
Mark Browndd235ee2013-01-11 08:55:51 +0900552 regmap_update_bits(arizona->regmap,
553 ARIZONA_HEADPHONE_DETECT_1,
554 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
555 return -EAGAIN;
556 }
557
558 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000559 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
560 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000561
562 /* Take the headphone impedance for the main report */
563 *reading = info->hpdet_res[0];
564
Mark Brown9dd5e532013-04-01 19:09:45 +0100565 /* Sometimes we get false readings due to slow insert */
566 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
567 dev_dbg(arizona->dev, "Retrying high impedance\n");
568 info->num_hpdet_res = 0;
569 info->hpdet_retried = true;
570 arizona_start_hpdet_acc_id(info);
571 pm_runtime_put(info->dev);
572 return -EAGAIN;
573 }
574
Mark Brown1eda6aa2013-01-11 08:55:54 +0900575 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530576 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900577 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000578 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900579 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000580 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000581 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900582 } else {
583 dev_dbg(arizona->dev, "Detected headphone\n");
584 }
585
586 /* Make sure everything is reset back to the real polarity */
587 regmap_update_bits(arizona->regmap,
588 ARIZONA_ACCESSORY_DETECT_MODE_1,
589 ARIZONA_ACCDET_SRC,
590 info->micd_modes[0].src);
591 }
592
593 return 0;
594}
595
Mark Brown4f340332013-01-11 08:55:43 +0900596static irqreturn_t arizona_hpdet_irq(int irq, void *data)
597{
598 struct arizona_extcon_info *info = data;
599 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900600 int id_gpio = arizona->pdata.hpdet_id_gpio;
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900601 unsigned int report = EXTCON_JACK_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900602 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000603 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900604
605 mutex_lock(&info->lock);
606
607 /* If we got a spurious IRQ for some reason then ignore it */
608 if (!info->hpdet_active) {
609 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
610 mutex_unlock(&info->lock);
611 return IRQ_NONE;
612 }
613
614 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900615 ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900616 if (ret < 0) {
617 dev_err(arizona->dev, "Failed to check cable state: %d\n",
618 ret);
619 goto out;
620 } else if (!ret) {
621 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
622 goto done;
623 }
624
625 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900626 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900627 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900628 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900629 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900630 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900631
632 /* Reset back to starting range */
633 regmap_update_bits(arizona->regmap,
634 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900635 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
636 0);
637
Mark Brown9c2ba272013-02-25 23:42:31 +0000638 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900639 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900640 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900641 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900642 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900643
644 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900645 if (reading >= 5000)
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900646 report = EXTCON_JACK_LINE_OUT;
Mark Brown4f340332013-01-11 08:55:43 +0900647 else
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900648 report = EXTCON_JACK_HEADPHONE;
Mark Brown4f340332013-01-11 08:55:43 +0900649
Chanwoo Choi8670b452016-08-16 15:55:34 +0900650 ret = extcon_set_state_sync(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900651 if (ret != 0)
652 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
653 ret);
654
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000655done:
656 /* Reset back to starting range */
657 regmap_update_bits(arizona->regmap,
658 ARIZONA_HEADPHONE_DETECT_1,
659 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
660 0);
661
Charles Keepax112bdfa2015-02-16 15:41:02 +0000662 arizona_extcon_hp_clamp(info, false);
Mark Brown4f340332013-01-11 08:55:43 +0900663
Mark Brown1eda6aa2013-01-11 08:55:54 +0900664 if (id_gpio)
665 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900666
667 /* Revert back to MICDET mode */
668 regmap_update_bits(arizona->regmap,
669 ARIZONA_ACCESSORY_DETECT_MODE_1,
670 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
671
672 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000673 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900674 arizona_start_mic(info);
675
676 if (info->hpdet_active) {
677 pm_runtime_put_autosuspend(info->dev);
678 info->hpdet_active = false;
679 }
680
Mark Brownbf14ee52013-02-05 20:20:17 +0000681 info->hpdet_done = true;
682
Mark Brown4f340332013-01-11 08:55:43 +0900683out:
684 mutex_unlock(&info->lock);
685
686 return IRQ_HANDLED;
687}
688
689static void arizona_identify_headphone(struct arizona_extcon_info *info)
690{
691 struct arizona *arizona = info->arizona;
692 int ret;
693
Mark Brownbf14ee52013-02-05 20:20:17 +0000694 if (info->hpdet_done)
695 return;
696
Mark Brown4f340332013-01-11 08:55:43 +0900697 dev_dbg(arizona->dev, "Starting HPDET\n");
698
699 /* Make sure we keep the device enabled during the measurement */
700 pm_runtime_get(info->dev);
701
702 info->hpdet_active = true;
703
704 if (info->mic)
705 arizona_stop_mic(info);
706
Charles Keepax112bdfa2015-02-16 15:41:02 +0000707 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900708
709 ret = regmap_update_bits(arizona->regmap,
710 ARIZONA_ACCESSORY_DETECT_MODE_1,
711 ARIZONA_ACCDET_MODE_MASK,
Inha Song9e86b2a2015-05-04 13:42:13 +0900712 arizona->pdata.hpdet_channel);
Mark Brown4f340332013-01-11 08:55:43 +0900713 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900714 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +0900715 goto err;
716 }
717
718 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
719 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
720 if (ret != 0) {
721 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
722 ret);
723 goto err;
724 }
725
726 return;
727
728err:
729 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
730 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
731
732 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900733 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900734 if (ret != 0)
735 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
736
737 if (info->mic)
738 arizona_start_mic(info);
739
740 info->hpdet_active = false;
741}
Mark Browndd235ee2013-01-11 08:55:51 +0900742
743static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
744{
745 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000746 int hp_reading = 32;
747 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900748 int ret;
749
750 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
751
752 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000753 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900754
755 info->hpdet_active = true;
756
Charles Keepax112bdfa2015-02-16 15:41:02 +0000757 arizona_extcon_hp_clamp(info, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900758
759 ret = regmap_update_bits(arizona->regmap,
760 ARIZONA_ACCESSORY_DETECT_MODE_1,
761 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
762 info->micd_modes[0].src |
Inha Song9e86b2a2015-05-04 13:42:13 +0900763 arizona->pdata.hpdet_channel);
Mark Browndd235ee2013-01-11 08:55:51 +0900764 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900765 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Browndd235ee2013-01-11 08:55:51 +0900766 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900767 }
768
Mark Brown9c2ba272013-02-25 23:42:31 +0000769 if (arizona->pdata.hpdet_acc_id_line) {
770 ret = regmap_update_bits(arizona->regmap,
771 ARIZONA_HEADPHONE_DETECT_1,
772 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
773 if (ret != 0) {
774 dev_err(arizona->dev,
775 "Can't start HPDETL measurement: %d\n",
776 ret);
777 goto err;
778 }
779 } else {
780 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900781 }
782
783 return;
784
785err:
786 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
787 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
788
789 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900790 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900791 if (ret != 0)
792 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
793
Mark Brown4f340332013-01-11 08:55:43 +0900794 info->hpdet_active = false;
795}
796
Mark Brown939c5672013-04-01 19:17:34 +0100797static void arizona_micd_timeout_work(struct work_struct *work)
798{
799 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900800 struct arizona_extcon_info,
801 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100802
803 mutex_lock(&info->lock);
804
805 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
Mark Brown939c5672013-04-01 19:17:34 +0100806
807 info->detecting = false;
808
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100809 arizona_identify_headphone(info);
810
Mark Brown939c5672013-04-01 19:17:34 +0100811 arizona_stop_mic(info);
812
813 mutex_unlock(&info->lock);
814}
815
Mark Browncd59e792013-04-01 19:21:48 +0100816static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100817{
Mark Browncd59e792013-04-01 19:21:48 +0100818 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900819 struct arizona_extcon_info,
820 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100821 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100822 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100823 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100824
Mark Brown939c5672013-04-01 19:17:34 +0100825 cancel_delayed_work_sync(&info->micd_timeout_work);
826
Mark Brownf2c32a82012-06-24 12:09:45 +0100827 mutex_lock(&info->lock);
828
Charles Keepax31a847e2013-11-14 16:18:23 +0000829 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900830 ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000831 if (ret < 0) {
832 dev_err(arizona->dev, "Failed to check cable state: %d\n",
833 ret);
834 mutex_unlock(&info->lock);
835 return;
836 } else if (!ret) {
837 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
838 mutex_unlock(&info->lock);
839 return;
840 }
841
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100842 if (info->detecting && arizona->pdata.micd_software_compare) {
843 /* Must disable MICD before we read the ADCVAL */
844 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
845 ARIZONA_MICD_ENA, 0);
846 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
847 if (ret != 0) {
848 dev_err(arizona->dev,
849 "Failed to read MICDET_ADCVAL: %d\n",
850 ret);
851 mutex_unlock(&info->lock);
852 return;
853 }
854
855 dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
856
857 val &= ARIZONA_MICDET_ADCVAL_MASK;
858 if (val < ARRAY_SIZE(arizona_micd_levels))
859 val = arizona_micd_levels[val];
860 else
861 val = INT_MAX;
862
863 if (val <= QUICK_HEADPHONE_MAX_OHM)
864 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
865 else if (val <= MICROPHONE_MIN_OHM)
866 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
867 else if (val <= MICROPHONE_MAX_OHM)
868 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
869 else
870 val = ARIZONA_MICD_LVL_8;
871 }
872
Charles Keepaxffae24f2013-11-14 16:18:21 +0000873 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100874 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
875 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900876 dev_err(arizona->dev,
877 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100878 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100879 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100880 }
881
882 dev_dbg(arizona->dev, "MICDET: %x\n", val);
883
884 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900885 dev_warn(arizona->dev,
886 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100887 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100888 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100889 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100890 }
891
Charles Keepaxffae24f2013-11-14 16:18:21 +0000892 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100893 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100894 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100895 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100896 }
897
898 /* Due to jack detect this should never happen */
899 if (!(val & ARIZONA_MICD_STS)) {
900 dev_warn(arizona->dev, "Detected open circuit\n");
Charles Keepax57f70ef2015-06-25 16:47:02 +0100901 info->mic = false;
902 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100903 info->detecting = false;
Charles Keepax57f70ef2015-06-25 16:47:02 +0100904 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100905 goto handled;
906 }
907
908 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000909 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100910 info->mic = true;
911 info->detecting = false;
912
Mark Brown4f340332013-01-11 08:55:43 +0900913 arizona_identify_headphone(info);
914
Chanwoo Choi8670b452016-08-16 15:55:34 +0900915 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900916 EXTCON_JACK_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100917 if (ret != 0)
918 dev_err(arizona->dev, "Headset report failed: %d\n",
919 ret);
920
Mark Brownbbbd46e2013-01-10 19:38:43 +0000921 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100922 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000923 if (ret != 0) {
924 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
925 ret);
926 }
927
Mark Brownf2c32a82012-06-24 12:09:45 +0100928 goto handled;
929 }
930
931 /* If we detected a lower impedence during initial startup
932 * then we probably have the wrong polarity, flip it. Don't
933 * do this for the lowest impedences to speed up detection of
934 * plain headphones. If both polarities report a low
935 * impedence then give up and report headphones.
936 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000937 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800938 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900939 dev_dbg(arizona->dev, "Detected HP/line\n");
Mark Brown9ef2224d2012-06-28 13:08:31 +0100940
Mark Brown4f340332013-01-11 08:55:43 +0900941 info->detecting = false;
942
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100943 arizona_identify_headphone(info);
944
Mark Brown4f340332013-01-11 08:55:43 +0900945 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100946 } else {
947 info->micd_mode++;
948 if (info->micd_mode == info->micd_num_modes)
949 info->micd_mode = 0;
950 arizona_extcon_set_mode(info, info->micd_mode);
951
952 info->jack_flips++;
953 }
954
955 goto handled;
956 }
957
958 /*
959 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100960 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100961 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000962 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100963 if (info->mic) {
964 dev_dbg(arizona->dev, "Mic button detected\n");
965
Mark Brown34efe4d2012-07-20 17:07:29 +0100966 lvl = val & ARIZONA_MICD_LVL_MASK;
967 lvl >>= ARIZONA_MICD_LVL_SHIFT;
968
Mark Brown41a57852013-04-01 19:18:18 +0100969 for (i = 0; i < info->num_micd_ranges; i++)
970 input_report_key(info->input,
971 info->micd_ranges[i].key, 0);
972
Mark Brown6fed4d82013-04-01 22:03:06 +0100973 WARN_ON(!lvl);
974 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
975 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
976 key = info->micd_ranges[ffs(lvl) - 1].key;
977 input_report_key(info->input, key, 1);
978 input_sync(info->input);
979 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100980
Mark Brownf2c32a82012-06-24 12:09:45 +0100981 } else if (info->detecting) {
982 dev_dbg(arizona->dev, "Headphone detected\n");
983 info->detecting = false;
984 arizona_stop_mic(info);
985
Mark Brown4f340332013-01-11 08:55:43 +0900986 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100987 } else {
988 dev_warn(arizona->dev, "Button with no mic: %x\n",
989 val);
990 }
991 } else {
992 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100993 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100994 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100995 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100996 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000997 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100998 }
999
1000handled:
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001001 if (info->detecting) {
1002 if (arizona->pdata.micd_software_compare)
1003 regmap_update_bits(arizona->regmap,
1004 ARIZONA_MIC_DETECT_1,
1005 ARIZONA_MICD_ENA,
1006 ARIZONA_MICD_ENA);
1007
Mark Browndf9a5ab2013-07-18 22:42:22 +01001008 queue_delayed_work(system_power_efficient_wq,
1009 &info->micd_timeout_work,
1010 msecs_to_jiffies(info->micd_timeout));
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001011 }
Mark Brown939c5672013-04-01 19:17:34 +01001012
Mark Brownf2c32a82012-06-24 12:09:45 +01001013 pm_runtime_mark_last_busy(info->dev);
1014 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +01001015}
1016
1017static irqreturn_t arizona_micdet(int irq, void *data)
1018{
1019 struct arizona_extcon_info *info = data;
1020 struct arizona *arizona = info->arizona;
1021 int debounce = arizona->pdata.micd_detect_debounce;
1022
1023 cancel_delayed_work_sync(&info->micd_detect_work);
1024 cancel_delayed_work_sync(&info->micd_timeout_work);
1025
1026 mutex_lock(&info->lock);
1027 if (!info->detecting)
1028 debounce = 0;
1029 mutex_unlock(&info->lock);
1030
1031 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001032 queue_delayed_work(system_power_efficient_wq,
1033 &info->micd_detect_work,
1034 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +01001035 else
1036 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001037
1038 return IRQ_HANDLED;
1039}
1040
Mark Brown0e27bd32013-02-05 21:00:15 +00001041static void arizona_hpdet_work(struct work_struct *work)
1042{
1043 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001044 struct arizona_extcon_info,
1045 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +00001046
1047 mutex_lock(&info->lock);
1048 arizona_start_hpdet_acc_id(info);
1049 mutex_unlock(&info->lock);
1050}
1051
Mark Brownf2c32a82012-06-24 12:09:45 +01001052static irqreturn_t arizona_jackdet(int irq, void *data)
1053{
1054 struct arizona_extcon_info *info = data;
1055 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001056 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +01001057 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +01001058 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +01001059
Mark Brown939c5672013-04-01 19:17:34 +01001060 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
1061 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001062
Mark Browna3e20782013-04-01 19:05:27 +01001063 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +00001064
Mark Brownf2c32a82012-06-24 12:09:45 +01001065 mutex_lock(&info->lock);
1066
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001067 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001068 mask = ARIZONA_MICD_CLAMP_STS;
Nariman Poushina0ef6422015-09-16 10:42:19 +01001069 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +09001070 } else {
1071 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001072 if (arizona->pdata.jd_invert)
1073 present = 0;
1074 else
1075 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +09001076 }
1077
Mark Brownf2c32a82012-06-24 12:09:45 +01001078 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
1079 if (ret != 0) {
1080 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
1081 ret);
1082 mutex_unlock(&info->lock);
1083 pm_runtime_put_autosuspend(info->dev);
1084 return IRQ_NONE;
1085 }
1086
Mark Browna3e20782013-04-01 19:05:27 +01001087 val &= mask;
1088 if (val == info->last_jackdet) {
1089 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001090 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001091 queue_delayed_work(system_power_efficient_wq,
1092 &info->hpdet_work,
1093 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001094
Chanwoo Choic2275d22013-08-23 10:21:37 +09001095 if (cancelled_mic) {
1096 int micd_timeout = info->micd_timeout;
1097
Mark Browndf9a5ab2013-07-18 22:42:22 +01001098 queue_delayed_work(system_power_efficient_wq,
1099 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001100 msecs_to_jiffies(micd_timeout));
1101 }
Mark Brown939c5672013-04-01 19:17:34 +01001102
Mark Browna3e20782013-04-01 19:05:27 +01001103 goto out;
1104 }
1105 info->last_jackdet = val;
1106
1107 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001108 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choi8670b452016-08-16 15:55:34 +09001109 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +09001110 EXTCON_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001111
1112 if (ret != 0)
1113 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1114 ret);
1115
Mark Browndd235ee2013-01-11 08:55:51 +09001116 if (!arizona->pdata.hpdet_acc_id) {
1117 info->detecting = true;
1118 info->mic = false;
1119 info->jack_flips = 0;
1120
1121 arizona_start_mic(info);
1122 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001123 queue_delayed_work(system_power_efficient_wq,
1124 &info->hpdet_work,
1125 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001126 }
Mark Brown4e616872013-01-15 22:09:20 +09001127
Charles Keepax6c20b932015-09-16 10:42:21 +01001128 if (info->micd_clamp || !arizona->pdata.jd_invert)
1129 regmap_update_bits(arizona->regmap,
1130 ARIZONA_JACK_DETECT_DEBOUNCE,
1131 ARIZONA_MICD_CLAMP_DB |
1132 ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001133 } else {
1134 dev_dbg(arizona->dev, "Detected jack removal\n");
1135
1136 arizona_stop_mic(info);
1137
Mark Browndd235ee2013-01-11 08:55:51 +09001138 info->num_hpdet_res = 0;
1139 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1140 info->hpdet_res[i] = 0;
1141 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001142 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001143 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001144
Mark Brown6fed4d82013-04-01 22:03:06 +01001145 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001146 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001147 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001148 input_sync(info->input);
1149
Chanwoo Choi5475e632016-07-01 02:36:49 +09001150 for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) {
Chanwoo Choi8670b452016-08-16 15:55:34 +09001151 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi5475e632016-07-01 02:36:49 +09001152 arizona_cable[i], false);
1153 if (ret != 0)
1154 dev_err(arizona->dev,
1155 "Removal report failed: %d\n", ret);
1156 }
Mark Brown4e616872013-01-15 22:09:20 +09001157
1158 regmap_update_bits(arizona->regmap,
1159 ARIZONA_JACK_DETECT_DEBOUNCE,
1160 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1161 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001162 }
1163
Mark Brown7abd4e22013-04-01 19:25:55 +01001164 if (arizona->pdata.micd_timeout)
1165 info->micd_timeout = arizona->pdata.micd_timeout;
1166 else
1167 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1168
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001169out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001170 /* Clear trig_sts to make sure DCVDD is not forced up */
1171 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1172 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1173 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1174 ARIZONA_JD1_FALL_TRIG_STS |
1175 ARIZONA_JD1_RISE_TRIG_STS);
1176
Mark Brownf2c32a82012-06-24 12:09:45 +01001177 mutex_unlock(&info->lock);
1178
1179 pm_runtime_mark_last_busy(info->dev);
1180 pm_runtime_put_autosuspend(info->dev);
1181
1182 return IRQ_HANDLED;
1183}
1184
Mark Brown6fed4d82013-04-01 22:03:06 +01001185/* Map a level onto a slot in the register bank */
1186static void arizona_micd_set_level(struct arizona *arizona, int index,
1187 unsigned int level)
1188{
1189 int reg;
1190 unsigned int mask;
1191
1192 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1193
1194 if (!(index % 2)) {
1195 mask = 0x3f00;
1196 level <<= 8;
1197 } else {
1198 mask = 0x3f;
1199 }
1200
1201 /* Program the level itself */
1202 regmap_update_bits(arizona->regmap, reg, mask, level);
1203}
1204
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001205static int arizona_extcon_get_micd_configs(struct device *dev,
1206 struct arizona *arizona)
1207{
1208 const char * const prop = "wlf,micd-configs";
1209 const int entries_per_config = 3;
1210 struct arizona_micd_config *micd_configs;
1211 int nconfs, ret;
1212 int i, j;
1213 u32 *vals;
1214
1215 nconfs = device_property_read_u32_array(arizona->dev, prop, NULL, 0);
1216 if (nconfs <= 0)
1217 return 0;
1218
1219 vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
1220 if (!vals)
1221 return -ENOMEM;
1222
1223 ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
1224 if (ret < 0)
1225 goto out;
1226
1227 nconfs /= entries_per_config;
1228
1229 micd_configs = devm_kzalloc(dev,
1230 nconfs * sizeof(struct arizona_micd_range),
1231 GFP_KERNEL);
1232 if (!micd_configs) {
1233 ret = -ENOMEM;
1234 goto out;
1235 }
1236
1237 for (i = 0, j = 0; i < nconfs; ++i) {
1238 micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
1239 micd_configs[i].bias = vals[j++];
1240 micd_configs[i].gpio = vals[j++];
1241 }
1242
1243 arizona->pdata.micd_configs = micd_configs;
1244 arizona->pdata.num_micd_configs = nconfs;
1245
1246out:
1247 kfree(vals);
1248 return ret;
1249}
1250
1251static int arizona_extcon_device_get_pdata(struct device *dev,
1252 struct arizona *arizona)
Inha Song9e86b2a2015-05-04 13:42:13 +09001253{
1254 struct arizona_pdata *pdata = &arizona->pdata;
1255 unsigned int val = ARIZONA_ACCDET_MODE_HPL;
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001256 int ret;
Inha Song9e86b2a2015-05-04 13:42:13 +09001257
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001258 device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
Inha Song9e86b2a2015-05-04 13:42:13 +09001259 switch (val) {
1260 case ARIZONA_ACCDET_MODE_HPL:
1261 case ARIZONA_ACCDET_MODE_HPR:
1262 pdata->hpdet_channel = val;
1263 break;
1264 default:
1265 dev_err(arizona->dev,
1266 "Wrong wlf,hpdet-channel DT value %d\n", val);
1267 pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
1268 }
1269
Charles Keepax4778d442015-06-19 17:23:30 +01001270 device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
1271 &pdata->micd_detect_debounce);
1272
1273 device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
1274 &pdata->micd_bias_start_time);
1275
1276 device_property_read_u32(arizona->dev, "wlf,micd-rate",
1277 &pdata->micd_rate);
1278
1279 device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
1280 &pdata->micd_dbtime);
1281
Charles Keepax7a7ef0f2015-11-23 14:51:30 +00001282 device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
Charles Keepax4778d442015-06-19 17:23:30 +01001283 &pdata->micd_timeout);
1284
1285 pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
1286 "wlf,micd-force-micbias");
1287
Charles Keepax2e87b7a2015-11-19 15:45:35 +00001288 pdata->micd_software_compare = device_property_read_bool(arizona->dev,
1289 "wlf,micd-software-compare");
1290
Charles Keepax3d7a8722015-11-19 15:45:37 +00001291 pdata->jd_invert = device_property_read_bool(arizona->dev,
1292 "wlf,jd-invert");
1293
Charles Keepax99374222015-11-19 15:45:36 +00001294 device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
1295
Charles Keepax35247c12015-11-19 15:45:38 +00001296 pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001297 "wlf,use-jd2");
Charles Keepax35247c12015-11-19 15:45:38 +00001298 pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001299 "wlf,use-jd2-nopull");
Charles Keepax35247c12015-11-19 15:45:38 +00001300
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001301 ret = arizona_extcon_get_micd_configs(dev, arizona);
1302 if (ret < 0)
1303 dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
1304
Inha Song9e86b2a2015-05-04 13:42:13 +09001305 return 0;
1306}
1307
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001308static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001309{
1310 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001311 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001312 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001313 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001314 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001315 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001316 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001317
Mark Brownbbbd46e2013-01-10 19:38:43 +00001318 if (!arizona->dapm || !arizona->dapm->card)
1319 return -EPROBE_DEFER;
1320
Mark Brownf2c32a82012-06-24 12:09:45 +01001321 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001322 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001323 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001324
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001325 if (!dev_get_platdata(arizona->dev))
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001326 arizona_extcon_device_get_pdata(&pdev->dev, arizona);
Inha Song9e86b2a2015-05-04 13:42:13 +09001327
Charles Keepax17271f62014-07-18 12:59:00 +01001328 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001329 if (IS_ERR(info->micvdd)) {
1330 ret = PTR_ERR(info->micvdd);
1331 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001332 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001333 }
1334
1335 mutex_init(&info->lock);
1336 info->arizona = arizona;
1337 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001338 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001339 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001340 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001341 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001342 platform_set_drvdata(pdev, info);
1343
1344 switch (arizona->type) {
1345 case WM5102:
1346 switch (arizona->rev) {
1347 case 0:
1348 info->micd_reva = true;
1349 break;
1350 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001351 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001352 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001353 break;
1354 }
1355 break;
Charles Keepax77438612013-11-14 16:18:25 +00001356 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001357 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001358 switch (arizona->rev) {
1359 case 0 ... 2:
1360 break;
1361 default:
1362 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001363 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001364 break;
1365 }
1366 break;
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +01001367 case WM8998:
1368 case WM1814:
1369 info->micd_clamp = true;
1370 info->hpdet_ip_version = 2;
1371 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001372 default:
1373 break;
1374 }
1375
Chanwoo Choief70a212014-04-21 20:47:31 +09001376 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1377 if (IS_ERR(info->edev)) {
1378 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1379 return -ENOMEM;
1380 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001381
Chanwoo Choief70a212014-04-21 20:47:31 +09001382 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001383 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001384 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001385 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001386 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001387 }
1388
Mark Brown6fed4d82013-04-01 22:03:06 +01001389 info->input = devm_input_allocate_device(&pdev->dev);
1390 if (!info->input) {
1391 dev_err(arizona->dev, "Can't allocate input dev\n");
1392 ret = -ENOMEM;
1393 goto err_register;
1394 }
1395
1396 info->input->name = "Headset";
1397 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001398
Mark Brownf2c32a82012-06-24 12:09:45 +01001399 if (pdata->num_micd_configs) {
1400 info->micd_modes = pdata->micd_configs;
1401 info->micd_num_modes = pdata->num_micd_configs;
1402 } else {
1403 info->micd_modes = micd_default_modes;
1404 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1405 }
1406
Charles Keepax6772a5a2015-09-16 10:42:17 +01001407 if (arizona->pdata.gpsw > 0)
1408 regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
1409 ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
1410
Charles Keepax6c467a12016-11-25 13:44:36 +00001411 if (pdata->micd_pol_gpio > 0) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001412 if (info->micd_modes[0].gpio)
1413 mode = GPIOF_OUT_INIT_HIGH;
1414 else
1415 mode = GPIOF_OUT_INIT_LOW;
1416
Charles Keepax6c467a12016-11-25 13:44:36 +00001417 ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio,
1418 mode, "MICD polarity");
Mark Brownf2c32a82012-06-24 12:09:45 +01001419 if (ret != 0) {
1420 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
Charles Keepax6c467a12016-11-25 13:44:36 +00001421 pdata->micd_pol_gpio, ret);
Mark Brownf2c32a82012-06-24 12:09:45 +01001422 goto err_register;
1423 }
Charles Keepax6c467a12016-11-25 13:44:36 +00001424
1425 info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001426 } else {
1427 if (info->micd_modes[0].gpio)
1428 mode = GPIOD_OUT_HIGH;
1429 else
1430 mode = GPIOD_OUT_LOW;
1431
1432 /* We can't use devm here because we need to do the get
1433 * against the MFD device, as that is where the of_node
1434 * will reside, but if we devm against that the GPIO
1435 * will not be freed if the extcon driver is unloaded.
1436 */
1437 info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
1438 "wlf,micd-pol",
1439 GPIOD_OUT_LOW);
1440 if (IS_ERR(info->micd_pol_gpio)) {
1441 ret = PTR_ERR(info->micd_pol_gpio);
1442 dev_err(arizona->dev,
1443 "Failed to get microphone polarity GPIO: %d\n",
1444 ret);
1445 goto err_register;
1446 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001447 }
1448
Mark Brown1eda6aa2013-01-11 08:55:54 +09001449 if (arizona->pdata.hpdet_id_gpio > 0) {
1450 ret = devm_gpio_request_one(&pdev->dev,
1451 arizona->pdata.hpdet_id_gpio,
1452 GPIOF_OUT_INIT_LOW,
1453 "HPDET");
1454 if (ret != 0) {
1455 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1456 arizona->pdata.hpdet_id_gpio, ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001457 goto err_gpio;
Mark Brown1eda6aa2013-01-11 08:55:54 +09001458 }
1459 }
1460
Mark Brownb17e5462013-01-11 08:55:24 +09001461 if (arizona->pdata.micd_bias_start_time)
1462 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1463 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1464 arizona->pdata.micd_bias_start_time
1465 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1466
Mark Brown2e033db2013-01-21 17:36:33 +09001467 if (arizona->pdata.micd_rate)
1468 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1469 ARIZONA_MICD_RATE_MASK,
1470 arizona->pdata.micd_rate
1471 << ARIZONA_MICD_RATE_SHIFT);
1472
Charles Keepaxbb327e92015-06-30 13:32:39 +01001473 switch (arizona->pdata.micd_dbtime) {
1474 case MICD_DBTIME_FOUR_READINGS:
Mark Brown2e033db2013-01-21 17:36:33 +09001475 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1476 ARIZONA_MICD_DBTIME_MASK,
Charles Keepaxbb327e92015-06-30 13:32:39 +01001477 ARIZONA_MICD_DBTIME);
1478 break;
1479 case MICD_DBTIME_TWO_READINGS:
1480 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1481 ARIZONA_MICD_DBTIME_MASK, 0);
1482 break;
1483 default:
1484 break;
1485 }
Mark Brown2e033db2013-01-21 17:36:33 +09001486
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001487 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) <
1488 ARIZONA_NUM_MICD_BUTTON_LEVELS);
Mark Brown6fed4d82013-04-01 22:03:06 +01001489
1490 if (arizona->pdata.num_micd_ranges) {
1491 info->micd_ranges = pdata->micd_ranges;
1492 info->num_micd_ranges = pdata->num_micd_ranges;
1493 } else {
1494 info->micd_ranges = micd_default_ranges;
1495 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1496 }
1497
1498 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1499 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1500 arizona->pdata.num_micd_ranges);
1501 }
1502
1503 if (info->num_micd_ranges > 1) {
1504 for (i = 1; i < info->num_micd_ranges; i++) {
1505 if (info->micd_ranges[i - 1].max >
1506 info->micd_ranges[i].max) {
1507 dev_err(arizona->dev,
1508 "MICD ranges must be sorted\n");
1509 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001510 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001511 }
1512 }
1513 }
1514
1515 /* Disable all buttons by default */
1516 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1517 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1518
1519 /* Set up all the buttons the user specified */
1520 for (i = 0; i < info->num_micd_ranges; i++) {
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001521 for (j = 0; j < ARIZONA_NUM_MICD_BUTTON_LEVELS; j++)
Mark Brown6fed4d82013-04-01 22:03:06 +01001522 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1523 break;
1524
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001525 if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
Mark Brown6fed4d82013-04-01 22:03:06 +01001526 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1527 info->micd_ranges[i].max);
1528 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001529 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001530 }
1531
1532 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1533 arizona_micd_levels[j], i);
1534
1535 arizona_micd_set_level(arizona, i, j);
1536 input_set_capability(info->input, EV_KEY,
1537 info->micd_ranges[i].key);
1538
1539 /* Enable reporting of that range */
1540 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1541 1 << i, 1 << i);
1542 }
1543
1544 /* Set all the remaining keys to a maximum */
1545 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1546 arizona_micd_set_level(arizona, i, 0x3f);
1547
Mark Browndab63eb2013-01-11 08:55:36 +09001548 /*
Mark Brown92a49872013-01-11 08:55:39 +09001549 * If we have a clamp use it, activating in conjunction with
1550 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001551 */
1552 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001553 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001554 /* Put the GPIO into input mode with optional pull */
1555 val = 0xc101;
1556 if (arizona->pdata.jd_gpio5_nopull)
1557 val &= ~ARIZONA_GPN_PU;
1558
Mark Brown92a49872013-01-11 08:55:39 +09001559 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001560 val);
Mark Brown92a49872013-01-11 08:55:39 +09001561
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001562 if (arizona->pdata.jd_invert)
1563 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1564 else
1565 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001566 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001567 if (arizona->pdata.jd_invert)
1568 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1569 else
1570 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001571 }
1572
Mark Browndab63eb2013-01-11 08:55:36 +09001573 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001574 ARIZONA_MICD_CLAMP_CONTROL,
1575 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1576
1577 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001578 ARIZONA_JACK_DETECT_DEBOUNCE,
1579 ARIZONA_MICD_CLAMP_DB,
1580 ARIZONA_MICD_CLAMP_DB);
1581 }
1582
Mark Brownf2c32a82012-06-24 12:09:45 +01001583 arizona_extcon_set_mode(info, 0);
1584
1585 pm_runtime_enable(&pdev->dev);
1586 pm_runtime_idle(&pdev->dev);
1587 pm_runtime_get_sync(&pdev->dev);
1588
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001589 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001590 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1591 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1592 } else {
1593 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1594 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1595 }
1596
1597 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001598 "JACKDET rise", arizona_jackdet, info);
1599 if (ret != 0) {
1600 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1601 ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001602 goto err_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +01001603 }
1604
Mark Brown92a49872013-01-11 08:55:39 +09001605 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001606 if (ret != 0) {
1607 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1608 ret);
1609 goto err_rise;
1610 }
1611
Mark Brown92a49872013-01-11 08:55:39 +09001612 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001613 "JACKDET fall", arizona_jackdet, info);
1614 if (ret != 0) {
1615 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1616 goto err_rise_wake;
1617 }
1618
Mark Brown92a49872013-01-11 08:55:39 +09001619 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001620 if (ret != 0) {
1621 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1622 ret);
1623 goto err_fall;
1624 }
1625
1626 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1627 "MICDET", arizona_micdet, info);
1628 if (ret != 0) {
1629 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1630 goto err_fall_wake;
1631 }
1632
Mark Brown4f340332013-01-11 08:55:43 +09001633 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1634 "HPDET", arizona_hpdet_irq, info);
1635 if (ret != 0) {
1636 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1637 goto err_micdet;
1638 }
1639
Mark Brownf2c32a82012-06-24 12:09:45 +01001640 arizona_clk32k_enable(arizona);
1641 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1642 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1643 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1644 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1645
Mark Brownb8575a12012-09-07 17:01:15 +08001646 ret = regulator_allow_bypass(info->micvdd, true);
1647 if (ret != 0)
1648 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1649 ret);
1650
Mark Brownf2c32a82012-06-24 12:09:45 +01001651 pm_runtime_put(&pdev->dev);
1652
Mark Brown34efe4d2012-07-20 17:07:29 +01001653 ret = input_register_device(info->input);
1654 if (ret) {
1655 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001656 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001657 }
1658
Mark Brownf2c32a82012-06-24 12:09:45 +01001659 return 0;
1660
Mark Brown4f340332013-01-11 08:55:43 +09001661err_hpdet:
1662 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001663err_micdet:
1664 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001665err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001666 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001667err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001668 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001669err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001670 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001671err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001672 arizona_free_irq(arizona, jack_irq_rise, info);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001673err_gpio:
1674 gpiod_put(info->micd_pol_gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +01001675err_register:
1676 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001677 return ret;
1678}
1679
Bill Pemberton93ed0322012-11-19 13:25:49 -05001680static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001681{
1682 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1683 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001684 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001685
Charles Keepax8e5838d2015-06-19 17:23:31 +01001686 gpiod_put(info->micd_pol_gpio);
1687
Mark Brownf2c32a82012-06-24 12:09:45 +01001688 pm_runtime_disable(&pdev->dev);
1689
Mark Browndab63eb2013-01-11 08:55:36 +09001690 regmap_update_bits(arizona->regmap,
1691 ARIZONA_MICD_CLAMP_CONTROL,
1692 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1693
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001694 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001695 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1696 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1697 } else {
1698 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1699 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1700 }
1701
1702 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1703 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1704 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001705 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001706 arizona_free_irq(arizona, jack_irq_rise, info);
1707 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001708 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001709 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1710 ARIZONA_JD1_ENA, 0);
1711 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001712
1713 return 0;
1714}
1715
1716static struct platform_driver arizona_extcon_driver = {
1717 .driver = {
1718 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001719 },
1720 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001721 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001722};
1723
1724module_platform_driver(arizona_extcon_driver);
1725
1726MODULE_DESCRIPTION("Arizona Extcon driver");
1727MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1728MODULE_LICENSE("GPL");
1729MODULE_ALIAS("platform:extcon-arizona");