blob: e2d78cd7030d3b0935c20f737906cf92f350a403 [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 Keepaxe57bb432017-01-25 09:34:06 +000054#define ARIZONA_HPDET_WAIT_COUNT 15
55#define ARIZONA_HPDET_WAIT_DELAY_MS 20
56
Charles Keepaxdf8b6772015-09-16 10:42:16 +010057#define QUICK_HEADPHONE_MAX_OHM 3
58#define MICROPHONE_MIN_OHM 1257
59#define MICROPHONE_MAX_OHM 30000
60
Charles Keepaxbb327e92015-06-30 13:32:39 +010061#define MICD_DBTIME_TWO_READINGS 2
62#define MICD_DBTIME_FOUR_READINGS 4
63
Charles Keepaxffae24f2013-11-14 16:18:21 +000064#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
65 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
66 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
67 ARIZONA_MICD_LVL_7)
68
69#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
70
71#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
72
Mark Brownf2c32a82012-06-24 12:09:45 +010073struct arizona_extcon_info {
74 struct device *dev;
75 struct arizona *arizona;
76 struct mutex lock;
77 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010078 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010079
Mark Browna3e20782013-04-01 19:05:27 +010080 u16 last_jackdet;
81
Mark Brownf2c32a82012-06-24 12:09:45 +010082 int micd_mode;
83 const struct arizona_micd_config *micd_modes;
84 int micd_num_modes;
85
Mark Brown6fed4d82013-04-01 22:03:06 +010086 const struct arizona_micd_range *micd_ranges;
87 int num_micd_ranges;
88
Mark Brown7abd4e22013-04-01 19:25:55 +010089 int micd_timeout;
90
Mark Brownf2c32a82012-06-24 12:09:45 +010091 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090092 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010093
Mark Brown0e27bd32013-02-05 21:00:15 +000094 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010095 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010096 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000097
Mark Brown4f340332013-01-11 08:55:43 +090098 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000099 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +0100100 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +0900101
Mark Browndd235ee2013-01-11 08:55:51 +0900102 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900103 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +0900104
Mark Brownf2c32a82012-06-24 12:09:45 +0100105 bool mic;
106 bool detecting;
107 int jack_flips;
108
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100109 int hpdet_ip_version;
Mark Brown4f340332013-01-11 08:55:43 +0900110
Chanwoo Choief70a212014-04-21 20:47:31 +0900111 struct extcon_dev *edev;
Charles Keepax8e5838d2015-06-19 17:23:31 +0100112
113 struct gpio_desc *micd_pol_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +0100114};
115
116static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +0100117 { ARIZONA_ACCDET_SRC, 1, 0 },
118 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100119};
120
Mark Brown6fed4d82013-04-01 22:03:06 +0100121static const struct arizona_micd_range micd_default_ranges[] = {
122 { .max = 11, .key = BTN_0 },
123 { .max = 28, .key = BTN_1 },
124 { .max = 54, .key = BTN_2 },
125 { .max = 100, .key = BTN_3 },
126 { .max = 186, .key = BTN_4 },
127 { .max = 430, .key = BTN_5 },
128};
129
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100130/* The number of levels in arizona_micd_levels valid for button thresholds */
131#define ARIZONA_NUM_MICD_BUTTON_LEVELS 64
132
Mark Brown6fed4d82013-04-01 22:03:06 +0100133static const int arizona_micd_levels[] = {
134 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
135 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
136 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
137 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100138 1257, 30000,
Mark Brown34efe4d2012-07-20 17:07:29 +0100139};
140
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900141static const unsigned int arizona_cable[] = {
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900142 EXTCON_MECHANICAL,
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900143 EXTCON_JACK_MICROPHONE,
144 EXTCON_JACK_HEADPHONE,
145 EXTCON_JACK_LINE_OUT,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900146 EXTCON_NONE,
Mark Brownf2c32a82012-06-24 12:09:45 +0100147};
148
Mark Brown9dd5e532013-04-01 19:09:45 +0100149static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
150
Charles Keepax112bdfa2015-02-16 15:41:02 +0000151static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
152 bool clamp)
Mark Brown03409072013-02-12 13:00:31 +0000153{
154 struct arizona *arizona = info->arizona;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000155 unsigned int mask = 0, val = 0;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100156 unsigned int cap_sel = 0;
Mark Brown03409072013-02-12 13:00:31 +0000157 int ret;
158
Charles Keepax43f0acd2015-02-16 15:41:03 +0000159 switch (arizona->type) {
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100160 case WM8998:
161 case WM1814:
162 mask = 0;
163 break;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000164 case WM5110:
Charles Keepax2b51f9c2015-04-30 23:43:37 +0900165 case WM8280:
Charles Keepax43f0acd2015-02-16 15:41:03 +0000166 mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
167 ARIZONA_HP1L_SHRTI;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100168 if (clamp) {
Charles Keepax43f0acd2015-02-16 15:41:03 +0000169 val = ARIZONA_HP1L_SHRTO;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100170 cap_sel = ARIZONA_TST_CAP_CLAMP;
171 } else {
Charles Keepax43f0acd2015-02-16 15:41:03 +0000172 val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100173 cap_sel = ARIZONA_TST_CAP_DEFAULT;
174 }
175
176 ret = regmap_update_bits(arizona->regmap,
177 ARIZONA_HP_TEST_CTRL_1,
178 ARIZONA_HP1_TST_CAP_SEL_MASK,
179 cap_sel);
180 if (ret != 0)
181 dev_warn(arizona->dev,
182 "Failed to set TST_CAP_SEL: %d\n", ret);
Charles Keepax43f0acd2015-02-16 15:41:03 +0000183 break;
184 default:
185 mask = ARIZONA_RMV_SHRT_HP1L;
186 if (clamp)
187 val = ARIZONA_RMV_SHRT_HP1L;
188 break;
Charles Keepaxc19dc202016-07-19 13:23:56 +0100189 }
Charles Keepax112bdfa2015-02-16 15:41:02 +0000190
Charles Keepax03bf1ad2015-12-29 16:32:03 +0000191 snd_soc_dapm_mutex_lock(arizona->dapm);
Mark Brown03409072013-02-12 13:00:31 +0000192
Charles Keepax112bdfa2015-02-16 15:41:02 +0000193 arizona->hpdet_clamp = clamp;
Mark Browndf8c3db2013-02-22 18:38:03 +0000194
Charles Keepax112bdfa2015-02-16 15:41:02 +0000195 /* Keep the HP output stages disabled while doing the clamp */
196 if (clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000197 ret = regmap_update_bits(arizona->regmap,
198 ARIZONA_OUTPUT_ENABLES_1,
199 ARIZONA_OUT1L_ENA |
200 ARIZONA_OUT1R_ENA, 0);
201 if (ret != 0)
202 dev_warn(arizona->dev,
203 "Failed to disable headphone outputs: %d\n",
204 ret);
Mark Brown03409072013-02-12 13:00:31 +0000205 }
206
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100207 if (mask) {
208 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
209 mask, val);
210 if (ret != 0)
211 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000212 ret);
213
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100214 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
215 mask, val);
216 if (ret != 0)
217 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
218 ret);
219 }
Mark Browndf8c3db2013-02-22 18:38:03 +0000220
Charles Keepax112bdfa2015-02-16 15:41:02 +0000221 /* Restore the desired state while not doing the clamp */
222 if (!clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000223 ret = regmap_update_bits(arizona->regmap,
224 ARIZONA_OUTPUT_ENABLES_1,
225 ARIZONA_OUT1L_ENA |
226 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000227 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000228 dev_warn(arizona->dev,
229 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000230 ret);
231 }
232
Charles Keepax03bf1ad2015-12-29 16:32:03 +0000233 snd_soc_dapm_mutex_unlock(arizona->dapm);
Mark Brown03409072013-02-12 13:00:31 +0000234}
235
Mark Brownf2c32a82012-06-24 12:09:45 +0100236static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
237{
238 struct arizona *arizona = info->arizona;
239
Mark Brown6fed4d82013-04-01 22:03:06 +0100240 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800241
Charles Keepax6c467a12016-11-25 13:44:36 +0000242 gpiod_set_value_cansleep(info->micd_pol_gpio,
243 info->micd_modes[mode].gpio);
Charles Keepax8e5838d2015-06-19 17:23:31 +0100244
Mark Brownf2c32a82012-06-24 12:09:45 +0100245 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
246 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100247 info->micd_modes[mode].bias <<
248 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100249 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
250 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
251
252 info->micd_mode = mode;
253
254 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
255}
256
Mark Brownbbbd46e2013-01-10 19:38:43 +0000257static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
258{
Charles Keepax41024242013-09-23 14:33:59 +0100259 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000260 case 1:
261 return "MICBIAS1";
262 case 2:
263 return "MICBIAS2";
264 case 3:
265 return "MICBIAS3";
266 default:
267 return "MICVDD";
268 }
269}
270
271static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
272{
273 struct arizona *arizona = info->arizona;
274 const char *widget = arizona_extcon_get_micbias(info);
275 struct snd_soc_dapm_context *dapm = arizona->dapm;
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000276 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000277 int ret;
278
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000279 ret = snd_soc_component_force_enable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000280 if (ret != 0)
281 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
282 widget, ret);
283
Mark Brownbbbd46e2013-01-10 19:38:43 +0000284 snd_soc_dapm_sync(dapm);
285
286 if (!arizona->pdata.micd_force_micbias) {
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000287 ret = snd_soc_component_disable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000288 if (ret != 0)
289 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
290 widget, ret);
291
Mark Brownbbbd46e2013-01-10 19:38:43 +0000292 snd_soc_dapm_sync(dapm);
293 }
294}
295
Mark Brown9b1270c2013-01-11 08:55:46 +0900296static void arizona_start_mic(struct arizona_extcon_info *info)
297{
298 struct arizona *arizona = info->arizona;
299 bool change;
300 int ret;
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100301 unsigned int mode;
Mark Brown9b1270c2013-01-11 08:55:46 +0900302
Mark Brown9b1270c2013-01-11 08:55:46 +0900303 /* Microphone detection can't use idle mode */
304 pm_runtime_get(info->dev);
305
Mark Brownbbbd46e2013-01-10 19:38:43 +0000306 if (info->detecting) {
307 ret = regulator_allow_bypass(info->micvdd, false);
308 if (ret != 0) {
309 dev_err(arizona->dev,
310 "Failed to regulate MICVDD: %d\n",
311 ret);
312 }
313 }
314
Mark Brown9b1270c2013-01-11 08:55:46 +0900315 ret = regulator_enable(info->micvdd);
316 if (ret != 0) {
317 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
318 ret);
319 }
320
321 if (info->micd_reva) {
322 regmap_write(arizona->regmap, 0x80, 0x3);
323 regmap_write(arizona->regmap, 0x294, 0);
324 regmap_write(arizona->regmap, 0x80, 0x0);
325 }
326
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100327 if (info->detecting && arizona->pdata.micd_software_compare)
328 mode = ARIZONA_ACCDET_MODE_ADC;
329 else
330 mode = ARIZONA_ACCDET_MODE_MIC;
331
Mark Brown9b1270c2013-01-11 08:55:46 +0900332 regmap_update_bits(arizona->regmap,
333 ARIZONA_ACCESSORY_DETECT_MODE_1,
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100334 ARIZONA_ACCDET_MODE_MASK, mode);
Mark Brown9b1270c2013-01-11 08:55:46 +0900335
Mark Brownbbbd46e2013-01-10 19:38:43 +0000336 arizona_extcon_pulse_micbias(info);
337
Mark Brown9b1270c2013-01-11 08:55:46 +0900338 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
339 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
340 &change);
341 if (!change) {
342 regulator_disable(info->micvdd);
343 pm_runtime_put_autosuspend(info->dev);
344 }
345}
346
347static void arizona_stop_mic(struct arizona_extcon_info *info)
348{
349 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000350 const char *widget = arizona_extcon_get_micbias(info);
351 struct snd_soc_dapm_context *dapm = arizona->dapm;
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000352 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
Mark Brown9b1270c2013-01-11 08:55:46 +0900353 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000354 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900355
356 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
357 ARIZONA_MICD_ENA, 0,
358 &change);
359
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000360 ret = snd_soc_component_disable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000361 if (ret != 0)
362 dev_warn(arizona->dev,
363 "Failed to disable %s: %d\n",
364 widget, ret);
365
Mark Brownbbbd46e2013-01-10 19:38:43 +0000366 snd_soc_dapm_sync(dapm);
367
Mark Brown9b1270c2013-01-11 08:55:46 +0900368 if (info->micd_reva) {
369 regmap_write(arizona->regmap, 0x80, 0x3);
370 regmap_write(arizona->regmap, 0x294, 2);
371 regmap_write(arizona->regmap, 0x80, 0x0);
372 }
373
Mark Brownbbbd46e2013-01-10 19:38:43 +0000374 ret = regulator_allow_bypass(info->micvdd, true);
375 if (ret != 0) {
376 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
377 ret);
378 }
379
Mark Brown9b1270c2013-01-11 08:55:46 +0900380 if (change) {
381 regulator_disable(info->micvdd);
382 pm_runtime_mark_last_busy(info->dev);
383 pm_runtime_put_autosuspend(info->dev);
384 }
385}
386
Mark Brown4f340332013-01-11 08:55:43 +0900387static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100388 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900389 unsigned int factor_a;
390 unsigned int factor_b;
391} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100392 { 100, 5528, 362464 },
393 { 169, 11084, 6186851 },
394 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900395};
396
Charles Keepax24a279b2014-05-30 13:19:17 +0100397#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
398
Mark Brown4f340332013-01-11 08:55:43 +0900399static struct {
400 int min;
401 int max;
402} arizona_hpdet_c_ranges[] = {
403 { 0, 30 },
404 { 8, 100 },
405 { 100, 1000 },
406 { 1000, 10000 },
407};
408
409static int arizona_hpdet_read(struct arizona_extcon_info *info)
410{
411 struct arizona *arizona = info->arizona;
412 unsigned int val, range;
413 int ret;
414
415 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
416 if (ret != 0) {
417 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
418 ret);
419 return ret;
420 }
421
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100422 switch (info->hpdet_ip_version) {
Mark Brown4f340332013-01-11 08:55:43 +0900423 case 0:
424 if (!(val & ARIZONA_HP_DONE)) {
425 dev_err(arizona->dev, "HPDET did not complete: %x\n",
426 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900427 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900428 }
429
430 val &= ARIZONA_HP_LVL_MASK;
431 break;
432
433 case 1:
434 if (!(val & ARIZONA_HP_DONE_B)) {
435 dev_err(arizona->dev, "HPDET did not complete: %x\n",
436 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900437 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900438 }
439
440 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
441 if (ret != 0) {
442 dev_err(arizona->dev, "Failed to read HP value: %d\n",
443 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900444 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900445 }
446
447 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
448 &range);
449 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
450 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
451
452 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100453 (val < arizona_hpdet_b_ranges[range].threshold ||
454 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900455 range++;
456 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
457 range);
458 regmap_update_bits(arizona->regmap,
459 ARIZONA_HEADPHONE_DETECT_1,
460 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
461 range <<
462 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
463 return -EAGAIN;
464 }
465
466 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100467 if (val < arizona_hpdet_b_ranges[range].threshold ||
468 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900469 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100470 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900471 }
472
473 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
474 val, range);
475
476 val = arizona_hpdet_b_ranges[range].factor_b
477 / ((val * 100) -
478 arizona_hpdet_b_ranges[range].factor_a);
479 break;
480
Mark Brown4f340332013-01-11 08:55:43 +0900481 case 2:
482 if (!(val & ARIZONA_HP_DONE_B)) {
483 dev_err(arizona->dev, "HPDET did not complete: %x\n",
484 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900485 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900486 }
487
488 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000489 /* Convert to ohms, the value is in 0.5 ohm increments */
490 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900491
492 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
493 &range);
494 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
495 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
496
Charles Keepax91414612013-11-14 16:18:24 +0000497 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900498 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
499 (val >= arizona_hpdet_c_ranges[range].max)) {
500 range++;
501 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
502 arizona_hpdet_c_ranges[range].min,
503 arizona_hpdet_c_ranges[range].max);
504 regmap_update_bits(arizona->regmap,
505 ARIZONA_HEADPHONE_DETECT_1,
506 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
507 range <<
508 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
509 return -EAGAIN;
510 }
Charles Keepax91414612013-11-14 16:18:24 +0000511
512 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
513 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
514 arizona_hpdet_c_ranges[range].min);
515 val = arizona_hpdet_c_ranges[range].min;
516 }
Chanwoo Choie9844b22015-09-29 19:06:31 +0900517 break;
518
519 default:
520 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
521 info->hpdet_ip_version);
522 return -EINVAL;
Mark Brown4f340332013-01-11 08:55:43 +0900523 }
524
525 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
526 return val;
527}
528
Mark Brown9c2ba272013-02-25 23:42:31 +0000529static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
530 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900531{
532 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900533 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900534
535 /*
536 * If we're using HPDET for accessory identification we need
537 * to take multiple measurements, step through them in sequence.
538 */
539 if (arizona->pdata.hpdet_acc_id) {
540 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900541
542 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000543 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900544 dev_dbg(arizona->dev, "Measuring mic\n");
545
546 regmap_update_bits(arizona->regmap,
547 ARIZONA_ACCESSORY_DETECT_MODE_1,
548 ARIZONA_ACCDET_MODE_MASK |
549 ARIZONA_ACCDET_SRC,
550 ARIZONA_ACCDET_MODE_HPR |
551 info->micd_modes[0].src);
552
553 gpio_set_value_cansleep(id_gpio, 1);
554
Mark Browndd235ee2013-01-11 08:55:51 +0900555 regmap_update_bits(arizona->regmap,
556 ARIZONA_HEADPHONE_DETECT_1,
557 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
558 return -EAGAIN;
559 }
560
561 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000562 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
563 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000564
565 /* Take the headphone impedance for the main report */
566 *reading = info->hpdet_res[0];
567
Mark Brown9dd5e532013-04-01 19:09:45 +0100568 /* Sometimes we get false readings due to slow insert */
569 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
570 dev_dbg(arizona->dev, "Retrying high impedance\n");
571 info->num_hpdet_res = 0;
572 info->hpdet_retried = true;
573 arizona_start_hpdet_acc_id(info);
574 pm_runtime_put(info->dev);
575 return -EAGAIN;
576 }
577
Mark Brown1eda6aa2013-01-11 08:55:54 +0900578 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530579 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900580 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000581 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900582 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000583 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000584 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900585 } else {
586 dev_dbg(arizona->dev, "Detected headphone\n");
587 }
588
589 /* Make sure everything is reset back to the real polarity */
590 regmap_update_bits(arizona->regmap,
591 ARIZONA_ACCESSORY_DETECT_MODE_1,
592 ARIZONA_ACCDET_SRC,
593 info->micd_modes[0].src);
594 }
595
596 return 0;
597}
598
Mark Brown4f340332013-01-11 08:55:43 +0900599static irqreturn_t arizona_hpdet_irq(int irq, void *data)
600{
601 struct arizona_extcon_info *info = data;
602 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900603 int id_gpio = arizona->pdata.hpdet_id_gpio;
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900604 unsigned int report = EXTCON_JACK_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900605 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000606 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900607
608 mutex_lock(&info->lock);
609
610 /* If we got a spurious IRQ for some reason then ignore it */
611 if (!info->hpdet_active) {
612 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
613 mutex_unlock(&info->lock);
614 return IRQ_NONE;
615 }
616
617 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900618 ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900619 if (ret < 0) {
620 dev_err(arizona->dev, "Failed to check cable state: %d\n",
621 ret);
622 goto out;
623 } else if (!ret) {
624 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
625 goto done;
626 }
627
628 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900629 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900630 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900631 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900632 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900633 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900634
635 /* Reset back to starting range */
636 regmap_update_bits(arizona->regmap,
637 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900638 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
639 0);
640
Mark Brown9c2ba272013-02-25 23:42:31 +0000641 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900642 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900643 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900644 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900645 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900646
647 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900648 if (reading >= 5000)
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900649 report = EXTCON_JACK_LINE_OUT;
Mark Brown4f340332013-01-11 08:55:43 +0900650 else
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900651 report = EXTCON_JACK_HEADPHONE;
Mark Brown4f340332013-01-11 08:55:43 +0900652
Chanwoo Choi8670b452016-08-16 15:55:34 +0900653 ret = extcon_set_state_sync(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900654 if (ret != 0)
655 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
656 ret);
657
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000658done:
659 /* Reset back to starting range */
660 regmap_update_bits(arizona->regmap,
661 ARIZONA_HEADPHONE_DETECT_1,
662 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
663 0);
664
Charles Keepax112bdfa2015-02-16 15:41:02 +0000665 arizona_extcon_hp_clamp(info, false);
Mark Brown4f340332013-01-11 08:55:43 +0900666
Mark Brown1eda6aa2013-01-11 08:55:54 +0900667 if (id_gpio)
668 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900669
670 /* Revert back to MICDET mode */
671 regmap_update_bits(arizona->regmap,
672 ARIZONA_ACCESSORY_DETECT_MODE_1,
673 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
674
675 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000676 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900677 arizona_start_mic(info);
678
679 if (info->hpdet_active) {
680 pm_runtime_put_autosuspend(info->dev);
681 info->hpdet_active = false;
682 }
683
Mark Brownbf14ee52013-02-05 20:20:17 +0000684 info->hpdet_done = true;
685
Mark Brown4f340332013-01-11 08:55:43 +0900686out:
687 mutex_unlock(&info->lock);
688
689 return IRQ_HANDLED;
690}
691
692static void arizona_identify_headphone(struct arizona_extcon_info *info)
693{
694 struct arizona *arizona = info->arizona;
695 int ret;
696
Mark Brownbf14ee52013-02-05 20:20:17 +0000697 if (info->hpdet_done)
698 return;
699
Mark Brown4f340332013-01-11 08:55:43 +0900700 dev_dbg(arizona->dev, "Starting HPDET\n");
701
702 /* Make sure we keep the device enabled during the measurement */
703 pm_runtime_get(info->dev);
704
705 info->hpdet_active = true;
706
707 if (info->mic)
708 arizona_stop_mic(info);
709
Charles Keepax112bdfa2015-02-16 15:41:02 +0000710 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900711
712 ret = regmap_update_bits(arizona->regmap,
713 ARIZONA_ACCESSORY_DETECT_MODE_1,
714 ARIZONA_ACCDET_MODE_MASK,
Inha Song9e86b2a2015-05-04 13:42:13 +0900715 arizona->pdata.hpdet_channel);
Mark Brown4f340332013-01-11 08:55:43 +0900716 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900717 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +0900718 goto err;
719 }
720
721 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
722 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
723 if (ret != 0) {
724 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
725 ret);
726 goto err;
727 }
728
729 return;
730
731err:
732 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
733 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
734
735 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900736 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900737 if (ret != 0)
738 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
739
740 if (info->mic)
741 arizona_start_mic(info);
742
743 info->hpdet_active = false;
744}
Mark Browndd235ee2013-01-11 08:55:51 +0900745
746static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
747{
748 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000749 int hp_reading = 32;
750 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900751 int ret;
752
753 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
754
755 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000756 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900757
758 info->hpdet_active = true;
759
Charles Keepax112bdfa2015-02-16 15:41:02 +0000760 arizona_extcon_hp_clamp(info, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900761
762 ret = regmap_update_bits(arizona->regmap,
763 ARIZONA_ACCESSORY_DETECT_MODE_1,
764 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
765 info->micd_modes[0].src |
Inha Song9e86b2a2015-05-04 13:42:13 +0900766 arizona->pdata.hpdet_channel);
Mark Browndd235ee2013-01-11 08:55:51 +0900767 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900768 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Browndd235ee2013-01-11 08:55:51 +0900769 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900770 }
771
Mark Brown9c2ba272013-02-25 23:42:31 +0000772 if (arizona->pdata.hpdet_acc_id_line) {
773 ret = regmap_update_bits(arizona->regmap,
774 ARIZONA_HEADPHONE_DETECT_1,
775 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
776 if (ret != 0) {
777 dev_err(arizona->dev,
778 "Can't start HPDETL measurement: %d\n",
779 ret);
780 goto err;
781 }
782 } else {
783 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900784 }
785
786 return;
787
788err:
789 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
790 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
791
792 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900793 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900794 if (ret != 0)
795 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
796
Mark Brown4f340332013-01-11 08:55:43 +0900797 info->hpdet_active = false;
798}
799
Mark Brown939c5672013-04-01 19:17:34 +0100800static void arizona_micd_timeout_work(struct work_struct *work)
801{
802 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900803 struct arizona_extcon_info,
804 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100805
806 mutex_lock(&info->lock);
807
808 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
Mark Brown939c5672013-04-01 19:17:34 +0100809
810 info->detecting = false;
811
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100812 arizona_identify_headphone(info);
813
Mark Brown939c5672013-04-01 19:17:34 +0100814 arizona_stop_mic(info);
815
816 mutex_unlock(&info->lock);
817}
818
Mark Browncd59e792013-04-01 19:21:48 +0100819static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100820{
Mark Browncd59e792013-04-01 19:21:48 +0100821 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900822 struct arizona_extcon_info,
823 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100824 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100825 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100826 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100827
Mark Brown939c5672013-04-01 19:17:34 +0100828 cancel_delayed_work_sync(&info->micd_timeout_work);
829
Mark Brownf2c32a82012-06-24 12:09:45 +0100830 mutex_lock(&info->lock);
831
Charles Keepax31a847e2013-11-14 16:18:23 +0000832 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900833 ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000834 if (ret < 0) {
835 dev_err(arizona->dev, "Failed to check cable state: %d\n",
836 ret);
837 mutex_unlock(&info->lock);
838 return;
839 } else if (!ret) {
840 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
841 mutex_unlock(&info->lock);
842 return;
843 }
844
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100845 if (info->detecting && arizona->pdata.micd_software_compare) {
846 /* Must disable MICD before we read the ADCVAL */
847 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
848 ARIZONA_MICD_ENA, 0);
849 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
850 if (ret != 0) {
851 dev_err(arizona->dev,
852 "Failed to read MICDET_ADCVAL: %d\n",
853 ret);
854 mutex_unlock(&info->lock);
855 return;
856 }
857
858 dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
859
860 val &= ARIZONA_MICDET_ADCVAL_MASK;
861 if (val < ARRAY_SIZE(arizona_micd_levels))
862 val = arizona_micd_levels[val];
863 else
864 val = INT_MAX;
865
866 if (val <= QUICK_HEADPHONE_MAX_OHM)
867 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
868 else if (val <= MICROPHONE_MIN_OHM)
869 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
870 else if (val <= MICROPHONE_MAX_OHM)
871 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
872 else
873 val = ARIZONA_MICD_LVL_8;
874 }
875
Charles Keepaxffae24f2013-11-14 16:18:21 +0000876 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100877 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
878 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900879 dev_err(arizona->dev,
880 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100881 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100882 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100883 }
884
885 dev_dbg(arizona->dev, "MICDET: %x\n", val);
886
887 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900888 dev_warn(arizona->dev,
889 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100890 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100891 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100892 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100893 }
894
Charles Keepaxffae24f2013-11-14 16:18:21 +0000895 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100896 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100897 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100898 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100899 }
900
901 /* Due to jack detect this should never happen */
902 if (!(val & ARIZONA_MICD_STS)) {
903 dev_warn(arizona->dev, "Detected open circuit\n");
Charles Keepax57f70ef2015-06-25 16:47:02 +0100904 info->mic = false;
905 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100906 info->detecting = false;
Charles Keepax57f70ef2015-06-25 16:47:02 +0100907 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100908 goto handled;
909 }
910
911 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000912 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100913 info->mic = true;
914 info->detecting = false;
915
Mark Brown4f340332013-01-11 08:55:43 +0900916 arizona_identify_headphone(info);
917
Chanwoo Choi8670b452016-08-16 15:55:34 +0900918 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900919 EXTCON_JACK_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100920 if (ret != 0)
921 dev_err(arizona->dev, "Headset report failed: %d\n",
922 ret);
923
Mark Brownbbbd46e2013-01-10 19:38:43 +0000924 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100925 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000926 if (ret != 0) {
927 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
928 ret);
929 }
930
Mark Brownf2c32a82012-06-24 12:09:45 +0100931 goto handled;
932 }
933
934 /* If we detected a lower impedence during initial startup
935 * then we probably have the wrong polarity, flip it. Don't
936 * do this for the lowest impedences to speed up detection of
937 * plain headphones. If both polarities report a low
938 * impedence then give up and report headphones.
939 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000940 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800941 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900942 dev_dbg(arizona->dev, "Detected HP/line\n");
Mark Brown9ef2224d2012-06-28 13:08:31 +0100943
Mark Brown4f340332013-01-11 08:55:43 +0900944 info->detecting = false;
945
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100946 arizona_identify_headphone(info);
947
Mark Brown4f340332013-01-11 08:55:43 +0900948 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100949 } else {
950 info->micd_mode++;
951 if (info->micd_mode == info->micd_num_modes)
952 info->micd_mode = 0;
953 arizona_extcon_set_mode(info, info->micd_mode);
954
955 info->jack_flips++;
956 }
957
958 goto handled;
959 }
960
961 /*
962 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100963 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100964 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000965 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100966 if (info->mic) {
967 dev_dbg(arizona->dev, "Mic button detected\n");
968
Mark Brown34efe4d2012-07-20 17:07:29 +0100969 lvl = val & ARIZONA_MICD_LVL_MASK;
970 lvl >>= ARIZONA_MICD_LVL_SHIFT;
971
Mark Brown41a57852013-04-01 19:18:18 +0100972 for (i = 0; i < info->num_micd_ranges; i++)
973 input_report_key(info->input,
974 info->micd_ranges[i].key, 0);
975
Mark Brown6fed4d82013-04-01 22:03:06 +0100976 WARN_ON(!lvl);
977 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
978 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
979 key = info->micd_ranges[ffs(lvl) - 1].key;
980 input_report_key(info->input, key, 1);
981 input_sync(info->input);
982 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100983
Mark Brownf2c32a82012-06-24 12:09:45 +0100984 } else if (info->detecting) {
985 dev_dbg(arizona->dev, "Headphone detected\n");
986 info->detecting = false;
987 arizona_stop_mic(info);
988
Mark Brown4f340332013-01-11 08:55:43 +0900989 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100990 } else {
991 dev_warn(arizona->dev, "Button with no mic: %x\n",
992 val);
993 }
994 } else {
995 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100996 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100997 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100998 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100999 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +00001000 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001001 }
1002
1003handled:
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001004 if (info->detecting) {
1005 if (arizona->pdata.micd_software_compare)
1006 regmap_update_bits(arizona->regmap,
1007 ARIZONA_MIC_DETECT_1,
1008 ARIZONA_MICD_ENA,
1009 ARIZONA_MICD_ENA);
1010
Mark Browndf9a5ab2013-07-18 22:42:22 +01001011 queue_delayed_work(system_power_efficient_wq,
1012 &info->micd_timeout_work,
1013 msecs_to_jiffies(info->micd_timeout));
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001014 }
Mark Brown939c5672013-04-01 19:17:34 +01001015
Mark Brownf2c32a82012-06-24 12:09:45 +01001016 pm_runtime_mark_last_busy(info->dev);
1017 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +01001018}
1019
1020static irqreturn_t arizona_micdet(int irq, void *data)
1021{
1022 struct arizona_extcon_info *info = data;
1023 struct arizona *arizona = info->arizona;
1024 int debounce = arizona->pdata.micd_detect_debounce;
1025
1026 cancel_delayed_work_sync(&info->micd_detect_work);
1027 cancel_delayed_work_sync(&info->micd_timeout_work);
1028
1029 mutex_lock(&info->lock);
1030 if (!info->detecting)
1031 debounce = 0;
1032 mutex_unlock(&info->lock);
1033
1034 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001035 queue_delayed_work(system_power_efficient_wq,
1036 &info->micd_detect_work,
1037 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +01001038 else
1039 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001040
1041 return IRQ_HANDLED;
1042}
1043
Mark Brown0e27bd32013-02-05 21:00:15 +00001044static void arizona_hpdet_work(struct work_struct *work)
1045{
1046 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001047 struct arizona_extcon_info,
1048 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +00001049
1050 mutex_lock(&info->lock);
1051 arizona_start_hpdet_acc_id(info);
1052 mutex_unlock(&info->lock);
1053}
1054
Charles Keepaxe57bb432017-01-25 09:34:06 +00001055static int arizona_hpdet_wait(struct arizona_extcon_info *info)
1056{
1057 struct arizona *arizona = info->arizona;
1058 unsigned int val;
1059 int i, ret;
1060
1061 for (i = 0; i < ARIZONA_HPDET_WAIT_COUNT; i++) {
1062 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2,
1063 &val);
1064 if (ret) {
1065 dev_err(arizona->dev,
1066 "Failed to read HPDET state: %d\n", ret);
1067 return ret;
1068 }
1069
1070 switch (info->hpdet_ip_version) {
1071 case 0:
1072 if (val & ARIZONA_HP_DONE)
1073 return 0;
1074 break;
1075 default:
1076 if (val & ARIZONA_HP_DONE_B)
1077 return 0;
1078 break;
1079 }
1080
1081 msleep(ARIZONA_HPDET_WAIT_DELAY_MS);
1082 }
1083
1084 dev_warn(arizona->dev, "HPDET did not appear to complete\n");
1085
1086 return -ETIMEDOUT;
1087}
1088
Mark Brownf2c32a82012-06-24 12:09:45 +01001089static irqreturn_t arizona_jackdet(int irq, void *data)
1090{
1091 struct arizona_extcon_info *info = data;
1092 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001093 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +01001094 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +01001095 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +01001096
Mark Brown939c5672013-04-01 19:17:34 +01001097 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
1098 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001099
Mark Browna3e20782013-04-01 19:05:27 +01001100 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +00001101
Mark Brownf2c32a82012-06-24 12:09:45 +01001102 mutex_lock(&info->lock);
1103
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001104 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001105 mask = ARIZONA_MICD_CLAMP_STS;
Nariman Poushina0ef6422015-09-16 10:42:19 +01001106 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +09001107 } else {
1108 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001109 if (arizona->pdata.jd_invert)
1110 present = 0;
1111 else
1112 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +09001113 }
1114
Mark Brownf2c32a82012-06-24 12:09:45 +01001115 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
1116 if (ret != 0) {
1117 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
1118 ret);
1119 mutex_unlock(&info->lock);
1120 pm_runtime_put_autosuspend(info->dev);
1121 return IRQ_NONE;
1122 }
1123
Mark Browna3e20782013-04-01 19:05:27 +01001124 val &= mask;
1125 if (val == info->last_jackdet) {
1126 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001127 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001128 queue_delayed_work(system_power_efficient_wq,
1129 &info->hpdet_work,
1130 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001131
Chanwoo Choic2275d22013-08-23 10:21:37 +09001132 if (cancelled_mic) {
1133 int micd_timeout = info->micd_timeout;
1134
Mark Browndf9a5ab2013-07-18 22:42:22 +01001135 queue_delayed_work(system_power_efficient_wq,
1136 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001137 msecs_to_jiffies(micd_timeout));
1138 }
Mark Brown939c5672013-04-01 19:17:34 +01001139
Mark Browna3e20782013-04-01 19:05:27 +01001140 goto out;
1141 }
1142 info->last_jackdet = val;
1143
1144 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001145 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choi8670b452016-08-16 15:55:34 +09001146 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +09001147 EXTCON_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001148
1149 if (ret != 0)
1150 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1151 ret);
1152
Mark Browndd235ee2013-01-11 08:55:51 +09001153 if (!arizona->pdata.hpdet_acc_id) {
1154 info->detecting = true;
1155 info->mic = false;
1156 info->jack_flips = 0;
1157
1158 arizona_start_mic(info);
1159 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001160 queue_delayed_work(system_power_efficient_wq,
1161 &info->hpdet_work,
1162 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001163 }
Mark Brown4e616872013-01-15 22:09:20 +09001164
Charles Keepax6c20b932015-09-16 10:42:21 +01001165 if (info->micd_clamp || !arizona->pdata.jd_invert)
1166 regmap_update_bits(arizona->regmap,
1167 ARIZONA_JACK_DETECT_DEBOUNCE,
1168 ARIZONA_MICD_CLAMP_DB |
1169 ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001170 } else {
1171 dev_dbg(arizona->dev, "Detected jack removal\n");
1172
1173 arizona_stop_mic(info);
1174
Mark Browndd235ee2013-01-11 08:55:51 +09001175 info->num_hpdet_res = 0;
1176 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1177 info->hpdet_res[i] = 0;
1178 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001179 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001180 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001181
Mark Brown6fed4d82013-04-01 22:03:06 +01001182 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001183 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001184 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001185 input_sync(info->input);
1186
Chanwoo Choi5475e632016-07-01 02:36:49 +09001187 for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) {
Chanwoo Choi8670b452016-08-16 15:55:34 +09001188 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi5475e632016-07-01 02:36:49 +09001189 arizona_cable[i], false);
1190 if (ret != 0)
1191 dev_err(arizona->dev,
1192 "Removal report failed: %d\n", ret);
1193 }
Mark Brown4e616872013-01-15 22:09:20 +09001194
Charles Keepaxe57bb432017-01-25 09:34:06 +00001195 /*
1196 * If the jack was removed during a headphone detection we
1197 * need to wait for the headphone detection to finish, as
1198 * it can not be aborted. We don't want to be able to start
1199 * a new headphone detection from a fresh insert until this
1200 * one is finished.
1201 */
1202 arizona_hpdet_wait(info);
1203
Mark Brown4e616872013-01-15 22:09:20 +09001204 regmap_update_bits(arizona->regmap,
1205 ARIZONA_JACK_DETECT_DEBOUNCE,
1206 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1207 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001208 }
1209
Mark Brown7abd4e22013-04-01 19:25:55 +01001210 if (arizona->pdata.micd_timeout)
1211 info->micd_timeout = arizona->pdata.micd_timeout;
1212 else
1213 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1214
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001215out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001216 /* Clear trig_sts to make sure DCVDD is not forced up */
1217 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1218 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1219 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1220 ARIZONA_JD1_FALL_TRIG_STS |
1221 ARIZONA_JD1_RISE_TRIG_STS);
1222
Mark Brownf2c32a82012-06-24 12:09:45 +01001223 mutex_unlock(&info->lock);
1224
1225 pm_runtime_mark_last_busy(info->dev);
1226 pm_runtime_put_autosuspend(info->dev);
1227
1228 return IRQ_HANDLED;
1229}
1230
Mark Brown6fed4d82013-04-01 22:03:06 +01001231/* Map a level onto a slot in the register bank */
1232static void arizona_micd_set_level(struct arizona *arizona, int index,
1233 unsigned int level)
1234{
1235 int reg;
1236 unsigned int mask;
1237
1238 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1239
1240 if (!(index % 2)) {
1241 mask = 0x3f00;
1242 level <<= 8;
1243 } else {
1244 mask = 0x3f;
1245 }
1246
1247 /* Program the level itself */
1248 regmap_update_bits(arizona->regmap, reg, mask, level);
1249}
1250
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001251static int arizona_extcon_get_micd_configs(struct device *dev,
1252 struct arizona *arizona)
1253{
1254 const char * const prop = "wlf,micd-configs";
1255 const int entries_per_config = 3;
1256 struct arizona_micd_config *micd_configs;
1257 int nconfs, ret;
1258 int i, j;
1259 u32 *vals;
1260
1261 nconfs = device_property_read_u32_array(arizona->dev, prop, NULL, 0);
1262 if (nconfs <= 0)
1263 return 0;
1264
1265 vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
1266 if (!vals)
1267 return -ENOMEM;
1268
1269 ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
1270 if (ret < 0)
1271 goto out;
1272
1273 nconfs /= entries_per_config;
1274
1275 micd_configs = devm_kzalloc(dev,
1276 nconfs * sizeof(struct arizona_micd_range),
1277 GFP_KERNEL);
1278 if (!micd_configs) {
1279 ret = -ENOMEM;
1280 goto out;
1281 }
1282
1283 for (i = 0, j = 0; i < nconfs; ++i) {
1284 micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
1285 micd_configs[i].bias = vals[j++];
1286 micd_configs[i].gpio = vals[j++];
1287 }
1288
1289 arizona->pdata.micd_configs = micd_configs;
1290 arizona->pdata.num_micd_configs = nconfs;
1291
1292out:
1293 kfree(vals);
1294 return ret;
1295}
1296
1297static int arizona_extcon_device_get_pdata(struct device *dev,
1298 struct arizona *arizona)
Inha Song9e86b2a2015-05-04 13:42:13 +09001299{
1300 struct arizona_pdata *pdata = &arizona->pdata;
1301 unsigned int val = ARIZONA_ACCDET_MODE_HPL;
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001302 int ret;
Inha Song9e86b2a2015-05-04 13:42:13 +09001303
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001304 device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
Inha Song9e86b2a2015-05-04 13:42:13 +09001305 switch (val) {
1306 case ARIZONA_ACCDET_MODE_HPL:
1307 case ARIZONA_ACCDET_MODE_HPR:
1308 pdata->hpdet_channel = val;
1309 break;
1310 default:
1311 dev_err(arizona->dev,
1312 "Wrong wlf,hpdet-channel DT value %d\n", val);
1313 pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
1314 }
1315
Charles Keepax4778d442015-06-19 17:23:30 +01001316 device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
1317 &pdata->micd_detect_debounce);
1318
1319 device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
1320 &pdata->micd_bias_start_time);
1321
1322 device_property_read_u32(arizona->dev, "wlf,micd-rate",
1323 &pdata->micd_rate);
1324
1325 device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
1326 &pdata->micd_dbtime);
1327
Charles Keepax7a7ef0f2015-11-23 14:51:30 +00001328 device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
Charles Keepax4778d442015-06-19 17:23:30 +01001329 &pdata->micd_timeout);
1330
1331 pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
1332 "wlf,micd-force-micbias");
1333
Charles Keepax2e87b7a2015-11-19 15:45:35 +00001334 pdata->micd_software_compare = device_property_read_bool(arizona->dev,
1335 "wlf,micd-software-compare");
1336
Charles Keepax3d7a8722015-11-19 15:45:37 +00001337 pdata->jd_invert = device_property_read_bool(arizona->dev,
1338 "wlf,jd-invert");
1339
Charles Keepax99374222015-11-19 15:45:36 +00001340 device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
1341
Charles Keepax35247c12015-11-19 15:45:38 +00001342 pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001343 "wlf,use-jd2");
Charles Keepax35247c12015-11-19 15:45:38 +00001344 pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001345 "wlf,use-jd2-nopull");
Charles Keepax35247c12015-11-19 15:45:38 +00001346
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001347 ret = arizona_extcon_get_micd_configs(dev, arizona);
1348 if (ret < 0)
1349 dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
1350
Inha Song9e86b2a2015-05-04 13:42:13 +09001351 return 0;
1352}
1353
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001354static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001355{
1356 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001357 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001358 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001359 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001360 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001361 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001362 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001363
Mark Brownbbbd46e2013-01-10 19:38:43 +00001364 if (!arizona->dapm || !arizona->dapm->card)
1365 return -EPROBE_DEFER;
1366
Mark Brownf2c32a82012-06-24 12:09:45 +01001367 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001368 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001369 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001370
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001371 if (!dev_get_platdata(arizona->dev))
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001372 arizona_extcon_device_get_pdata(&pdev->dev, arizona);
Inha Song9e86b2a2015-05-04 13:42:13 +09001373
Charles Keepax17271f62014-07-18 12:59:00 +01001374 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001375 if (IS_ERR(info->micvdd)) {
1376 ret = PTR_ERR(info->micvdd);
1377 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001378 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001379 }
1380
1381 mutex_init(&info->lock);
1382 info->arizona = arizona;
1383 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001384 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001385 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001386 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001387 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001388 platform_set_drvdata(pdev, info);
1389
1390 switch (arizona->type) {
1391 case WM5102:
1392 switch (arizona->rev) {
1393 case 0:
1394 info->micd_reva = true;
1395 break;
1396 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001397 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001398 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001399 break;
1400 }
1401 break;
Charles Keepax77438612013-11-14 16:18:25 +00001402 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001403 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001404 switch (arizona->rev) {
1405 case 0 ... 2:
1406 break;
1407 default:
1408 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001409 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001410 break;
1411 }
1412 break;
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +01001413 case WM8998:
1414 case WM1814:
1415 info->micd_clamp = true;
1416 info->hpdet_ip_version = 2;
1417 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001418 default:
1419 break;
1420 }
1421
Chanwoo Choief70a212014-04-21 20:47:31 +09001422 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1423 if (IS_ERR(info->edev)) {
1424 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1425 return -ENOMEM;
1426 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001427
Chanwoo Choief70a212014-04-21 20:47:31 +09001428 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001429 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001430 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001431 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001432 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001433 }
1434
Mark Brown6fed4d82013-04-01 22:03:06 +01001435 info->input = devm_input_allocate_device(&pdev->dev);
1436 if (!info->input) {
1437 dev_err(arizona->dev, "Can't allocate input dev\n");
1438 ret = -ENOMEM;
1439 goto err_register;
1440 }
1441
1442 info->input->name = "Headset";
1443 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001444
Mark Brownf2c32a82012-06-24 12:09:45 +01001445 if (pdata->num_micd_configs) {
1446 info->micd_modes = pdata->micd_configs;
1447 info->micd_num_modes = pdata->num_micd_configs;
1448 } else {
1449 info->micd_modes = micd_default_modes;
1450 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1451 }
1452
Charles Keepax6772a5a2015-09-16 10:42:17 +01001453 if (arizona->pdata.gpsw > 0)
1454 regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
1455 ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
1456
Charles Keepax6c467a12016-11-25 13:44:36 +00001457 if (pdata->micd_pol_gpio > 0) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001458 if (info->micd_modes[0].gpio)
1459 mode = GPIOF_OUT_INIT_HIGH;
1460 else
1461 mode = GPIOF_OUT_INIT_LOW;
1462
Charles Keepax6c467a12016-11-25 13:44:36 +00001463 ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio,
1464 mode, "MICD polarity");
Mark Brownf2c32a82012-06-24 12:09:45 +01001465 if (ret != 0) {
1466 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
Charles Keepax6c467a12016-11-25 13:44:36 +00001467 pdata->micd_pol_gpio, ret);
Mark Brownf2c32a82012-06-24 12:09:45 +01001468 goto err_register;
1469 }
Charles Keepax6c467a12016-11-25 13:44:36 +00001470
1471 info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001472 } else {
1473 if (info->micd_modes[0].gpio)
1474 mode = GPIOD_OUT_HIGH;
1475 else
1476 mode = GPIOD_OUT_LOW;
1477
1478 /* We can't use devm here because we need to do the get
1479 * against the MFD device, as that is where the of_node
1480 * will reside, but if we devm against that the GPIO
1481 * will not be freed if the extcon driver is unloaded.
1482 */
1483 info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
1484 "wlf,micd-pol",
1485 GPIOD_OUT_LOW);
1486 if (IS_ERR(info->micd_pol_gpio)) {
1487 ret = PTR_ERR(info->micd_pol_gpio);
1488 dev_err(arizona->dev,
1489 "Failed to get microphone polarity GPIO: %d\n",
1490 ret);
1491 goto err_register;
1492 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001493 }
1494
Mark Brown1eda6aa2013-01-11 08:55:54 +09001495 if (arizona->pdata.hpdet_id_gpio > 0) {
1496 ret = devm_gpio_request_one(&pdev->dev,
1497 arizona->pdata.hpdet_id_gpio,
1498 GPIOF_OUT_INIT_LOW,
1499 "HPDET");
1500 if (ret != 0) {
1501 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1502 arizona->pdata.hpdet_id_gpio, ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001503 goto err_gpio;
Mark Brown1eda6aa2013-01-11 08:55:54 +09001504 }
1505 }
1506
Mark Brownb17e5462013-01-11 08:55:24 +09001507 if (arizona->pdata.micd_bias_start_time)
1508 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1509 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1510 arizona->pdata.micd_bias_start_time
1511 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1512
Mark Brown2e033db2013-01-21 17:36:33 +09001513 if (arizona->pdata.micd_rate)
1514 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1515 ARIZONA_MICD_RATE_MASK,
1516 arizona->pdata.micd_rate
1517 << ARIZONA_MICD_RATE_SHIFT);
1518
Charles Keepaxbb327e92015-06-30 13:32:39 +01001519 switch (arizona->pdata.micd_dbtime) {
1520 case MICD_DBTIME_FOUR_READINGS:
Mark Brown2e033db2013-01-21 17:36:33 +09001521 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1522 ARIZONA_MICD_DBTIME_MASK,
Charles Keepaxbb327e92015-06-30 13:32:39 +01001523 ARIZONA_MICD_DBTIME);
1524 break;
1525 case MICD_DBTIME_TWO_READINGS:
1526 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1527 ARIZONA_MICD_DBTIME_MASK, 0);
1528 break;
1529 default:
1530 break;
1531 }
Mark Brown2e033db2013-01-21 17:36:33 +09001532
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001533 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) <
1534 ARIZONA_NUM_MICD_BUTTON_LEVELS);
Mark Brown6fed4d82013-04-01 22:03:06 +01001535
1536 if (arizona->pdata.num_micd_ranges) {
1537 info->micd_ranges = pdata->micd_ranges;
1538 info->num_micd_ranges = pdata->num_micd_ranges;
1539 } else {
1540 info->micd_ranges = micd_default_ranges;
1541 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1542 }
1543
1544 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1545 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1546 arizona->pdata.num_micd_ranges);
1547 }
1548
1549 if (info->num_micd_ranges > 1) {
1550 for (i = 1; i < info->num_micd_ranges; i++) {
1551 if (info->micd_ranges[i - 1].max >
1552 info->micd_ranges[i].max) {
1553 dev_err(arizona->dev,
1554 "MICD ranges must be sorted\n");
1555 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001556 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001557 }
1558 }
1559 }
1560
1561 /* Disable all buttons by default */
1562 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1563 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1564
1565 /* Set up all the buttons the user specified */
1566 for (i = 0; i < info->num_micd_ranges; i++) {
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001567 for (j = 0; j < ARIZONA_NUM_MICD_BUTTON_LEVELS; j++)
Mark Brown6fed4d82013-04-01 22:03:06 +01001568 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1569 break;
1570
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001571 if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
Mark Brown6fed4d82013-04-01 22:03:06 +01001572 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1573 info->micd_ranges[i].max);
1574 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001575 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001576 }
1577
1578 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1579 arizona_micd_levels[j], i);
1580
1581 arizona_micd_set_level(arizona, i, j);
1582 input_set_capability(info->input, EV_KEY,
1583 info->micd_ranges[i].key);
1584
1585 /* Enable reporting of that range */
1586 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1587 1 << i, 1 << i);
1588 }
1589
1590 /* Set all the remaining keys to a maximum */
1591 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1592 arizona_micd_set_level(arizona, i, 0x3f);
1593
Mark Browndab63eb2013-01-11 08:55:36 +09001594 /*
Mark Brown92a49872013-01-11 08:55:39 +09001595 * If we have a clamp use it, activating in conjunction with
1596 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001597 */
1598 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001599 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001600 /* Put the GPIO into input mode with optional pull */
1601 val = 0xc101;
1602 if (arizona->pdata.jd_gpio5_nopull)
1603 val &= ~ARIZONA_GPN_PU;
1604
Mark Brown92a49872013-01-11 08:55:39 +09001605 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001606 val);
Mark Brown92a49872013-01-11 08:55:39 +09001607
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001608 if (arizona->pdata.jd_invert)
1609 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1610 else
1611 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001612 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001613 if (arizona->pdata.jd_invert)
1614 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1615 else
1616 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001617 }
1618
Mark Browndab63eb2013-01-11 08:55:36 +09001619 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001620 ARIZONA_MICD_CLAMP_CONTROL,
1621 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1622
1623 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001624 ARIZONA_JACK_DETECT_DEBOUNCE,
1625 ARIZONA_MICD_CLAMP_DB,
1626 ARIZONA_MICD_CLAMP_DB);
1627 }
1628
Mark Brownf2c32a82012-06-24 12:09:45 +01001629 arizona_extcon_set_mode(info, 0);
1630
1631 pm_runtime_enable(&pdev->dev);
1632 pm_runtime_idle(&pdev->dev);
1633 pm_runtime_get_sync(&pdev->dev);
1634
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001635 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001636 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1637 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1638 } else {
1639 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1640 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1641 }
1642
1643 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001644 "JACKDET rise", arizona_jackdet, info);
1645 if (ret != 0) {
1646 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1647 ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001648 goto err_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +01001649 }
1650
Mark Brown92a49872013-01-11 08:55:39 +09001651 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001652 if (ret != 0) {
1653 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1654 ret);
1655 goto err_rise;
1656 }
1657
Mark Brown92a49872013-01-11 08:55:39 +09001658 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001659 "JACKDET fall", arizona_jackdet, info);
1660 if (ret != 0) {
1661 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1662 goto err_rise_wake;
1663 }
1664
Mark Brown92a49872013-01-11 08:55:39 +09001665 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001666 if (ret != 0) {
1667 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1668 ret);
1669 goto err_fall;
1670 }
1671
1672 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1673 "MICDET", arizona_micdet, info);
1674 if (ret != 0) {
1675 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1676 goto err_fall_wake;
1677 }
1678
Mark Brown4f340332013-01-11 08:55:43 +09001679 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1680 "HPDET", arizona_hpdet_irq, info);
1681 if (ret != 0) {
1682 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1683 goto err_micdet;
1684 }
1685
Mark Brownf2c32a82012-06-24 12:09:45 +01001686 arizona_clk32k_enable(arizona);
1687 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1688 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1689 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1690 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1691
Mark Brownb8575a12012-09-07 17:01:15 +08001692 ret = regulator_allow_bypass(info->micvdd, true);
1693 if (ret != 0)
1694 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1695 ret);
1696
Mark Brownf2c32a82012-06-24 12:09:45 +01001697 pm_runtime_put(&pdev->dev);
1698
Mark Brown34efe4d2012-07-20 17:07:29 +01001699 ret = input_register_device(info->input);
1700 if (ret) {
1701 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001702 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001703 }
1704
Mark Brownf2c32a82012-06-24 12:09:45 +01001705 return 0;
1706
Mark Brown4f340332013-01-11 08:55:43 +09001707err_hpdet:
1708 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001709err_micdet:
1710 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001711err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001712 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001713err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001714 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001715err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001716 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001717err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001718 arizona_free_irq(arizona, jack_irq_rise, info);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001719err_gpio:
1720 gpiod_put(info->micd_pol_gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +01001721err_register:
1722 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001723 return ret;
1724}
1725
Bill Pemberton93ed0322012-11-19 13:25:49 -05001726static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001727{
1728 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1729 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001730 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001731
Charles Keepax8e5838d2015-06-19 17:23:31 +01001732 gpiod_put(info->micd_pol_gpio);
1733
Mark Brownf2c32a82012-06-24 12:09:45 +01001734 pm_runtime_disable(&pdev->dev);
1735
Mark Browndab63eb2013-01-11 08:55:36 +09001736 regmap_update_bits(arizona->regmap,
1737 ARIZONA_MICD_CLAMP_CONTROL,
1738 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1739
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001740 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001741 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1742 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1743 } else {
1744 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1745 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1746 }
1747
1748 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1749 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1750 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001751 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001752 arizona_free_irq(arizona, jack_irq_rise, info);
1753 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001754 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001755 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1756 ARIZONA_JD1_ENA, 0);
1757 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001758
1759 return 0;
1760}
1761
1762static struct platform_driver arizona_extcon_driver = {
1763 .driver = {
1764 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001765 },
1766 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001767 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001768};
1769
1770module_platform_driver(arizona_extcon_driver);
1771
1772MODULE_DESCRIPTION("Arizona Extcon driver");
1773MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1774MODULE_LICENSE("GPL");
1775MODULE_ALIAS("platform:extcon-arizona");