blob: bb6434726c7a945c0e96c2edbd10e505e25eca85 [file] [log] [blame]
Thomas Gleixnerc942fdd2019-05-27 08:55:06 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Mark Brownf2c32a82012-06-24 12:09:45 +01002/*
3 * extcon-arizona.c - Extcon driver Wolfson Arizona devices
4 *
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +01005 * Copyright (C) 2012-2014 Wolfson Microelectronics plc
Mark Brownf2c32a82012-06-24 12:09:45 +01006 */
7
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <linux/i2c.h>
11#include <linux/slab.h>
12#include <linux/interrupt.h>
13#include <linux/err.h>
Charles Keepax8e5838d2015-06-19 17:23:31 +010014#include <linux/gpio/consumer.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010015#include <linux/gpio.h>
Mark Brown34efe4d2012-07-20 17:07:29 +010016#include <linux/input.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010017#include <linux/platform_device.h>
18#include <linux/pm_runtime.h>
Charles Keepaxfeffb0c2015-06-19 17:23:29 +010019#include <linux/property.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010020#include <linux/regulator/consumer.h>
Chanwoo Choi176aa362017-09-21 12:11:24 +090021#include <linux/extcon-provider.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010022
Mark Brownbbbd46e2013-01-10 19:38:43 +000023#include <sound/soc.h>
24
Mark Brownf2c32a82012-06-24 12:09:45 +010025#include <linux/mfd/arizona/core.h>
26#include <linux/mfd/arizona/pdata.h>
27#include <linux/mfd/arizona/registers.h>
Inha Song9e86b2a2015-05-04 13:42:13 +090028#include <dt-bindings/mfd/arizona.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010029
Mark Brown6fed4d82013-04-01 22:03:06 +010030#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010031
Richard Fitzgeralda288d642014-05-23 12:54:57 +010032#define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
33#define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
34#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
35#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
36
Charles Keepaxf719ae32015-09-16 10:42:18 +010037#define ARIZONA_TST_CAP_DEFAULT 0x3
38#define ARIZONA_TST_CAP_CLAMP 0x1
39
Mark Brown9dd5e532013-04-01 19:09:45 +010040#define ARIZONA_HPDET_MAX 10000
41
Mark Brown2643fd62013-04-01 19:07:28 +010042#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010043#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010044
Charles Keepaxe57bb432017-01-25 09:34:06 +000045#define ARIZONA_HPDET_WAIT_COUNT 15
46#define ARIZONA_HPDET_WAIT_DELAY_MS 20
47
Charles Keepaxdf8b6772015-09-16 10:42:16 +010048#define QUICK_HEADPHONE_MAX_OHM 3
49#define MICROPHONE_MIN_OHM 1257
50#define MICROPHONE_MAX_OHM 30000
51
Charles Keepaxbb327e92015-06-30 13:32:39 +010052#define MICD_DBTIME_TWO_READINGS 2
53#define MICD_DBTIME_FOUR_READINGS 4
54
Charles Keepaxffae24f2013-11-14 16:18:21 +000055#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
56 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
57 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
58 ARIZONA_MICD_LVL_7)
59
60#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
61
62#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
63
Mark Brownf2c32a82012-06-24 12:09:45 +010064struct arizona_extcon_info {
65 struct device *dev;
66 struct arizona *arizona;
67 struct mutex lock;
68 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010069 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010070
Mark Browna3e20782013-04-01 19:05:27 +010071 u16 last_jackdet;
72
Mark Brownf2c32a82012-06-24 12:09:45 +010073 int micd_mode;
74 const struct arizona_micd_config *micd_modes;
75 int micd_num_modes;
76
Mark Brown6fed4d82013-04-01 22:03:06 +010077 const struct arizona_micd_range *micd_ranges;
78 int num_micd_ranges;
79
Mark Brown7abd4e22013-04-01 19:25:55 +010080 int micd_timeout;
81
Mark Brownf2c32a82012-06-24 12:09:45 +010082 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090083 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010084
Mark Brown0e27bd32013-02-05 21:00:15 +000085 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010086 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010087 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000088
Mark Brown4f340332013-01-11 08:55:43 +090089 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000090 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010091 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090092
Mark Browndd235ee2013-01-11 08:55:51 +090093 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090094 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090095
Mark Brownf2c32a82012-06-24 12:09:45 +010096 bool mic;
97 bool detecting;
98 int jack_flips;
99
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100100 int hpdet_ip_version;
Mark Brown4f340332013-01-11 08:55:43 +0900101
Chanwoo Choief70a212014-04-21 20:47:31 +0900102 struct extcon_dev *edev;
Charles Keepax8e5838d2015-06-19 17:23:31 +0100103
104 struct gpio_desc *micd_pol_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +0100105};
106
107static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +0100108 { ARIZONA_ACCDET_SRC, 1, 0 },
109 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100110};
111
Mark Brown6fed4d82013-04-01 22:03:06 +0100112static const struct arizona_micd_range micd_default_ranges[] = {
113 { .max = 11, .key = BTN_0 },
114 { .max = 28, .key = BTN_1 },
115 { .max = 54, .key = BTN_2 },
116 { .max = 100, .key = BTN_3 },
117 { .max = 186, .key = BTN_4 },
118 { .max = 430, .key = BTN_5 },
119};
120
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100121/* The number of levels in arizona_micd_levels valid for button thresholds */
122#define ARIZONA_NUM_MICD_BUTTON_LEVELS 64
123
Mark Brown6fed4d82013-04-01 22:03:06 +0100124static const int arizona_micd_levels[] = {
125 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
126 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
127 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
128 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100129 1257, 30000,
Mark Brown34efe4d2012-07-20 17:07:29 +0100130};
131
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900132static const unsigned int arizona_cable[] = {
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900133 EXTCON_MECHANICAL,
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900134 EXTCON_JACK_MICROPHONE,
135 EXTCON_JACK_HEADPHONE,
136 EXTCON_JACK_LINE_OUT,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900137 EXTCON_NONE,
Mark Brownf2c32a82012-06-24 12:09:45 +0100138};
139
Mark Brown9dd5e532013-04-01 19:09:45 +0100140static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
141
Charles Keepax112bdfa2015-02-16 15:41:02 +0000142static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
143 bool clamp)
Mark Brown03409072013-02-12 13:00:31 +0000144{
145 struct arizona *arizona = info->arizona;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000146 unsigned int mask = 0, val = 0;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100147 unsigned int cap_sel = 0;
Mark Brown03409072013-02-12 13:00:31 +0000148 int ret;
149
Charles Keepax43f0acd2015-02-16 15:41:03 +0000150 switch (arizona->type) {
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100151 case WM8998:
152 case WM1814:
153 mask = 0;
154 break;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000155 case WM5110:
Charles Keepax2b51f9c2015-04-30 23:43:37 +0900156 case WM8280:
Charles Keepax43f0acd2015-02-16 15:41:03 +0000157 mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
158 ARIZONA_HP1L_SHRTI;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100159 if (clamp) {
Charles Keepax43f0acd2015-02-16 15:41:03 +0000160 val = ARIZONA_HP1L_SHRTO;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100161 cap_sel = ARIZONA_TST_CAP_CLAMP;
162 } else {
Charles Keepax43f0acd2015-02-16 15:41:03 +0000163 val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100164 cap_sel = ARIZONA_TST_CAP_DEFAULT;
165 }
166
167 ret = regmap_update_bits(arizona->regmap,
168 ARIZONA_HP_TEST_CTRL_1,
169 ARIZONA_HP1_TST_CAP_SEL_MASK,
170 cap_sel);
171 if (ret != 0)
172 dev_warn(arizona->dev,
173 "Failed to set TST_CAP_SEL: %d\n", ret);
Charles Keepax43f0acd2015-02-16 15:41:03 +0000174 break;
175 default:
176 mask = ARIZONA_RMV_SHRT_HP1L;
177 if (clamp)
178 val = ARIZONA_RMV_SHRT_HP1L;
179 break;
Charles Keepaxc19dc202016-07-19 13:23:56 +0100180 }
Charles Keepax112bdfa2015-02-16 15:41:02 +0000181
Charles Keepax03bf1ad2015-12-29 16:32:03 +0000182 snd_soc_dapm_mutex_lock(arizona->dapm);
Mark Brown03409072013-02-12 13:00:31 +0000183
Charles Keepax112bdfa2015-02-16 15:41:02 +0000184 arizona->hpdet_clamp = clamp;
Mark Browndf8c3db2013-02-22 18:38:03 +0000185
Charles Keepax112bdfa2015-02-16 15:41:02 +0000186 /* Keep the HP output stages disabled while doing the clamp */
187 if (clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000188 ret = regmap_update_bits(arizona->regmap,
189 ARIZONA_OUTPUT_ENABLES_1,
190 ARIZONA_OUT1L_ENA |
191 ARIZONA_OUT1R_ENA, 0);
192 if (ret != 0)
193 dev_warn(arizona->dev,
194 "Failed to disable headphone outputs: %d\n",
195 ret);
Mark Brown03409072013-02-12 13:00:31 +0000196 }
197
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100198 if (mask) {
199 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
200 mask, val);
201 if (ret != 0)
202 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000203 ret);
204
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100205 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
206 mask, val);
207 if (ret != 0)
208 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
209 ret);
210 }
Mark Browndf8c3db2013-02-22 18:38:03 +0000211
Charles Keepax112bdfa2015-02-16 15:41:02 +0000212 /* Restore the desired state while not doing the clamp */
213 if (!clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000214 ret = regmap_update_bits(arizona->regmap,
215 ARIZONA_OUTPUT_ENABLES_1,
216 ARIZONA_OUT1L_ENA |
217 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000218 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000219 dev_warn(arizona->dev,
220 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000221 ret);
222 }
223
Charles Keepax03bf1ad2015-12-29 16:32:03 +0000224 snd_soc_dapm_mutex_unlock(arizona->dapm);
Mark Brown03409072013-02-12 13:00:31 +0000225}
226
Mark Brownf2c32a82012-06-24 12:09:45 +0100227static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
228{
229 struct arizona *arizona = info->arizona;
230
Mark Brown6fed4d82013-04-01 22:03:06 +0100231 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800232
Charles Keepax6c467a12016-11-25 13:44:36 +0000233 gpiod_set_value_cansleep(info->micd_pol_gpio,
234 info->micd_modes[mode].gpio);
Charles Keepax8e5838d2015-06-19 17:23:31 +0100235
Mark Brownf2c32a82012-06-24 12:09:45 +0100236 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
237 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100238 info->micd_modes[mode].bias <<
239 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100240 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
241 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
242
243 info->micd_mode = mode;
244
245 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
246}
247
Mark Brownbbbd46e2013-01-10 19:38:43 +0000248static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
249{
Charles Keepax41024242013-09-23 14:33:59 +0100250 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000251 case 1:
252 return "MICBIAS1";
253 case 2:
254 return "MICBIAS2";
255 case 3:
256 return "MICBIAS3";
257 default:
258 return "MICVDD";
259 }
260}
261
262static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
263{
264 struct arizona *arizona = info->arizona;
265 const char *widget = arizona_extcon_get_micbias(info);
266 struct snd_soc_dapm_context *dapm = arizona->dapm;
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000267 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000268 int ret;
269
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000270 ret = snd_soc_component_force_enable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000271 if (ret != 0)
272 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
273 widget, ret);
274
Mark Brownbbbd46e2013-01-10 19:38:43 +0000275 snd_soc_dapm_sync(dapm);
276
277 if (!arizona->pdata.micd_force_micbias) {
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000278 ret = snd_soc_component_disable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000279 if (ret != 0)
280 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
281 widget, ret);
282
Mark Brownbbbd46e2013-01-10 19:38:43 +0000283 snd_soc_dapm_sync(dapm);
284 }
285}
286
Mark Brown9b1270c2013-01-11 08:55:46 +0900287static void arizona_start_mic(struct arizona_extcon_info *info)
288{
289 struct arizona *arizona = info->arizona;
290 bool change;
291 int ret;
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100292 unsigned int mode;
Mark Brown9b1270c2013-01-11 08:55:46 +0900293
Mark Brown9b1270c2013-01-11 08:55:46 +0900294 /* Microphone detection can't use idle mode */
295 pm_runtime_get(info->dev);
296
Mark Brownbbbd46e2013-01-10 19:38:43 +0000297 if (info->detecting) {
298 ret = regulator_allow_bypass(info->micvdd, false);
299 if (ret != 0) {
300 dev_err(arizona->dev,
301 "Failed to regulate MICVDD: %d\n",
302 ret);
303 }
304 }
305
Mark Brown9b1270c2013-01-11 08:55:46 +0900306 ret = regulator_enable(info->micvdd);
307 if (ret != 0) {
308 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
309 ret);
310 }
311
312 if (info->micd_reva) {
313 regmap_write(arizona->regmap, 0x80, 0x3);
314 regmap_write(arizona->regmap, 0x294, 0);
315 regmap_write(arizona->regmap, 0x80, 0x0);
316 }
317
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100318 if (info->detecting && arizona->pdata.micd_software_compare)
319 mode = ARIZONA_ACCDET_MODE_ADC;
320 else
321 mode = ARIZONA_ACCDET_MODE_MIC;
322
Mark Brown9b1270c2013-01-11 08:55:46 +0900323 regmap_update_bits(arizona->regmap,
324 ARIZONA_ACCESSORY_DETECT_MODE_1,
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100325 ARIZONA_ACCDET_MODE_MASK, mode);
Mark Brown9b1270c2013-01-11 08:55:46 +0900326
Mark Brownbbbd46e2013-01-10 19:38:43 +0000327 arizona_extcon_pulse_micbias(info);
328
Mark Brown9b1270c2013-01-11 08:55:46 +0900329 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
330 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
331 &change);
332 if (!change) {
333 regulator_disable(info->micvdd);
334 pm_runtime_put_autosuspend(info->dev);
335 }
336}
337
338static void arizona_stop_mic(struct arizona_extcon_info *info)
339{
340 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000341 const char *widget = arizona_extcon_get_micbias(info);
342 struct snd_soc_dapm_context *dapm = arizona->dapm;
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000343 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
Mark Brown9b1270c2013-01-11 08:55:46 +0900344 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000345 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900346
347 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
348 ARIZONA_MICD_ENA, 0,
349 &change);
350
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000351 ret = snd_soc_component_disable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000352 if (ret != 0)
353 dev_warn(arizona->dev,
354 "Failed to disable %s: %d\n",
355 widget, ret);
356
Mark Brownbbbd46e2013-01-10 19:38:43 +0000357 snd_soc_dapm_sync(dapm);
358
Mark Brown9b1270c2013-01-11 08:55:46 +0900359 if (info->micd_reva) {
360 regmap_write(arizona->regmap, 0x80, 0x3);
361 regmap_write(arizona->regmap, 0x294, 2);
362 regmap_write(arizona->regmap, 0x80, 0x0);
363 }
364
Mark Brownbbbd46e2013-01-10 19:38:43 +0000365 ret = regulator_allow_bypass(info->micvdd, true);
366 if (ret != 0) {
367 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
368 ret);
369 }
370
Mark Brown9b1270c2013-01-11 08:55:46 +0900371 if (change) {
372 regulator_disable(info->micvdd);
373 pm_runtime_mark_last_busy(info->dev);
374 pm_runtime_put_autosuspend(info->dev);
375 }
376}
377
Mark Brown4f340332013-01-11 08:55:43 +0900378static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100379 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900380 unsigned int factor_a;
381 unsigned int factor_b;
382} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100383 { 100, 5528, 362464 },
384 { 169, 11084, 6186851 },
385 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900386};
387
Charles Keepax24a279b2014-05-30 13:19:17 +0100388#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
389
Mark Brown4f340332013-01-11 08:55:43 +0900390static struct {
391 int min;
392 int max;
393} arizona_hpdet_c_ranges[] = {
394 { 0, 30 },
395 { 8, 100 },
396 { 100, 1000 },
397 { 1000, 10000 },
398};
399
400static int arizona_hpdet_read(struct arizona_extcon_info *info)
401{
402 struct arizona *arizona = info->arizona;
403 unsigned int val, range;
404 int ret;
405
406 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
407 if (ret != 0) {
408 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
409 ret);
410 return ret;
411 }
412
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100413 switch (info->hpdet_ip_version) {
Mark Brown4f340332013-01-11 08:55:43 +0900414 case 0:
415 if (!(val & ARIZONA_HP_DONE)) {
416 dev_err(arizona->dev, "HPDET did not complete: %x\n",
417 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900418 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900419 }
420
421 val &= ARIZONA_HP_LVL_MASK;
422 break;
423
424 case 1:
425 if (!(val & ARIZONA_HP_DONE_B)) {
426 dev_err(arizona->dev, "HPDET did not complete: %x\n",
427 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900428 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900429 }
430
431 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
432 if (ret != 0) {
433 dev_err(arizona->dev, "Failed to read HP value: %d\n",
434 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900435 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900436 }
437
438 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
439 &range);
440 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
441 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
442
443 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100444 (val < arizona_hpdet_b_ranges[range].threshold ||
445 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900446 range++;
447 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
448 range);
449 regmap_update_bits(arizona->regmap,
450 ARIZONA_HEADPHONE_DETECT_1,
451 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
452 range <<
453 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
454 return -EAGAIN;
455 }
456
457 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100458 if (val < arizona_hpdet_b_ranges[range].threshold ||
459 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900460 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100461 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900462 }
463
464 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
465 val, range);
466
467 val = arizona_hpdet_b_ranges[range].factor_b
468 / ((val * 100) -
469 arizona_hpdet_b_ranges[range].factor_a);
470 break;
471
Mark Brown4f340332013-01-11 08:55:43 +0900472 case 2:
473 if (!(val & ARIZONA_HP_DONE_B)) {
474 dev_err(arizona->dev, "HPDET did not complete: %x\n",
475 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900476 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900477 }
478
479 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000480 /* Convert to ohms, the value is in 0.5 ohm increments */
481 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900482
483 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
484 &range);
485 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
486 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
487
Charles Keepax91414612013-11-14 16:18:24 +0000488 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900489 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
490 (val >= arizona_hpdet_c_ranges[range].max)) {
491 range++;
492 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
493 arizona_hpdet_c_ranges[range].min,
494 arizona_hpdet_c_ranges[range].max);
495 regmap_update_bits(arizona->regmap,
496 ARIZONA_HEADPHONE_DETECT_1,
497 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
498 range <<
499 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
500 return -EAGAIN;
501 }
Charles Keepax91414612013-11-14 16:18:24 +0000502
503 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
504 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
505 arizona_hpdet_c_ranges[range].min);
506 val = arizona_hpdet_c_ranges[range].min;
507 }
Chanwoo Choie9844b2c2015-09-29 19:06:31 +0900508 break;
509
510 default:
511 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
512 info->hpdet_ip_version);
513 return -EINVAL;
Mark Brown4f340332013-01-11 08:55:43 +0900514 }
515
516 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
517 return val;
518}
519
Mark Brown9c2ba272013-02-25 23:42:31 +0000520static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
521 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900522{
523 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900524 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900525
526 /*
527 * If we're using HPDET for accessory identification we need
528 * to take multiple measurements, step through them in sequence.
529 */
530 if (arizona->pdata.hpdet_acc_id) {
531 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900532
533 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000534 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900535 dev_dbg(arizona->dev, "Measuring mic\n");
536
537 regmap_update_bits(arizona->regmap,
538 ARIZONA_ACCESSORY_DETECT_MODE_1,
539 ARIZONA_ACCDET_MODE_MASK |
540 ARIZONA_ACCDET_SRC,
541 ARIZONA_ACCDET_MODE_HPR |
542 info->micd_modes[0].src);
543
544 gpio_set_value_cansleep(id_gpio, 1);
545
Mark Browndd235ee2013-01-11 08:55:51 +0900546 regmap_update_bits(arizona->regmap,
547 ARIZONA_HEADPHONE_DETECT_1,
548 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
549 return -EAGAIN;
550 }
551
552 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000553 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
554 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000555
556 /* Take the headphone impedance for the main report */
557 *reading = info->hpdet_res[0];
558
Mark Brown9dd5e532013-04-01 19:09:45 +0100559 /* Sometimes we get false readings due to slow insert */
560 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
561 dev_dbg(arizona->dev, "Retrying high impedance\n");
562 info->num_hpdet_res = 0;
563 info->hpdet_retried = true;
564 arizona_start_hpdet_acc_id(info);
565 pm_runtime_put(info->dev);
566 return -EAGAIN;
567 }
568
Mark Brown1eda6aa2013-01-11 08:55:54 +0900569 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530570 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900571 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000572 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900573 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000574 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000575 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900576 } else {
577 dev_dbg(arizona->dev, "Detected headphone\n");
578 }
579
580 /* Make sure everything is reset back to the real polarity */
581 regmap_update_bits(arizona->regmap,
582 ARIZONA_ACCESSORY_DETECT_MODE_1,
583 ARIZONA_ACCDET_SRC,
584 info->micd_modes[0].src);
585 }
586
587 return 0;
588}
589
Mark Brown4f340332013-01-11 08:55:43 +0900590static irqreturn_t arizona_hpdet_irq(int irq, void *data)
591{
592 struct arizona_extcon_info *info = data;
593 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900594 int id_gpio = arizona->pdata.hpdet_id_gpio;
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900595 unsigned int report = EXTCON_JACK_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900596 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000597 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900598
599 mutex_lock(&info->lock);
600
601 /* If we got a spurious IRQ for some reason then ignore it */
602 if (!info->hpdet_active) {
603 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
604 mutex_unlock(&info->lock);
605 return IRQ_NONE;
606 }
607
608 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900609 ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900610 if (ret < 0) {
611 dev_err(arizona->dev, "Failed to check cable state: %d\n",
612 ret);
613 goto out;
614 } else if (!ret) {
615 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
616 goto done;
617 }
618
619 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900620 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900621 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900622 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900623 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900624 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900625
626 /* Reset back to starting range */
627 regmap_update_bits(arizona->regmap,
628 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900629 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
630 0);
631
Mark Brown9c2ba272013-02-25 23:42:31 +0000632 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900633 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900634 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900635 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900636 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900637
638 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900639 if (reading >= 5000)
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900640 report = EXTCON_JACK_LINE_OUT;
Mark Brown4f340332013-01-11 08:55:43 +0900641 else
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900642 report = EXTCON_JACK_HEADPHONE;
Mark Brown4f340332013-01-11 08:55:43 +0900643
Chanwoo Choi8670b452016-08-16 15:55:34 +0900644 ret = extcon_set_state_sync(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900645 if (ret != 0)
646 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
647 ret);
648
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000649done:
650 /* Reset back to starting range */
651 regmap_update_bits(arizona->regmap,
652 ARIZONA_HEADPHONE_DETECT_1,
653 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
654 0);
655
Charles Keepax112bdfa2015-02-16 15:41:02 +0000656 arizona_extcon_hp_clamp(info, false);
Mark Brown4f340332013-01-11 08:55:43 +0900657
Mark Brown1eda6aa2013-01-11 08:55:54 +0900658 if (id_gpio)
659 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900660
661 /* Revert back to MICDET mode */
662 regmap_update_bits(arizona->regmap,
663 ARIZONA_ACCESSORY_DETECT_MODE_1,
664 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
665
666 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000667 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900668 arizona_start_mic(info);
669
670 if (info->hpdet_active) {
671 pm_runtime_put_autosuspend(info->dev);
672 info->hpdet_active = false;
673 }
674
Mark Brownbf14ee52013-02-05 20:20:17 +0000675 info->hpdet_done = true;
676
Mark Brown4f340332013-01-11 08:55:43 +0900677out:
678 mutex_unlock(&info->lock);
679
680 return IRQ_HANDLED;
681}
682
683static void arizona_identify_headphone(struct arizona_extcon_info *info)
684{
685 struct arizona *arizona = info->arizona;
686 int ret;
687
Mark Brownbf14ee52013-02-05 20:20:17 +0000688 if (info->hpdet_done)
689 return;
690
Mark Brown4f340332013-01-11 08:55:43 +0900691 dev_dbg(arizona->dev, "Starting HPDET\n");
692
693 /* Make sure we keep the device enabled during the measurement */
694 pm_runtime_get(info->dev);
695
696 info->hpdet_active = true;
697
698 if (info->mic)
699 arizona_stop_mic(info);
700
Charles Keepax112bdfa2015-02-16 15:41:02 +0000701 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900702
703 ret = regmap_update_bits(arizona->regmap,
704 ARIZONA_ACCESSORY_DETECT_MODE_1,
705 ARIZONA_ACCDET_MODE_MASK,
Inha Song9e86b2a2015-05-04 13:42:13 +0900706 arizona->pdata.hpdet_channel);
Mark Brown4f340332013-01-11 08:55:43 +0900707 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900708 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +0900709 goto err;
710 }
711
712 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
713 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
714 if (ret != 0) {
715 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
716 ret);
717 goto err;
718 }
719
720 return;
721
722err:
723 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
724 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
725
726 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900727 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900728 if (ret != 0)
729 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
730
731 if (info->mic)
732 arizona_start_mic(info);
733
734 info->hpdet_active = false;
735}
Mark Browndd235ee2013-01-11 08:55:51 +0900736
737static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
738{
739 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000740 int hp_reading = 32;
741 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900742 int ret;
743
744 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
745
746 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000747 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900748
749 info->hpdet_active = true;
750
Charles Keepax112bdfa2015-02-16 15:41:02 +0000751 arizona_extcon_hp_clamp(info, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900752
753 ret = regmap_update_bits(arizona->regmap,
754 ARIZONA_ACCESSORY_DETECT_MODE_1,
755 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
756 info->micd_modes[0].src |
Inha Song9e86b2a2015-05-04 13:42:13 +0900757 arizona->pdata.hpdet_channel);
Mark Browndd235ee2013-01-11 08:55:51 +0900758 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900759 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Browndd235ee2013-01-11 08:55:51 +0900760 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900761 }
762
Mark Brown9c2ba272013-02-25 23:42:31 +0000763 if (arizona->pdata.hpdet_acc_id_line) {
764 ret = regmap_update_bits(arizona->regmap,
765 ARIZONA_HEADPHONE_DETECT_1,
766 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
767 if (ret != 0) {
768 dev_err(arizona->dev,
769 "Can't start HPDETL measurement: %d\n",
770 ret);
771 goto err;
772 }
773 } else {
774 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900775 }
776
777 return;
778
779err:
780 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
781 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
782
783 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900784 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900785 if (ret != 0)
786 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
787
Mark Brown4f340332013-01-11 08:55:43 +0900788 info->hpdet_active = false;
789}
790
Mark Brown939c5672013-04-01 19:17:34 +0100791static void arizona_micd_timeout_work(struct work_struct *work)
792{
793 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900794 struct arizona_extcon_info,
795 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100796
797 mutex_lock(&info->lock);
798
799 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
Mark Brown939c5672013-04-01 19:17:34 +0100800
801 info->detecting = false;
802
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100803 arizona_identify_headphone(info);
804
Mark Brown939c5672013-04-01 19:17:34 +0100805 arizona_stop_mic(info);
806
807 mutex_unlock(&info->lock);
808}
809
Mark Browncd59e792013-04-01 19:21:48 +0100810static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100811{
Mark Browncd59e792013-04-01 19:21:48 +0100812 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900813 struct arizona_extcon_info,
814 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100815 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100816 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100817 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100818
Mark Brown939c5672013-04-01 19:17:34 +0100819 cancel_delayed_work_sync(&info->micd_timeout_work);
820
Mark Brownf2c32a82012-06-24 12:09:45 +0100821 mutex_lock(&info->lock);
822
Charles Keepax31a847e2013-11-14 16:18:23 +0000823 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900824 ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000825 if (ret < 0) {
826 dev_err(arizona->dev, "Failed to check cable state: %d\n",
827 ret);
828 mutex_unlock(&info->lock);
829 return;
830 } else if (!ret) {
831 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
832 mutex_unlock(&info->lock);
833 return;
834 }
835
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100836 if (info->detecting && arizona->pdata.micd_software_compare) {
837 /* Must disable MICD before we read the ADCVAL */
838 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
839 ARIZONA_MICD_ENA, 0);
840 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
841 if (ret != 0) {
842 dev_err(arizona->dev,
843 "Failed to read MICDET_ADCVAL: %d\n",
844 ret);
845 mutex_unlock(&info->lock);
846 return;
847 }
848
849 dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
850
851 val &= ARIZONA_MICDET_ADCVAL_MASK;
852 if (val < ARRAY_SIZE(arizona_micd_levels))
853 val = arizona_micd_levels[val];
854 else
855 val = INT_MAX;
856
857 if (val <= QUICK_HEADPHONE_MAX_OHM)
858 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
859 else if (val <= MICROPHONE_MIN_OHM)
860 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
861 else if (val <= MICROPHONE_MAX_OHM)
862 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
863 else
864 val = ARIZONA_MICD_LVL_8;
865 }
866
Charles Keepaxffae24f2013-11-14 16:18:21 +0000867 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100868 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
869 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900870 dev_err(arizona->dev,
871 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100872 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100873 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100874 }
875
876 dev_dbg(arizona->dev, "MICDET: %x\n", val);
877
878 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900879 dev_warn(arizona->dev,
880 "Microphone detection state invalid\n");
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 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100884 }
885
Charles Keepaxffae24f2013-11-14 16:18:21 +0000886 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100887 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100888 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100889 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100890 }
891
892 /* Due to jack detect this should never happen */
893 if (!(val & ARIZONA_MICD_STS)) {
894 dev_warn(arizona->dev, "Detected open circuit\n");
Charles Keepax57f70ef2015-06-25 16:47:02 +0100895 info->mic = false;
896 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100897 info->detecting = false;
Charles Keepax57f70ef2015-06-25 16:47:02 +0100898 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100899 goto handled;
900 }
901
902 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000903 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100904 info->mic = true;
905 info->detecting = false;
906
Mark Brown4f340332013-01-11 08:55:43 +0900907 arizona_identify_headphone(info);
908
Chanwoo Choi8670b452016-08-16 15:55:34 +0900909 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900910 EXTCON_JACK_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100911 if (ret != 0)
912 dev_err(arizona->dev, "Headset report failed: %d\n",
913 ret);
914
Mark Brownbbbd46e2013-01-10 19:38:43 +0000915 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100916 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000917 if (ret != 0) {
918 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
919 ret);
920 }
921
Mark Brownf2c32a82012-06-24 12:09:45 +0100922 goto handled;
923 }
924
925 /* If we detected a lower impedence during initial startup
926 * then we probably have the wrong polarity, flip it. Don't
927 * do this for the lowest impedences to speed up detection of
928 * plain headphones. If both polarities report a low
929 * impedence then give up and report headphones.
930 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000931 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800932 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900933 dev_dbg(arizona->dev, "Detected HP/line\n");
Mark Brown9ef2224d2012-06-28 13:08:31 +0100934
Mark Brown4f340332013-01-11 08:55:43 +0900935 info->detecting = false;
936
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100937 arizona_identify_headphone(info);
938
Mark Brown4f340332013-01-11 08:55:43 +0900939 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100940 } else {
941 info->micd_mode++;
942 if (info->micd_mode == info->micd_num_modes)
943 info->micd_mode = 0;
944 arizona_extcon_set_mode(info, info->micd_mode);
945
946 info->jack_flips++;
947 }
948
949 goto handled;
950 }
951
952 /*
953 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100954 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100955 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000956 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100957 if (info->mic) {
958 dev_dbg(arizona->dev, "Mic button detected\n");
959
Mark Brown34efe4d2012-07-20 17:07:29 +0100960 lvl = val & ARIZONA_MICD_LVL_MASK;
961 lvl >>= ARIZONA_MICD_LVL_SHIFT;
962
Mark Brown41a57852013-04-01 19:18:18 +0100963 for (i = 0; i < info->num_micd_ranges; i++)
964 input_report_key(info->input,
965 info->micd_ranges[i].key, 0);
966
Mark Brown6fed4d82013-04-01 22:03:06 +0100967 WARN_ON(!lvl);
968 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
969 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
970 key = info->micd_ranges[ffs(lvl) - 1].key;
971 input_report_key(info->input, key, 1);
972 input_sync(info->input);
973 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100974
Mark Brownf2c32a82012-06-24 12:09:45 +0100975 } else if (info->detecting) {
976 dev_dbg(arizona->dev, "Headphone detected\n");
977 info->detecting = false;
978 arizona_stop_mic(info);
979
Mark Brown4f340332013-01-11 08:55:43 +0900980 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100981 } else {
982 dev_warn(arizona->dev, "Button with no mic: %x\n",
983 val);
984 }
985 } else {
986 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100987 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100988 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100989 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100990 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000991 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100992 }
993
994handled:
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100995 if (info->detecting) {
996 if (arizona->pdata.micd_software_compare)
997 regmap_update_bits(arizona->regmap,
998 ARIZONA_MIC_DETECT_1,
999 ARIZONA_MICD_ENA,
1000 ARIZONA_MICD_ENA);
1001
Mark Browndf9a5ab2013-07-18 22:42:22 +01001002 queue_delayed_work(system_power_efficient_wq,
1003 &info->micd_timeout_work,
1004 msecs_to_jiffies(info->micd_timeout));
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001005 }
Mark Brown939c5672013-04-01 19:17:34 +01001006
Mark Brownf2c32a82012-06-24 12:09:45 +01001007 pm_runtime_mark_last_busy(info->dev);
1008 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +01001009}
1010
1011static irqreturn_t arizona_micdet(int irq, void *data)
1012{
1013 struct arizona_extcon_info *info = data;
1014 struct arizona *arizona = info->arizona;
1015 int debounce = arizona->pdata.micd_detect_debounce;
1016
1017 cancel_delayed_work_sync(&info->micd_detect_work);
1018 cancel_delayed_work_sync(&info->micd_timeout_work);
1019
1020 mutex_lock(&info->lock);
1021 if (!info->detecting)
1022 debounce = 0;
1023 mutex_unlock(&info->lock);
1024
1025 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001026 queue_delayed_work(system_power_efficient_wq,
1027 &info->micd_detect_work,
1028 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +01001029 else
1030 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001031
1032 return IRQ_HANDLED;
1033}
1034
Mark Brown0e27bd32013-02-05 21:00:15 +00001035static void arizona_hpdet_work(struct work_struct *work)
1036{
1037 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001038 struct arizona_extcon_info,
1039 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +00001040
1041 mutex_lock(&info->lock);
1042 arizona_start_hpdet_acc_id(info);
1043 mutex_unlock(&info->lock);
1044}
1045
Charles Keepaxe57bb432017-01-25 09:34:06 +00001046static int arizona_hpdet_wait(struct arizona_extcon_info *info)
1047{
1048 struct arizona *arizona = info->arizona;
1049 unsigned int val;
1050 int i, ret;
1051
1052 for (i = 0; i < ARIZONA_HPDET_WAIT_COUNT; i++) {
1053 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2,
1054 &val);
1055 if (ret) {
1056 dev_err(arizona->dev,
1057 "Failed to read HPDET state: %d\n", ret);
1058 return ret;
1059 }
1060
1061 switch (info->hpdet_ip_version) {
1062 case 0:
1063 if (val & ARIZONA_HP_DONE)
1064 return 0;
1065 break;
1066 default:
1067 if (val & ARIZONA_HP_DONE_B)
1068 return 0;
1069 break;
1070 }
1071
1072 msleep(ARIZONA_HPDET_WAIT_DELAY_MS);
1073 }
1074
1075 dev_warn(arizona->dev, "HPDET did not appear to complete\n");
1076
1077 return -ETIMEDOUT;
1078}
1079
Mark Brownf2c32a82012-06-24 12:09:45 +01001080static irqreturn_t arizona_jackdet(int irq, void *data)
1081{
1082 struct arizona_extcon_info *info = data;
1083 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001084 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +01001085 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +01001086 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +01001087
Mark Brown939c5672013-04-01 19:17:34 +01001088 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
1089 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001090
Mark Browna3e20782013-04-01 19:05:27 +01001091 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +00001092
Mark Brownf2c32a82012-06-24 12:09:45 +01001093 mutex_lock(&info->lock);
1094
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001095 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001096 mask = ARIZONA_MICD_CLAMP_STS;
Nariman Poushina0ef6422015-09-16 10:42:19 +01001097 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +09001098 } else {
1099 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001100 if (arizona->pdata.jd_invert)
1101 present = 0;
1102 else
1103 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +09001104 }
1105
Mark Brownf2c32a82012-06-24 12:09:45 +01001106 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
1107 if (ret != 0) {
1108 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
1109 ret);
1110 mutex_unlock(&info->lock);
1111 pm_runtime_put_autosuspend(info->dev);
1112 return IRQ_NONE;
1113 }
1114
Mark Browna3e20782013-04-01 19:05:27 +01001115 val &= mask;
1116 if (val == info->last_jackdet) {
1117 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001118 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001119 queue_delayed_work(system_power_efficient_wq,
1120 &info->hpdet_work,
1121 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001122
Chanwoo Choic2275d22013-08-23 10:21:37 +09001123 if (cancelled_mic) {
1124 int micd_timeout = info->micd_timeout;
1125
Mark Browndf9a5ab2013-07-18 22:42:22 +01001126 queue_delayed_work(system_power_efficient_wq,
1127 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001128 msecs_to_jiffies(micd_timeout));
1129 }
Mark Brown939c5672013-04-01 19:17:34 +01001130
Mark Browna3e20782013-04-01 19:05:27 +01001131 goto out;
1132 }
1133 info->last_jackdet = val;
1134
1135 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001136 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choi8670b452016-08-16 15:55:34 +09001137 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +09001138 EXTCON_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001139
1140 if (ret != 0)
1141 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1142 ret);
1143
Mark Browndd235ee2013-01-11 08:55:51 +09001144 if (!arizona->pdata.hpdet_acc_id) {
1145 info->detecting = true;
1146 info->mic = false;
1147 info->jack_flips = 0;
1148
1149 arizona_start_mic(info);
1150 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001151 queue_delayed_work(system_power_efficient_wq,
1152 &info->hpdet_work,
1153 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001154 }
Mark Brown4e616872013-01-15 22:09:20 +09001155
Charles Keepax6c20b932015-09-16 10:42:21 +01001156 if (info->micd_clamp || !arizona->pdata.jd_invert)
1157 regmap_update_bits(arizona->regmap,
1158 ARIZONA_JACK_DETECT_DEBOUNCE,
1159 ARIZONA_MICD_CLAMP_DB |
1160 ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001161 } else {
1162 dev_dbg(arizona->dev, "Detected jack removal\n");
1163
1164 arizona_stop_mic(info);
1165
Mark Browndd235ee2013-01-11 08:55:51 +09001166 info->num_hpdet_res = 0;
1167 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1168 info->hpdet_res[i] = 0;
1169 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001170 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001171 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001172
Mark Brown6fed4d82013-04-01 22:03:06 +01001173 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001174 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001175 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001176 input_sync(info->input);
1177
Chanwoo Choi5475e632016-07-01 02:36:49 +09001178 for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) {
Chanwoo Choi8670b452016-08-16 15:55:34 +09001179 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi5475e632016-07-01 02:36:49 +09001180 arizona_cable[i], false);
1181 if (ret != 0)
1182 dev_err(arizona->dev,
1183 "Removal report failed: %d\n", ret);
1184 }
Mark Brown4e616872013-01-15 22:09:20 +09001185
Charles Keepaxe57bb432017-01-25 09:34:06 +00001186 /*
1187 * If the jack was removed during a headphone detection we
1188 * need to wait for the headphone detection to finish, as
1189 * it can not be aborted. We don't want to be able to start
1190 * a new headphone detection from a fresh insert until this
1191 * one is finished.
1192 */
1193 arizona_hpdet_wait(info);
1194
Mark Brown4e616872013-01-15 22:09:20 +09001195 regmap_update_bits(arizona->regmap,
1196 ARIZONA_JACK_DETECT_DEBOUNCE,
1197 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1198 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001199 }
1200
Mark Brown7abd4e22013-04-01 19:25:55 +01001201 if (arizona->pdata.micd_timeout)
1202 info->micd_timeout = arizona->pdata.micd_timeout;
1203 else
1204 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1205
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001206out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001207 /* Clear trig_sts to make sure DCVDD is not forced up */
1208 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1209 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1210 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1211 ARIZONA_JD1_FALL_TRIG_STS |
1212 ARIZONA_JD1_RISE_TRIG_STS);
1213
Mark Brownf2c32a82012-06-24 12:09:45 +01001214 mutex_unlock(&info->lock);
1215
1216 pm_runtime_mark_last_busy(info->dev);
1217 pm_runtime_put_autosuspend(info->dev);
1218
1219 return IRQ_HANDLED;
1220}
1221
Mark Brown6fed4d82013-04-01 22:03:06 +01001222/* Map a level onto a slot in the register bank */
1223static void arizona_micd_set_level(struct arizona *arizona, int index,
1224 unsigned int level)
1225{
1226 int reg;
1227 unsigned int mask;
1228
1229 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1230
1231 if (!(index % 2)) {
1232 mask = 0x3f00;
1233 level <<= 8;
1234 } else {
1235 mask = 0x3f;
1236 }
1237
1238 /* Program the level itself */
1239 regmap_update_bits(arizona->regmap, reg, mask, level);
1240}
1241
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001242static int arizona_extcon_get_micd_configs(struct device *dev,
1243 struct arizona *arizona)
1244{
1245 const char * const prop = "wlf,micd-configs";
1246 const int entries_per_config = 3;
1247 struct arizona_micd_config *micd_configs;
1248 int nconfs, ret;
1249 int i, j;
1250 u32 *vals;
1251
1252 nconfs = device_property_read_u32_array(arizona->dev, prop, NULL, 0);
1253 if (nconfs <= 0)
1254 return 0;
1255
1256 vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
1257 if (!vals)
1258 return -ENOMEM;
1259
1260 ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
1261 if (ret < 0)
1262 goto out;
1263
1264 nconfs /= entries_per_config;
Markus Elfringcf5459a2017-04-23 22:44:19 +02001265 micd_configs = devm_kcalloc(dev, nconfs, sizeof(*micd_configs),
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001266 GFP_KERNEL);
1267 if (!micd_configs) {
1268 ret = -ENOMEM;
1269 goto out;
1270 }
1271
1272 for (i = 0, j = 0; i < nconfs; ++i) {
1273 micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
1274 micd_configs[i].bias = vals[j++];
1275 micd_configs[i].gpio = vals[j++];
1276 }
1277
1278 arizona->pdata.micd_configs = micd_configs;
1279 arizona->pdata.num_micd_configs = nconfs;
1280
1281out:
1282 kfree(vals);
1283 return ret;
1284}
1285
1286static int arizona_extcon_device_get_pdata(struct device *dev,
1287 struct arizona *arizona)
Inha Song9e86b2a2015-05-04 13:42:13 +09001288{
1289 struct arizona_pdata *pdata = &arizona->pdata;
1290 unsigned int val = ARIZONA_ACCDET_MODE_HPL;
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001291 int ret;
Inha Song9e86b2a2015-05-04 13:42:13 +09001292
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001293 device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
Inha Song9e86b2a2015-05-04 13:42:13 +09001294 switch (val) {
1295 case ARIZONA_ACCDET_MODE_HPL:
1296 case ARIZONA_ACCDET_MODE_HPR:
1297 pdata->hpdet_channel = val;
1298 break;
1299 default:
1300 dev_err(arizona->dev,
1301 "Wrong wlf,hpdet-channel DT value %d\n", val);
1302 pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
1303 }
1304
Charles Keepax4778d442015-06-19 17:23:30 +01001305 device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
1306 &pdata->micd_detect_debounce);
1307
1308 device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
1309 &pdata->micd_bias_start_time);
1310
1311 device_property_read_u32(arizona->dev, "wlf,micd-rate",
1312 &pdata->micd_rate);
1313
1314 device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
1315 &pdata->micd_dbtime);
1316
Charles Keepax7a7ef0f2015-11-23 14:51:30 +00001317 device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
Charles Keepax4778d442015-06-19 17:23:30 +01001318 &pdata->micd_timeout);
1319
1320 pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
1321 "wlf,micd-force-micbias");
1322
Charles Keepax2e87b7a2015-11-19 15:45:35 +00001323 pdata->micd_software_compare = device_property_read_bool(arizona->dev,
1324 "wlf,micd-software-compare");
1325
Charles Keepax3d7a8722015-11-19 15:45:37 +00001326 pdata->jd_invert = device_property_read_bool(arizona->dev,
1327 "wlf,jd-invert");
1328
Charles Keepax99374222015-11-19 15:45:36 +00001329 device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
1330
Charles Keepax35247c12015-11-19 15:45:38 +00001331 pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001332 "wlf,use-jd2");
Charles Keepax35247c12015-11-19 15:45:38 +00001333 pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001334 "wlf,use-jd2-nopull");
Charles Keepax35247c12015-11-19 15:45:38 +00001335
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001336 ret = arizona_extcon_get_micd_configs(dev, arizona);
1337 if (ret < 0)
1338 dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
1339
Inha Song9e86b2a2015-05-04 13:42:13 +09001340 return 0;
1341}
1342
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001343static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001344{
1345 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001346 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001347 struct arizona_extcon_info *info;
Mark Browne56a0a572013-04-01 19:03:52 +01001348 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001349 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001350 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001351 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001352
Mark Brownbbbd46e2013-01-10 19:38:43 +00001353 if (!arizona->dapm || !arizona->dapm->card)
1354 return -EPROBE_DEFER;
1355
Mark Brownf2c32a82012-06-24 12:09:45 +01001356 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001357 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001358 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001359
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001360 if (!dev_get_platdata(arizona->dev))
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001361 arizona_extcon_device_get_pdata(&pdev->dev, arizona);
Inha Song9e86b2a2015-05-04 13:42:13 +09001362
Charles Keepax17271f62014-07-18 12:59:00 +01001363 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001364 if (IS_ERR(info->micvdd)) {
1365 ret = PTR_ERR(info->micvdd);
1366 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001367 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001368 }
1369
1370 mutex_init(&info->lock);
1371 info->arizona = arizona;
1372 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001373 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001374 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001375 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001376 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001377 platform_set_drvdata(pdev, info);
1378
1379 switch (arizona->type) {
1380 case WM5102:
1381 switch (arizona->rev) {
1382 case 0:
1383 info->micd_reva = true;
1384 break;
1385 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001386 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001387 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001388 break;
1389 }
1390 break;
Charles Keepax77438612013-11-14 16:18:25 +00001391 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001392 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001393 switch (arizona->rev) {
1394 case 0 ... 2:
1395 break;
1396 default:
1397 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001398 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001399 break;
1400 }
1401 break;
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +01001402 case WM8998:
1403 case WM1814:
1404 info->micd_clamp = true;
1405 info->hpdet_ip_version = 2;
1406 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001407 default:
1408 break;
1409 }
1410
Chanwoo Choief70a212014-04-21 20:47:31 +09001411 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1412 if (IS_ERR(info->edev)) {
1413 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1414 return -ENOMEM;
1415 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001416
Chanwoo Choief70a212014-04-21 20:47:31 +09001417 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001418 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001419 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001420 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001421 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001422 }
1423
Mark Brown6fed4d82013-04-01 22:03:06 +01001424 info->input = devm_input_allocate_device(&pdev->dev);
1425 if (!info->input) {
1426 dev_err(arizona->dev, "Can't allocate input dev\n");
1427 ret = -ENOMEM;
1428 goto err_register;
1429 }
1430
1431 info->input->name = "Headset";
1432 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001433
Mark Brownf2c32a82012-06-24 12:09:45 +01001434 if (pdata->num_micd_configs) {
1435 info->micd_modes = pdata->micd_configs;
1436 info->micd_num_modes = pdata->num_micd_configs;
1437 } else {
1438 info->micd_modes = micd_default_modes;
1439 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1440 }
1441
Charles Keepax6772a5a2015-09-16 10:42:17 +01001442 if (arizona->pdata.gpsw > 0)
1443 regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
1444 ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
1445
Charles Keepax6c467a12016-11-25 13:44:36 +00001446 if (pdata->micd_pol_gpio > 0) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001447 if (info->micd_modes[0].gpio)
1448 mode = GPIOF_OUT_INIT_HIGH;
1449 else
1450 mode = GPIOF_OUT_INIT_LOW;
1451
Charles Keepax6c467a12016-11-25 13:44:36 +00001452 ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio,
1453 mode, "MICD polarity");
Mark Brownf2c32a82012-06-24 12:09:45 +01001454 if (ret != 0) {
1455 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
Charles Keepax6c467a12016-11-25 13:44:36 +00001456 pdata->micd_pol_gpio, ret);
Mark Brownf2c32a82012-06-24 12:09:45 +01001457 goto err_register;
1458 }
Charles Keepax6c467a12016-11-25 13:44:36 +00001459
1460 info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001461 } else {
1462 if (info->micd_modes[0].gpio)
1463 mode = GPIOD_OUT_HIGH;
1464 else
1465 mode = GPIOD_OUT_LOW;
1466
1467 /* We can't use devm here because we need to do the get
1468 * against the MFD device, as that is where the of_node
1469 * will reside, but if we devm against that the GPIO
1470 * will not be freed if the extcon driver is unloaded.
1471 */
1472 info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
1473 "wlf,micd-pol",
1474 GPIOD_OUT_LOW);
1475 if (IS_ERR(info->micd_pol_gpio)) {
1476 ret = PTR_ERR(info->micd_pol_gpio);
1477 dev_err(arizona->dev,
1478 "Failed to get microphone polarity GPIO: %d\n",
1479 ret);
1480 goto err_register;
1481 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001482 }
1483
Mark Brown1eda6aa2013-01-11 08:55:54 +09001484 if (arizona->pdata.hpdet_id_gpio > 0) {
1485 ret = devm_gpio_request_one(&pdev->dev,
1486 arizona->pdata.hpdet_id_gpio,
1487 GPIOF_OUT_INIT_LOW,
1488 "HPDET");
1489 if (ret != 0) {
1490 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1491 arizona->pdata.hpdet_id_gpio, ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001492 goto err_gpio;
Mark Brown1eda6aa2013-01-11 08:55:54 +09001493 }
1494 }
1495
Mark Brownb17e5462013-01-11 08:55:24 +09001496 if (arizona->pdata.micd_bias_start_time)
1497 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1498 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1499 arizona->pdata.micd_bias_start_time
1500 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1501
Mark Brown2e033db2013-01-21 17:36:33 +09001502 if (arizona->pdata.micd_rate)
1503 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1504 ARIZONA_MICD_RATE_MASK,
1505 arizona->pdata.micd_rate
1506 << ARIZONA_MICD_RATE_SHIFT);
1507
Charles Keepaxbb327e92015-06-30 13:32:39 +01001508 switch (arizona->pdata.micd_dbtime) {
1509 case MICD_DBTIME_FOUR_READINGS:
Mark Brown2e033db2013-01-21 17:36:33 +09001510 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1511 ARIZONA_MICD_DBTIME_MASK,
Charles Keepaxbb327e92015-06-30 13:32:39 +01001512 ARIZONA_MICD_DBTIME);
1513 break;
1514 case MICD_DBTIME_TWO_READINGS:
1515 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1516 ARIZONA_MICD_DBTIME_MASK, 0);
1517 break;
1518 default:
1519 break;
1520 }
Mark Brown2e033db2013-01-21 17:36:33 +09001521
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001522 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) <
1523 ARIZONA_NUM_MICD_BUTTON_LEVELS);
Mark Brown6fed4d82013-04-01 22:03:06 +01001524
1525 if (arizona->pdata.num_micd_ranges) {
1526 info->micd_ranges = pdata->micd_ranges;
1527 info->num_micd_ranges = pdata->num_micd_ranges;
1528 } else {
1529 info->micd_ranges = micd_default_ranges;
1530 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1531 }
1532
1533 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1534 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1535 arizona->pdata.num_micd_ranges);
1536 }
1537
1538 if (info->num_micd_ranges > 1) {
1539 for (i = 1; i < info->num_micd_ranges; i++) {
1540 if (info->micd_ranges[i - 1].max >
1541 info->micd_ranges[i].max) {
1542 dev_err(arizona->dev,
1543 "MICD ranges must be sorted\n");
1544 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001545 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001546 }
1547 }
1548 }
1549
1550 /* Disable all buttons by default */
1551 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1552 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1553
1554 /* Set up all the buttons the user specified */
1555 for (i = 0; i < info->num_micd_ranges; i++) {
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001556 for (j = 0; j < ARIZONA_NUM_MICD_BUTTON_LEVELS; j++)
Mark Brown6fed4d82013-04-01 22:03:06 +01001557 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1558 break;
1559
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001560 if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
Mark Brown6fed4d82013-04-01 22:03:06 +01001561 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1562 info->micd_ranges[i].max);
1563 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001564 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001565 }
1566
1567 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1568 arizona_micd_levels[j], i);
1569
1570 arizona_micd_set_level(arizona, i, j);
1571 input_set_capability(info->input, EV_KEY,
1572 info->micd_ranges[i].key);
1573
1574 /* Enable reporting of that range */
1575 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1576 1 << i, 1 << i);
1577 }
1578
1579 /* Set all the remaining keys to a maximum */
1580 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1581 arizona_micd_set_level(arizona, i, 0x3f);
1582
Mark Browndab63eb2013-01-11 08:55:36 +09001583 /*
Mark Brown92a49872013-01-11 08:55:39 +09001584 * If we have a clamp use it, activating in conjunction with
1585 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001586 */
1587 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001588 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a572013-04-01 19:03:52 +01001589 /* Put the GPIO into input mode with optional pull */
1590 val = 0xc101;
1591 if (arizona->pdata.jd_gpio5_nopull)
1592 val &= ~ARIZONA_GPN_PU;
1593
Mark Brown92a49872013-01-11 08:55:39 +09001594 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a572013-04-01 19:03:52 +01001595 val);
Mark Brown92a49872013-01-11 08:55:39 +09001596
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001597 if (arizona->pdata.jd_invert)
1598 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1599 else
1600 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001601 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001602 if (arizona->pdata.jd_invert)
1603 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1604 else
1605 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001606 }
1607
Mark Browndab63eb2013-01-11 08:55:36 +09001608 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001609 ARIZONA_MICD_CLAMP_CONTROL,
1610 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1611
1612 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001613 ARIZONA_JACK_DETECT_DEBOUNCE,
1614 ARIZONA_MICD_CLAMP_DB,
1615 ARIZONA_MICD_CLAMP_DB);
1616 }
1617
Mark Brownf2c32a82012-06-24 12:09:45 +01001618 arizona_extcon_set_mode(info, 0);
1619
1620 pm_runtime_enable(&pdev->dev);
1621 pm_runtime_idle(&pdev->dev);
1622 pm_runtime_get_sync(&pdev->dev);
1623
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001624 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001625 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1626 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1627 } else {
1628 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1629 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1630 }
1631
1632 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001633 "JACKDET rise", arizona_jackdet, info);
1634 if (ret != 0) {
1635 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1636 ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001637 goto err_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +01001638 }
1639
Mark Brown92a49872013-01-11 08:55:39 +09001640 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001641 if (ret != 0) {
1642 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1643 ret);
1644 goto err_rise;
1645 }
1646
Mark Brown92a49872013-01-11 08:55:39 +09001647 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001648 "JACKDET fall", arizona_jackdet, info);
1649 if (ret != 0) {
1650 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1651 goto err_rise_wake;
1652 }
1653
Mark Brown92a49872013-01-11 08:55:39 +09001654 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001655 if (ret != 0) {
1656 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1657 ret);
1658 goto err_fall;
1659 }
1660
1661 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1662 "MICDET", arizona_micdet, info);
1663 if (ret != 0) {
1664 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1665 goto err_fall_wake;
1666 }
1667
Mark Brown4f340332013-01-11 08:55:43 +09001668 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1669 "HPDET", arizona_hpdet_irq, info);
1670 if (ret != 0) {
1671 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1672 goto err_micdet;
1673 }
1674
Mark Brownf2c32a82012-06-24 12:09:45 +01001675 arizona_clk32k_enable(arizona);
1676 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1677 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1678 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1679 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1680
Mark Brownb8575a12012-09-07 17:01:15 +08001681 ret = regulator_allow_bypass(info->micvdd, true);
1682 if (ret != 0)
1683 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1684 ret);
1685
Mark Brownf2c32a82012-06-24 12:09:45 +01001686 pm_runtime_put(&pdev->dev);
1687
Mark Brown34efe4d2012-07-20 17:07:29 +01001688 ret = input_register_device(info->input);
1689 if (ret) {
1690 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001691 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001692 }
1693
Mark Brownf2c32a82012-06-24 12:09:45 +01001694 return 0;
1695
Mark Brown4f340332013-01-11 08:55:43 +09001696err_hpdet:
1697 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001698err_micdet:
1699 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001700err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001701 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001702err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001703 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001704err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001705 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001706err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001707 arizona_free_irq(arizona, jack_irq_rise, info);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001708err_gpio:
1709 gpiod_put(info->micd_pol_gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +01001710err_register:
1711 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001712 return ret;
1713}
1714
Bill Pemberton93ed0322012-11-19 13:25:49 -05001715static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001716{
1717 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1718 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001719 int jack_irq_rise, jack_irq_fall;
Charles Keepax00053de2019-04-04 17:33:56 +01001720 bool change;
1721
1722 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
1723 ARIZONA_MICD_ENA, 0,
1724 &change);
1725
1726 if (change) {
1727 regulator_disable(info->micvdd);
1728 pm_runtime_put(info->dev);
1729 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001730
Charles Keepax8e5838d2015-06-19 17:23:31 +01001731 gpiod_put(info->micd_pol_gpio);
1732
Mark Brownf2c32a82012-06-24 12:09:45 +01001733 pm_runtime_disable(&pdev->dev);
1734
Mark Browndab63eb2013-01-11 08:55:36 +09001735 regmap_update_bits(arizona->regmap,
1736 ARIZONA_MICD_CLAMP_CONTROL,
1737 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1738
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001739 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001740 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1741 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1742 } else {
1743 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1744 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1745 }
1746
1747 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1748 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1749 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001750 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001751 arizona_free_irq(arizona, jack_irq_rise, info);
1752 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001753 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001754 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1755 ARIZONA_JD1_ENA, 0);
1756 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001757
1758 return 0;
1759}
1760
1761static struct platform_driver arizona_extcon_driver = {
1762 .driver = {
1763 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001764 },
1765 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001766 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001767};
1768
1769module_platform_driver(arizona_extcon_driver);
1770
1771MODULE_DESCRIPTION("Arizona Extcon driver");
1772MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1773MODULE_LICENSE("GPL");
1774MODULE_ALIAS("platform:extcon-arizona");