blob: d836d4ce5ee46ab9da23715881d0cdd82ec7fcb5 [file] [log] [blame]
Mark Brownf2c32a82012-06-24 12:09:45 +01001/*
2 * extcon-arizona.c - Extcon driver Wolfson Arizona devices
3 *
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +01004 * Copyright (C) 2012-2014 Wolfson Microelectronics plc
Mark Brownf2c32a82012-06-24 12:09:45 +01005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/i2c.h>
20#include <linux/slab.h>
21#include <linux/interrupt.h>
22#include <linux/err.h>
Charles Keepax8e5838d2015-06-19 17:23:31 +010023#include <linux/gpio/consumer.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010024#include <linux/gpio.h>
Mark Brown34efe4d2012-07-20 17:07:29 +010025#include <linux/input.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010026#include <linux/platform_device.h>
27#include <linux/pm_runtime.h>
Charles Keepaxfeffb0c2015-06-19 17:23:29 +010028#include <linux/property.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010029#include <linux/regulator/consumer.h>
30#include <linux/extcon.h>
31
Mark Brownbbbd46e2013-01-10 19:38:43 +000032#include <sound/soc.h>
33
Mark Brownf2c32a82012-06-24 12:09:45 +010034#include <linux/mfd/arizona/core.h>
35#include <linux/mfd/arizona/pdata.h>
36#include <linux/mfd/arizona/registers.h>
Inha Song9e86b2a2015-05-04 13:42:13 +090037#include <dt-bindings/mfd/arizona.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010038
Mark Brown6fed4d82013-04-01 22:03:06 +010039#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010040
Richard Fitzgeralda288d642014-05-23 12:54:57 +010041#define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
42#define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
43#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
44#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
45
Charles Keepaxf719ae32015-09-16 10:42:18 +010046#define ARIZONA_TST_CAP_DEFAULT 0x3
47#define ARIZONA_TST_CAP_CLAMP 0x1
48
Mark Brown9dd5e532013-04-01 19:09:45 +010049#define ARIZONA_HPDET_MAX 10000
50
Mark Brown2643fd62013-04-01 19:07:28 +010051#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010052#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010053
Charles Keepaxdf8b6772015-09-16 10:42:16 +010054#define QUICK_HEADPHONE_MAX_OHM 3
55#define MICROPHONE_MIN_OHM 1257
56#define MICROPHONE_MAX_OHM 30000
57
Charles Keepaxbb327e92015-06-30 13:32:39 +010058#define MICD_DBTIME_TWO_READINGS 2
59#define MICD_DBTIME_FOUR_READINGS 4
60
Charles Keepaxffae24f2013-11-14 16:18:21 +000061#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
62 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
63 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
64 ARIZONA_MICD_LVL_7)
65
66#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
67
68#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
69
Mark Brownf2c32a82012-06-24 12:09:45 +010070struct arizona_extcon_info {
71 struct device *dev;
72 struct arizona *arizona;
73 struct mutex lock;
74 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010075 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010076
Mark Browna3e20782013-04-01 19:05:27 +010077 u16 last_jackdet;
78
Mark Brownf2c32a82012-06-24 12:09:45 +010079 int micd_mode;
80 const struct arizona_micd_config *micd_modes;
81 int micd_num_modes;
82
Mark Brown6fed4d82013-04-01 22:03:06 +010083 const struct arizona_micd_range *micd_ranges;
84 int num_micd_ranges;
85
Mark Brown7abd4e22013-04-01 19:25:55 +010086 int micd_timeout;
87
Mark Brownf2c32a82012-06-24 12:09:45 +010088 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090089 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010090
Mark Brown0e27bd32013-02-05 21:00:15 +000091 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010092 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010093 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000094
Mark Brown4f340332013-01-11 08:55:43 +090095 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000096 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010097 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090098
Mark Browndd235ee2013-01-11 08:55:51 +090099 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900100 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +0900101
Mark Brownf2c32a82012-06-24 12:09:45 +0100102 bool mic;
103 bool detecting;
104 int jack_flips;
105
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100106 int hpdet_ip_version;
Mark Brown4f340332013-01-11 08:55:43 +0900107
Chanwoo Choief70a212014-04-21 20:47:31 +0900108 struct extcon_dev *edev;
Charles Keepax8e5838d2015-06-19 17:23:31 +0100109
110 struct gpio_desc *micd_pol_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +0100111};
112
113static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +0100114 { ARIZONA_ACCDET_SRC, 1, 0 },
115 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100116};
117
Mark Brown6fed4d82013-04-01 22:03:06 +0100118static const struct arizona_micd_range micd_default_ranges[] = {
119 { .max = 11, .key = BTN_0 },
120 { .max = 28, .key = BTN_1 },
121 { .max = 54, .key = BTN_2 },
122 { .max = 100, .key = BTN_3 },
123 { .max = 186, .key = BTN_4 },
124 { .max = 430, .key = BTN_5 },
125};
126
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100127/* The number of levels in arizona_micd_levels valid for button thresholds */
128#define ARIZONA_NUM_MICD_BUTTON_LEVELS 64
129
Mark Brown6fed4d82013-04-01 22:03:06 +0100130static const int arizona_micd_levels[] = {
131 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
132 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
133 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
134 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100135 1257, 30000,
Mark Brown34efe4d2012-07-20 17:07:29 +0100136};
137
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900138static const unsigned int arizona_cable[] = {
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900139 EXTCON_MECHANICAL,
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900140 EXTCON_JACK_MICROPHONE,
141 EXTCON_JACK_HEADPHONE,
142 EXTCON_JACK_LINE_OUT,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900143 EXTCON_NONE,
Mark Brownf2c32a82012-06-24 12:09:45 +0100144};
145
Mark Brown9dd5e532013-04-01 19:09:45 +0100146static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
147
Charles Keepax112bdfa2015-02-16 15:41:02 +0000148static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
149 bool clamp)
Mark Brown03409072013-02-12 13:00:31 +0000150{
151 struct arizona *arizona = info->arizona;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000152 unsigned int mask = 0, val = 0;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100153 unsigned int cap_sel = 0;
Mark Brown03409072013-02-12 13:00:31 +0000154 int ret;
155
Charles Keepax43f0acd2015-02-16 15:41:03 +0000156 switch (arizona->type) {
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100157 case WM8998:
158 case WM1814:
159 mask = 0;
160 break;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000161 case WM5110:
Charles Keepax2b51f9c2015-04-30 23:43:37 +0900162 case WM8280:
Charles Keepax43f0acd2015-02-16 15:41:03 +0000163 mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
164 ARIZONA_HP1L_SHRTI;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100165 if (clamp) {
Charles Keepax43f0acd2015-02-16 15:41:03 +0000166 val = ARIZONA_HP1L_SHRTO;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100167 cap_sel = ARIZONA_TST_CAP_CLAMP;
168 } else {
Charles Keepax43f0acd2015-02-16 15:41:03 +0000169 val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100170 cap_sel = ARIZONA_TST_CAP_DEFAULT;
171 }
172
173 ret = regmap_update_bits(arizona->regmap,
174 ARIZONA_HP_TEST_CTRL_1,
175 ARIZONA_HP1_TST_CAP_SEL_MASK,
176 cap_sel);
177 if (ret != 0)
178 dev_warn(arizona->dev,
179 "Failed to set TST_CAP_SEL: %d\n", ret);
Charles Keepax43f0acd2015-02-16 15:41:03 +0000180 break;
181 default:
182 mask = ARIZONA_RMV_SHRT_HP1L;
183 if (clamp)
184 val = ARIZONA_RMV_SHRT_HP1L;
185 break;
Charles Keepaxc19dc202016-07-19 13:23:56 +0100186 }
Charles Keepax112bdfa2015-02-16 15:41:02 +0000187
Charles Keepax03bf1ad2015-12-29 16:32:03 +0000188 snd_soc_dapm_mutex_lock(arizona->dapm);
Mark Brown03409072013-02-12 13:00:31 +0000189
Charles Keepax112bdfa2015-02-16 15:41:02 +0000190 arizona->hpdet_clamp = clamp;
Mark Browndf8c3db2013-02-22 18:38:03 +0000191
Charles Keepax112bdfa2015-02-16 15:41:02 +0000192 /* Keep the HP output stages disabled while doing the clamp */
193 if (clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000194 ret = regmap_update_bits(arizona->regmap,
195 ARIZONA_OUTPUT_ENABLES_1,
196 ARIZONA_OUT1L_ENA |
197 ARIZONA_OUT1R_ENA, 0);
198 if (ret != 0)
199 dev_warn(arizona->dev,
200 "Failed to disable headphone outputs: %d\n",
201 ret);
Mark Brown03409072013-02-12 13:00:31 +0000202 }
203
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100204 if (mask) {
205 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
206 mask, val);
207 if (ret != 0)
208 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000209 ret);
210
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100211 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
212 mask, val);
213 if (ret != 0)
214 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
215 ret);
216 }
Mark Browndf8c3db2013-02-22 18:38:03 +0000217
Charles Keepax112bdfa2015-02-16 15:41:02 +0000218 /* Restore the desired state while not doing the clamp */
219 if (!clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000220 ret = regmap_update_bits(arizona->regmap,
221 ARIZONA_OUTPUT_ENABLES_1,
222 ARIZONA_OUT1L_ENA |
223 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000224 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000225 dev_warn(arizona->dev,
226 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000227 ret);
228 }
229
Charles Keepax03bf1ad2015-12-29 16:32:03 +0000230 snd_soc_dapm_mutex_unlock(arizona->dapm);
Mark Brown03409072013-02-12 13:00:31 +0000231}
232
Mark Brownf2c32a82012-06-24 12:09:45 +0100233static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
234{
235 struct arizona *arizona = info->arizona;
236
Mark Brown6fed4d82013-04-01 22:03:06 +0100237 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800238
Mark Browncd74f7b2012-11-27 16:14:26 +0900239 if (arizona->pdata.micd_pol_gpio > 0)
240 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
241 info->micd_modes[mode].gpio);
Charles Keepax8e5838d2015-06-19 17:23:31 +0100242 else
243 gpiod_set_value_cansleep(info->micd_pol_gpio,
244 info->micd_modes[mode].gpio);
245
Mark Brownf2c32a82012-06-24 12:09:45 +0100246 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
247 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100248 info->micd_modes[mode].bias <<
249 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100250 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
251 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
252
253 info->micd_mode = mode;
254
255 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
256}
257
Mark Brownbbbd46e2013-01-10 19:38:43 +0000258static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
259{
Charles Keepax41024242013-09-23 14:33:59 +0100260 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000261 case 1:
262 return "MICBIAS1";
263 case 2:
264 return "MICBIAS2";
265 case 3:
266 return "MICBIAS3";
267 default:
268 return "MICVDD";
269 }
270}
271
272static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
273{
274 struct arizona *arizona = info->arizona;
275 const char *widget = arizona_extcon_get_micbias(info);
276 struct snd_soc_dapm_context *dapm = arizona->dapm;
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000277 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000278 int ret;
279
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000280 ret = snd_soc_component_force_enable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000281 if (ret != 0)
282 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
283 widget, ret);
284
Mark Brownbbbd46e2013-01-10 19:38:43 +0000285 snd_soc_dapm_sync(dapm);
286
287 if (!arizona->pdata.micd_force_micbias) {
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000288 ret = snd_soc_component_disable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000289 if (ret != 0)
290 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
291 widget, ret);
292
Mark Brownbbbd46e2013-01-10 19:38:43 +0000293 snd_soc_dapm_sync(dapm);
294 }
295}
296
Mark Brown9b1270c2013-01-11 08:55:46 +0900297static void arizona_start_mic(struct arizona_extcon_info *info)
298{
299 struct arizona *arizona = info->arizona;
300 bool change;
301 int ret;
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100302 unsigned int mode;
Mark Brown9b1270c2013-01-11 08:55:46 +0900303
Mark Brown9b1270c2013-01-11 08:55:46 +0900304 /* Microphone detection can't use idle mode */
305 pm_runtime_get(info->dev);
306
Mark Brownbbbd46e2013-01-10 19:38:43 +0000307 if (info->detecting) {
308 ret = regulator_allow_bypass(info->micvdd, false);
309 if (ret != 0) {
310 dev_err(arizona->dev,
311 "Failed to regulate MICVDD: %d\n",
312 ret);
313 }
314 }
315
Mark Brown9b1270c2013-01-11 08:55:46 +0900316 ret = regulator_enable(info->micvdd);
317 if (ret != 0) {
318 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
319 ret);
320 }
321
322 if (info->micd_reva) {
323 regmap_write(arizona->regmap, 0x80, 0x3);
324 regmap_write(arizona->regmap, 0x294, 0);
325 regmap_write(arizona->regmap, 0x80, 0x0);
326 }
327
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100328 if (info->detecting && arizona->pdata.micd_software_compare)
329 mode = ARIZONA_ACCDET_MODE_ADC;
330 else
331 mode = ARIZONA_ACCDET_MODE_MIC;
332
Mark Brown9b1270c2013-01-11 08:55:46 +0900333 regmap_update_bits(arizona->regmap,
334 ARIZONA_ACCESSORY_DETECT_MODE_1,
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100335 ARIZONA_ACCDET_MODE_MASK, mode);
Mark Brown9b1270c2013-01-11 08:55:46 +0900336
Mark Brownbbbd46e2013-01-10 19:38:43 +0000337 arizona_extcon_pulse_micbias(info);
338
Mark Brown9b1270c2013-01-11 08:55:46 +0900339 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
340 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
341 &change);
342 if (!change) {
343 regulator_disable(info->micvdd);
344 pm_runtime_put_autosuspend(info->dev);
345 }
346}
347
348static void arizona_stop_mic(struct arizona_extcon_info *info)
349{
350 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000351 const char *widget = arizona_extcon_get_micbias(info);
352 struct snd_soc_dapm_context *dapm = arizona->dapm;
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000353 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
Mark Brown9b1270c2013-01-11 08:55:46 +0900354 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000355 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900356
357 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
358 ARIZONA_MICD_ENA, 0,
359 &change);
360
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000361 ret = snd_soc_component_disable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000362 if (ret != 0)
363 dev_warn(arizona->dev,
364 "Failed to disable %s: %d\n",
365 widget, ret);
366
Mark Brownbbbd46e2013-01-10 19:38:43 +0000367 snd_soc_dapm_sync(dapm);
368
Mark Brown9b1270c2013-01-11 08:55:46 +0900369 if (info->micd_reva) {
370 regmap_write(arizona->regmap, 0x80, 0x3);
371 regmap_write(arizona->regmap, 0x294, 2);
372 regmap_write(arizona->regmap, 0x80, 0x0);
373 }
374
Mark Brownbbbd46e2013-01-10 19:38:43 +0000375 ret = regulator_allow_bypass(info->micvdd, true);
376 if (ret != 0) {
377 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
378 ret);
379 }
380
Mark Brown9b1270c2013-01-11 08:55:46 +0900381 if (change) {
382 regulator_disable(info->micvdd);
383 pm_runtime_mark_last_busy(info->dev);
384 pm_runtime_put_autosuspend(info->dev);
385 }
386}
387
Mark Brown4f340332013-01-11 08:55:43 +0900388static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100389 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900390 unsigned int factor_a;
391 unsigned int factor_b;
392} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100393 { 100, 5528, 362464 },
394 { 169, 11084, 6186851 },
395 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900396};
397
Charles Keepax24a279b2014-05-30 13:19:17 +0100398#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
399
Mark Brown4f340332013-01-11 08:55:43 +0900400static struct {
401 int min;
402 int max;
403} arizona_hpdet_c_ranges[] = {
404 { 0, 30 },
405 { 8, 100 },
406 { 100, 1000 },
407 { 1000, 10000 },
408};
409
410static int arizona_hpdet_read(struct arizona_extcon_info *info)
411{
412 struct arizona *arizona = info->arizona;
413 unsigned int val, range;
414 int ret;
415
416 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
417 if (ret != 0) {
418 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
419 ret);
420 return ret;
421 }
422
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100423 switch (info->hpdet_ip_version) {
Mark Brown4f340332013-01-11 08:55:43 +0900424 case 0:
425 if (!(val & ARIZONA_HP_DONE)) {
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 val &= ARIZONA_HP_LVL_MASK;
432 break;
433
434 case 1:
435 if (!(val & ARIZONA_HP_DONE_B)) {
436 dev_err(arizona->dev, "HPDET did not complete: %x\n",
437 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900438 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900439 }
440
441 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
442 if (ret != 0) {
443 dev_err(arizona->dev, "Failed to read HP value: %d\n",
444 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900445 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900446 }
447
448 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
449 &range);
450 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
451 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
452
453 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100454 (val < arizona_hpdet_b_ranges[range].threshold ||
455 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900456 range++;
457 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
458 range);
459 regmap_update_bits(arizona->regmap,
460 ARIZONA_HEADPHONE_DETECT_1,
461 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
462 range <<
463 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
464 return -EAGAIN;
465 }
466
467 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100468 if (val < arizona_hpdet_b_ranges[range].threshold ||
469 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900470 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100471 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900472 }
473
474 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
475 val, range);
476
477 val = arizona_hpdet_b_ranges[range].factor_b
478 / ((val * 100) -
479 arizona_hpdet_b_ranges[range].factor_a);
480 break;
481
Mark Brown4f340332013-01-11 08:55:43 +0900482 case 2:
483 if (!(val & ARIZONA_HP_DONE_B)) {
484 dev_err(arizona->dev, "HPDET did not complete: %x\n",
485 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900486 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900487 }
488
489 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000490 /* Convert to ohms, the value is in 0.5 ohm increments */
491 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900492
493 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
494 &range);
495 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
496 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
497
Charles Keepax91414612013-11-14 16:18:24 +0000498 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900499 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
500 (val >= arizona_hpdet_c_ranges[range].max)) {
501 range++;
502 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
503 arizona_hpdet_c_ranges[range].min,
504 arizona_hpdet_c_ranges[range].max);
505 regmap_update_bits(arizona->regmap,
506 ARIZONA_HEADPHONE_DETECT_1,
507 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
508 range <<
509 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
510 return -EAGAIN;
511 }
Charles Keepax91414612013-11-14 16:18:24 +0000512
513 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
514 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
515 arizona_hpdet_c_ranges[range].min);
516 val = arizona_hpdet_c_ranges[range].min;
517 }
Chanwoo Choie9844b22015-09-29 19:06:31 +0900518 break;
519
520 default:
521 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
522 info->hpdet_ip_version);
523 return -EINVAL;
Mark Brown4f340332013-01-11 08:55:43 +0900524 }
525
526 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
527 return val;
528}
529
Mark Brown9c2ba272013-02-25 23:42:31 +0000530static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
531 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900532{
533 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900534 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900535
536 /*
537 * If we're using HPDET for accessory identification we need
538 * to take multiple measurements, step through them in sequence.
539 */
540 if (arizona->pdata.hpdet_acc_id) {
541 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900542
543 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000544 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900545 dev_dbg(arizona->dev, "Measuring mic\n");
546
547 regmap_update_bits(arizona->regmap,
548 ARIZONA_ACCESSORY_DETECT_MODE_1,
549 ARIZONA_ACCDET_MODE_MASK |
550 ARIZONA_ACCDET_SRC,
551 ARIZONA_ACCDET_MODE_HPR |
552 info->micd_modes[0].src);
553
554 gpio_set_value_cansleep(id_gpio, 1);
555
Mark Browndd235ee2013-01-11 08:55:51 +0900556 regmap_update_bits(arizona->regmap,
557 ARIZONA_HEADPHONE_DETECT_1,
558 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
559 return -EAGAIN;
560 }
561
562 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000563 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
564 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000565
566 /* Take the headphone impedance for the main report */
567 *reading = info->hpdet_res[0];
568
Mark Brown9dd5e532013-04-01 19:09:45 +0100569 /* Sometimes we get false readings due to slow insert */
570 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
571 dev_dbg(arizona->dev, "Retrying high impedance\n");
572 info->num_hpdet_res = 0;
573 info->hpdet_retried = true;
574 arizona_start_hpdet_acc_id(info);
575 pm_runtime_put(info->dev);
576 return -EAGAIN;
577 }
578
Mark Brown1eda6aa2013-01-11 08:55:54 +0900579 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530580 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900581 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000582 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900583 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000584 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000585 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900586 } else {
587 dev_dbg(arizona->dev, "Detected headphone\n");
588 }
589
590 /* Make sure everything is reset back to the real polarity */
591 regmap_update_bits(arizona->regmap,
592 ARIZONA_ACCESSORY_DETECT_MODE_1,
593 ARIZONA_ACCDET_SRC,
594 info->micd_modes[0].src);
595 }
596
597 return 0;
598}
599
Mark Brown4f340332013-01-11 08:55:43 +0900600static irqreturn_t arizona_hpdet_irq(int irq, void *data)
601{
602 struct arizona_extcon_info *info = data;
603 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900604 int id_gpio = arizona->pdata.hpdet_id_gpio;
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900605 unsigned int report = EXTCON_JACK_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900606 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000607 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900608
609 mutex_lock(&info->lock);
610
611 /* If we got a spurious IRQ for some reason then ignore it */
612 if (!info->hpdet_active) {
613 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
614 mutex_unlock(&info->lock);
615 return IRQ_NONE;
616 }
617
618 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900619 ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900620 if (ret < 0) {
621 dev_err(arizona->dev, "Failed to check cable state: %d\n",
622 ret);
623 goto out;
624 } else if (!ret) {
625 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
626 goto done;
627 }
628
629 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900630 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900631 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900632 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900633 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900634 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900635
636 /* Reset back to starting range */
637 regmap_update_bits(arizona->regmap,
638 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900639 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
640 0);
641
Mark Brown9c2ba272013-02-25 23:42:31 +0000642 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900643 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900644 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900645 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900646 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900647
648 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900649 if (reading >= 5000)
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900650 report = EXTCON_JACK_LINE_OUT;
Mark Brown4f340332013-01-11 08:55:43 +0900651 else
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900652 report = EXTCON_JACK_HEADPHONE;
Mark Brown4f340332013-01-11 08:55:43 +0900653
Chanwoo Choi8670b452016-08-16 15:55:34 +0900654 ret = extcon_set_state_sync(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900655 if (ret != 0)
656 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
657 ret);
658
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000659done:
660 /* Reset back to starting range */
661 regmap_update_bits(arizona->regmap,
662 ARIZONA_HEADPHONE_DETECT_1,
663 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
664 0);
665
Charles Keepax112bdfa2015-02-16 15:41:02 +0000666 arizona_extcon_hp_clamp(info, false);
Mark Brown4f340332013-01-11 08:55:43 +0900667
Mark Brown1eda6aa2013-01-11 08:55:54 +0900668 if (id_gpio)
669 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900670
671 /* Revert back to MICDET mode */
672 regmap_update_bits(arizona->regmap,
673 ARIZONA_ACCESSORY_DETECT_MODE_1,
674 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
675
676 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000677 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900678 arizona_start_mic(info);
679
680 if (info->hpdet_active) {
681 pm_runtime_put_autosuspend(info->dev);
682 info->hpdet_active = false;
683 }
684
Mark Brownbf14ee52013-02-05 20:20:17 +0000685 info->hpdet_done = true;
686
Mark Brown4f340332013-01-11 08:55:43 +0900687out:
688 mutex_unlock(&info->lock);
689
690 return IRQ_HANDLED;
691}
692
693static void arizona_identify_headphone(struct arizona_extcon_info *info)
694{
695 struct arizona *arizona = info->arizona;
696 int ret;
697
Mark Brownbf14ee52013-02-05 20:20:17 +0000698 if (info->hpdet_done)
699 return;
700
Mark Brown4f340332013-01-11 08:55:43 +0900701 dev_dbg(arizona->dev, "Starting HPDET\n");
702
703 /* Make sure we keep the device enabled during the measurement */
704 pm_runtime_get(info->dev);
705
706 info->hpdet_active = true;
707
708 if (info->mic)
709 arizona_stop_mic(info);
710
Charles Keepax112bdfa2015-02-16 15:41:02 +0000711 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900712
713 ret = regmap_update_bits(arizona->regmap,
714 ARIZONA_ACCESSORY_DETECT_MODE_1,
715 ARIZONA_ACCDET_MODE_MASK,
Inha Song9e86b2a2015-05-04 13:42:13 +0900716 arizona->pdata.hpdet_channel);
Mark Brown4f340332013-01-11 08:55:43 +0900717 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900718 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +0900719 goto err;
720 }
721
722 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
723 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
724 if (ret != 0) {
725 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
726 ret);
727 goto err;
728 }
729
730 return;
731
732err:
733 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
734 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
735
736 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900737 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900738 if (ret != 0)
739 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
740
741 if (info->mic)
742 arizona_start_mic(info);
743
744 info->hpdet_active = false;
745}
Mark Browndd235ee2013-01-11 08:55:51 +0900746
747static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
748{
749 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000750 int hp_reading = 32;
751 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900752 int ret;
753
754 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
755
756 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000757 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900758
759 info->hpdet_active = true;
760
Charles Keepax112bdfa2015-02-16 15:41:02 +0000761 arizona_extcon_hp_clamp(info, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900762
763 ret = regmap_update_bits(arizona->regmap,
764 ARIZONA_ACCESSORY_DETECT_MODE_1,
765 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
766 info->micd_modes[0].src |
Inha Song9e86b2a2015-05-04 13:42:13 +0900767 arizona->pdata.hpdet_channel);
Mark Browndd235ee2013-01-11 08:55:51 +0900768 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900769 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Browndd235ee2013-01-11 08:55:51 +0900770 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900771 }
772
Mark Brown9c2ba272013-02-25 23:42:31 +0000773 if (arizona->pdata.hpdet_acc_id_line) {
774 ret = regmap_update_bits(arizona->regmap,
775 ARIZONA_HEADPHONE_DETECT_1,
776 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
777 if (ret != 0) {
778 dev_err(arizona->dev,
779 "Can't start HPDETL measurement: %d\n",
780 ret);
781 goto err;
782 }
783 } else {
784 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900785 }
786
787 return;
788
789err:
790 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
791 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
792
793 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900794 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900795 if (ret != 0)
796 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
797
Mark Brown4f340332013-01-11 08:55:43 +0900798 info->hpdet_active = false;
799}
800
Mark Brown939c5672013-04-01 19:17:34 +0100801static void arizona_micd_timeout_work(struct work_struct *work)
802{
803 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900804 struct arizona_extcon_info,
805 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100806
807 mutex_lock(&info->lock);
808
809 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
Mark Brown939c5672013-04-01 19:17:34 +0100810
811 info->detecting = false;
812
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100813 arizona_identify_headphone(info);
814
Mark Brown939c5672013-04-01 19:17:34 +0100815 arizona_stop_mic(info);
816
817 mutex_unlock(&info->lock);
818}
819
Mark Browncd59e792013-04-01 19:21:48 +0100820static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100821{
Mark Browncd59e792013-04-01 19:21:48 +0100822 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900823 struct arizona_extcon_info,
824 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100825 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100826 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100827 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100828
Mark Brown939c5672013-04-01 19:17:34 +0100829 cancel_delayed_work_sync(&info->micd_timeout_work);
830
Mark Brownf2c32a82012-06-24 12:09:45 +0100831 mutex_lock(&info->lock);
832
Charles Keepax31a847e2013-11-14 16:18:23 +0000833 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900834 ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000835 if (ret < 0) {
836 dev_err(arizona->dev, "Failed to check cable state: %d\n",
837 ret);
838 mutex_unlock(&info->lock);
839 return;
840 } else if (!ret) {
841 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
842 mutex_unlock(&info->lock);
843 return;
844 }
845
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100846 if (info->detecting && arizona->pdata.micd_software_compare) {
847 /* Must disable MICD before we read the ADCVAL */
848 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
849 ARIZONA_MICD_ENA, 0);
850 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
851 if (ret != 0) {
852 dev_err(arizona->dev,
853 "Failed to read MICDET_ADCVAL: %d\n",
854 ret);
855 mutex_unlock(&info->lock);
856 return;
857 }
858
859 dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
860
861 val &= ARIZONA_MICDET_ADCVAL_MASK;
862 if (val < ARRAY_SIZE(arizona_micd_levels))
863 val = arizona_micd_levels[val];
864 else
865 val = INT_MAX;
866
867 if (val <= QUICK_HEADPHONE_MAX_OHM)
868 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
869 else if (val <= MICROPHONE_MIN_OHM)
870 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
871 else if (val <= MICROPHONE_MAX_OHM)
872 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
873 else
874 val = ARIZONA_MICD_LVL_8;
875 }
876
Charles Keepaxffae24f2013-11-14 16:18:21 +0000877 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100878 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
879 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900880 dev_err(arizona->dev,
881 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100882 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100883 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100884 }
885
886 dev_dbg(arizona->dev, "MICDET: %x\n", val);
887
888 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900889 dev_warn(arizona->dev,
890 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100891 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100892 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100893 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100894 }
895
Charles Keepaxffae24f2013-11-14 16:18:21 +0000896 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100897 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100898 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100899 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100900 }
901
902 /* Due to jack detect this should never happen */
903 if (!(val & ARIZONA_MICD_STS)) {
904 dev_warn(arizona->dev, "Detected open circuit\n");
Charles Keepax57f70ef2015-06-25 16:47:02 +0100905 info->mic = false;
906 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100907 info->detecting = false;
Charles Keepax57f70ef2015-06-25 16:47:02 +0100908 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100909 goto handled;
910 }
911
912 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000913 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100914 info->mic = true;
915 info->detecting = false;
916
Mark Brown4f340332013-01-11 08:55:43 +0900917 arizona_identify_headphone(info);
918
Chanwoo Choi8670b452016-08-16 15:55:34 +0900919 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900920 EXTCON_JACK_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100921 if (ret != 0)
922 dev_err(arizona->dev, "Headset report failed: %d\n",
923 ret);
924
Mark Brownbbbd46e2013-01-10 19:38:43 +0000925 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100926 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000927 if (ret != 0) {
928 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
929 ret);
930 }
931
Mark Brownf2c32a82012-06-24 12:09:45 +0100932 goto handled;
933 }
934
935 /* If we detected a lower impedence during initial startup
936 * then we probably have the wrong polarity, flip it. Don't
937 * do this for the lowest impedences to speed up detection of
938 * plain headphones. If both polarities report a low
939 * impedence then give up and report headphones.
940 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000941 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800942 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900943 dev_dbg(arizona->dev, "Detected HP/line\n");
Mark Brown9ef2224d2012-06-28 13:08:31 +0100944
Mark Brown4f340332013-01-11 08:55:43 +0900945 info->detecting = false;
946
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100947 arizona_identify_headphone(info);
948
Mark Brown4f340332013-01-11 08:55:43 +0900949 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100950 } else {
951 info->micd_mode++;
952 if (info->micd_mode == info->micd_num_modes)
953 info->micd_mode = 0;
954 arizona_extcon_set_mode(info, info->micd_mode);
955
956 info->jack_flips++;
957 }
958
959 goto handled;
960 }
961
962 /*
963 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100964 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100965 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000966 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100967 if (info->mic) {
968 dev_dbg(arizona->dev, "Mic button detected\n");
969
Mark Brown34efe4d2012-07-20 17:07:29 +0100970 lvl = val & ARIZONA_MICD_LVL_MASK;
971 lvl >>= ARIZONA_MICD_LVL_SHIFT;
972
Mark Brown41a57852013-04-01 19:18:18 +0100973 for (i = 0; i < info->num_micd_ranges; i++)
974 input_report_key(info->input,
975 info->micd_ranges[i].key, 0);
976
Mark Brown6fed4d82013-04-01 22:03:06 +0100977 WARN_ON(!lvl);
978 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
979 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
980 key = info->micd_ranges[ffs(lvl) - 1].key;
981 input_report_key(info->input, key, 1);
982 input_sync(info->input);
983 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100984
Mark Brownf2c32a82012-06-24 12:09:45 +0100985 } else if (info->detecting) {
986 dev_dbg(arizona->dev, "Headphone detected\n");
987 info->detecting = false;
988 arizona_stop_mic(info);
989
Mark Brown4f340332013-01-11 08:55:43 +0900990 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100991 } else {
992 dev_warn(arizona->dev, "Button with no mic: %x\n",
993 val);
994 }
995 } else {
996 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100997 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100998 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100999 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001000 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +00001001 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001002 }
1003
1004handled:
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001005 if (info->detecting) {
1006 if (arizona->pdata.micd_software_compare)
1007 regmap_update_bits(arizona->regmap,
1008 ARIZONA_MIC_DETECT_1,
1009 ARIZONA_MICD_ENA,
1010 ARIZONA_MICD_ENA);
1011
Mark Browndf9a5ab2013-07-18 22:42:22 +01001012 queue_delayed_work(system_power_efficient_wq,
1013 &info->micd_timeout_work,
1014 msecs_to_jiffies(info->micd_timeout));
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001015 }
Mark Brown939c5672013-04-01 19:17:34 +01001016
Mark Brownf2c32a82012-06-24 12:09:45 +01001017 pm_runtime_mark_last_busy(info->dev);
1018 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +01001019}
1020
1021static irqreturn_t arizona_micdet(int irq, void *data)
1022{
1023 struct arizona_extcon_info *info = data;
1024 struct arizona *arizona = info->arizona;
1025 int debounce = arizona->pdata.micd_detect_debounce;
1026
1027 cancel_delayed_work_sync(&info->micd_detect_work);
1028 cancel_delayed_work_sync(&info->micd_timeout_work);
1029
1030 mutex_lock(&info->lock);
1031 if (!info->detecting)
1032 debounce = 0;
1033 mutex_unlock(&info->lock);
1034
1035 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001036 queue_delayed_work(system_power_efficient_wq,
1037 &info->micd_detect_work,
1038 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +01001039 else
1040 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001041
1042 return IRQ_HANDLED;
1043}
1044
Mark Brown0e27bd32013-02-05 21:00:15 +00001045static void arizona_hpdet_work(struct work_struct *work)
1046{
1047 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001048 struct arizona_extcon_info,
1049 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +00001050
1051 mutex_lock(&info->lock);
1052 arizona_start_hpdet_acc_id(info);
1053 mutex_unlock(&info->lock);
1054}
1055
Mark Brownf2c32a82012-06-24 12:09:45 +01001056static irqreturn_t arizona_jackdet(int irq, void *data)
1057{
1058 struct arizona_extcon_info *info = data;
1059 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001060 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +01001061 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +01001062 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +01001063
Mark Brown939c5672013-04-01 19:17:34 +01001064 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
1065 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001066
Mark Browna3e20782013-04-01 19:05:27 +01001067 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +00001068
Mark Brownf2c32a82012-06-24 12:09:45 +01001069 mutex_lock(&info->lock);
1070
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001071 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001072 mask = ARIZONA_MICD_CLAMP_STS;
Nariman Poushina0ef6422015-09-16 10:42:19 +01001073 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +09001074 } else {
1075 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001076 if (arizona->pdata.jd_invert)
1077 present = 0;
1078 else
1079 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +09001080 }
1081
Mark Brownf2c32a82012-06-24 12:09:45 +01001082 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
1083 if (ret != 0) {
1084 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
1085 ret);
1086 mutex_unlock(&info->lock);
1087 pm_runtime_put_autosuspend(info->dev);
1088 return IRQ_NONE;
1089 }
1090
Mark Browna3e20782013-04-01 19:05:27 +01001091 val &= mask;
1092 if (val == info->last_jackdet) {
1093 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001094 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001095 queue_delayed_work(system_power_efficient_wq,
1096 &info->hpdet_work,
1097 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001098
Chanwoo Choic2275d22013-08-23 10:21:37 +09001099 if (cancelled_mic) {
1100 int micd_timeout = info->micd_timeout;
1101
Mark Browndf9a5ab2013-07-18 22:42:22 +01001102 queue_delayed_work(system_power_efficient_wq,
1103 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001104 msecs_to_jiffies(micd_timeout));
1105 }
Mark Brown939c5672013-04-01 19:17:34 +01001106
Mark Browna3e20782013-04-01 19:05:27 +01001107 goto out;
1108 }
1109 info->last_jackdet = val;
1110
1111 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001112 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choi8670b452016-08-16 15:55:34 +09001113 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +09001114 EXTCON_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001115
1116 if (ret != 0)
1117 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1118 ret);
1119
Mark Browndd235ee2013-01-11 08:55:51 +09001120 if (!arizona->pdata.hpdet_acc_id) {
1121 info->detecting = true;
1122 info->mic = false;
1123 info->jack_flips = 0;
1124
1125 arizona_start_mic(info);
1126 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001127 queue_delayed_work(system_power_efficient_wq,
1128 &info->hpdet_work,
1129 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001130 }
Mark Brown4e616872013-01-15 22:09:20 +09001131
Charles Keepax6c20b932015-09-16 10:42:21 +01001132 if (info->micd_clamp || !arizona->pdata.jd_invert)
1133 regmap_update_bits(arizona->regmap,
1134 ARIZONA_JACK_DETECT_DEBOUNCE,
1135 ARIZONA_MICD_CLAMP_DB |
1136 ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001137 } else {
1138 dev_dbg(arizona->dev, "Detected jack removal\n");
1139
1140 arizona_stop_mic(info);
1141
Mark Browndd235ee2013-01-11 08:55:51 +09001142 info->num_hpdet_res = 0;
1143 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1144 info->hpdet_res[i] = 0;
1145 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001146 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001147 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001148
Mark Brown6fed4d82013-04-01 22:03:06 +01001149 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001150 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001151 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001152 input_sync(info->input);
1153
Chanwoo Choi5475e632016-07-01 02:36:49 +09001154 for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) {
Chanwoo Choi8670b452016-08-16 15:55:34 +09001155 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi5475e632016-07-01 02:36:49 +09001156 arizona_cable[i], false);
1157 if (ret != 0)
1158 dev_err(arizona->dev,
1159 "Removal report failed: %d\n", ret);
1160 }
Mark Brown4e616872013-01-15 22:09:20 +09001161
1162 regmap_update_bits(arizona->regmap,
1163 ARIZONA_JACK_DETECT_DEBOUNCE,
1164 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1165 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001166 }
1167
Mark Brown7abd4e22013-04-01 19:25:55 +01001168 if (arizona->pdata.micd_timeout)
1169 info->micd_timeout = arizona->pdata.micd_timeout;
1170 else
1171 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1172
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001173out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001174 /* Clear trig_sts to make sure DCVDD is not forced up */
1175 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1176 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1177 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1178 ARIZONA_JD1_FALL_TRIG_STS |
1179 ARIZONA_JD1_RISE_TRIG_STS);
1180
Mark Brownf2c32a82012-06-24 12:09:45 +01001181 mutex_unlock(&info->lock);
1182
1183 pm_runtime_mark_last_busy(info->dev);
1184 pm_runtime_put_autosuspend(info->dev);
1185
1186 return IRQ_HANDLED;
1187}
1188
Mark Brown6fed4d82013-04-01 22:03:06 +01001189/* Map a level onto a slot in the register bank */
1190static void arizona_micd_set_level(struct arizona *arizona, int index,
1191 unsigned int level)
1192{
1193 int reg;
1194 unsigned int mask;
1195
1196 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1197
1198 if (!(index % 2)) {
1199 mask = 0x3f00;
1200 level <<= 8;
1201 } else {
1202 mask = 0x3f;
1203 }
1204
1205 /* Program the level itself */
1206 regmap_update_bits(arizona->regmap, reg, mask, level);
1207}
1208
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001209static int arizona_extcon_get_micd_configs(struct device *dev,
1210 struct arizona *arizona)
1211{
1212 const char * const prop = "wlf,micd-configs";
1213 const int entries_per_config = 3;
1214 struct arizona_micd_config *micd_configs;
1215 int nconfs, ret;
1216 int i, j;
1217 u32 *vals;
1218
1219 nconfs = device_property_read_u32_array(arizona->dev, prop, NULL, 0);
1220 if (nconfs <= 0)
1221 return 0;
1222
1223 vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
1224 if (!vals)
1225 return -ENOMEM;
1226
1227 ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
1228 if (ret < 0)
1229 goto out;
1230
1231 nconfs /= entries_per_config;
1232
1233 micd_configs = devm_kzalloc(dev,
1234 nconfs * sizeof(struct arizona_micd_range),
1235 GFP_KERNEL);
1236 if (!micd_configs) {
1237 ret = -ENOMEM;
1238 goto out;
1239 }
1240
1241 for (i = 0, j = 0; i < nconfs; ++i) {
1242 micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
1243 micd_configs[i].bias = vals[j++];
1244 micd_configs[i].gpio = vals[j++];
1245 }
1246
1247 arizona->pdata.micd_configs = micd_configs;
1248 arizona->pdata.num_micd_configs = nconfs;
1249
1250out:
1251 kfree(vals);
1252 return ret;
1253}
1254
1255static int arizona_extcon_device_get_pdata(struct device *dev,
1256 struct arizona *arizona)
Inha Song9e86b2a2015-05-04 13:42:13 +09001257{
1258 struct arizona_pdata *pdata = &arizona->pdata;
1259 unsigned int val = ARIZONA_ACCDET_MODE_HPL;
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001260 int ret;
Inha Song9e86b2a2015-05-04 13:42:13 +09001261
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001262 device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
Inha Song9e86b2a2015-05-04 13:42:13 +09001263 switch (val) {
1264 case ARIZONA_ACCDET_MODE_HPL:
1265 case ARIZONA_ACCDET_MODE_HPR:
1266 pdata->hpdet_channel = val;
1267 break;
1268 default:
1269 dev_err(arizona->dev,
1270 "Wrong wlf,hpdet-channel DT value %d\n", val);
1271 pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
1272 }
1273
Charles Keepax4778d442015-06-19 17:23:30 +01001274 device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
1275 &pdata->micd_detect_debounce);
1276
1277 device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
1278 &pdata->micd_bias_start_time);
1279
1280 device_property_read_u32(arizona->dev, "wlf,micd-rate",
1281 &pdata->micd_rate);
1282
1283 device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
1284 &pdata->micd_dbtime);
1285
Charles Keepax7a7ef0f2015-11-23 14:51:30 +00001286 device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
Charles Keepax4778d442015-06-19 17:23:30 +01001287 &pdata->micd_timeout);
1288
1289 pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
1290 "wlf,micd-force-micbias");
1291
Charles Keepax2e87b7a2015-11-19 15:45:35 +00001292 pdata->micd_software_compare = device_property_read_bool(arizona->dev,
1293 "wlf,micd-software-compare");
1294
Charles Keepax3d7a8722015-11-19 15:45:37 +00001295 pdata->jd_invert = device_property_read_bool(arizona->dev,
1296 "wlf,jd-invert");
1297
Charles Keepax99374222015-11-19 15:45:36 +00001298 device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
1299
Charles Keepax35247c12015-11-19 15:45:38 +00001300 pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001301 "wlf,use-jd2");
Charles Keepax35247c12015-11-19 15:45:38 +00001302 pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001303 "wlf,use-jd2-nopull");
Charles Keepax35247c12015-11-19 15:45:38 +00001304
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001305 ret = arizona_extcon_get_micd_configs(dev, arizona);
1306 if (ret < 0)
1307 dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
1308
Inha Song9e86b2a2015-05-04 13:42:13 +09001309 return 0;
1310}
1311
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001312static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001313{
1314 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001315 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001316 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001317 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001318 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001319 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001320 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001321
Mark Brownbbbd46e2013-01-10 19:38:43 +00001322 if (!arizona->dapm || !arizona->dapm->card)
1323 return -EPROBE_DEFER;
1324
Mark Brownf2c32a82012-06-24 12:09:45 +01001325 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001326 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001327 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001328
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001329 if (!dev_get_platdata(arizona->dev))
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001330 arizona_extcon_device_get_pdata(&pdev->dev, arizona);
Inha Song9e86b2a2015-05-04 13:42:13 +09001331
Charles Keepax17271f62014-07-18 12:59:00 +01001332 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001333 if (IS_ERR(info->micvdd)) {
1334 ret = PTR_ERR(info->micvdd);
1335 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001336 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001337 }
1338
1339 mutex_init(&info->lock);
1340 info->arizona = arizona;
1341 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001342 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001343 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001344 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001345 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001346 platform_set_drvdata(pdev, info);
1347
1348 switch (arizona->type) {
1349 case WM5102:
1350 switch (arizona->rev) {
1351 case 0:
1352 info->micd_reva = true;
1353 break;
1354 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001355 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001356 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001357 break;
1358 }
1359 break;
Charles Keepax77438612013-11-14 16:18:25 +00001360 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001361 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001362 switch (arizona->rev) {
1363 case 0 ... 2:
1364 break;
1365 default:
1366 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001367 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001368 break;
1369 }
1370 break;
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +01001371 case WM8998:
1372 case WM1814:
1373 info->micd_clamp = true;
1374 info->hpdet_ip_version = 2;
1375 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001376 default:
1377 break;
1378 }
1379
Chanwoo Choief70a212014-04-21 20:47:31 +09001380 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1381 if (IS_ERR(info->edev)) {
1382 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1383 return -ENOMEM;
1384 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001385
Chanwoo Choief70a212014-04-21 20:47:31 +09001386 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001387 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001388 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001389 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001390 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001391 }
1392
Mark Brown6fed4d82013-04-01 22:03:06 +01001393 info->input = devm_input_allocate_device(&pdev->dev);
1394 if (!info->input) {
1395 dev_err(arizona->dev, "Can't allocate input dev\n");
1396 ret = -ENOMEM;
1397 goto err_register;
1398 }
1399
1400 info->input->name = "Headset";
1401 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001402
Mark Brownf2c32a82012-06-24 12:09:45 +01001403 if (pdata->num_micd_configs) {
1404 info->micd_modes = pdata->micd_configs;
1405 info->micd_num_modes = pdata->num_micd_configs;
1406 } else {
1407 info->micd_modes = micd_default_modes;
1408 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1409 }
1410
Charles Keepax6772a5a2015-09-16 10:42:17 +01001411 if (arizona->pdata.gpsw > 0)
1412 regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
1413 ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
1414
Mark Brownf2c32a82012-06-24 12:09:45 +01001415 if (arizona->pdata.micd_pol_gpio > 0) {
1416 if (info->micd_modes[0].gpio)
1417 mode = GPIOF_OUT_INIT_HIGH;
1418 else
1419 mode = GPIOF_OUT_INIT_LOW;
1420
1421 ret = devm_gpio_request_one(&pdev->dev,
1422 arizona->pdata.micd_pol_gpio,
1423 mode,
1424 "MICD polarity");
1425 if (ret != 0) {
1426 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1427 arizona->pdata.micd_pol_gpio, ret);
1428 goto err_register;
1429 }
Charles Keepax8e5838d2015-06-19 17:23:31 +01001430 } else {
1431 if (info->micd_modes[0].gpio)
1432 mode = GPIOD_OUT_HIGH;
1433 else
1434 mode = GPIOD_OUT_LOW;
1435
1436 /* We can't use devm here because we need to do the get
1437 * against the MFD device, as that is where the of_node
1438 * will reside, but if we devm against that the GPIO
1439 * will not be freed if the extcon driver is unloaded.
1440 */
1441 info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
1442 "wlf,micd-pol",
1443 GPIOD_OUT_LOW);
1444 if (IS_ERR(info->micd_pol_gpio)) {
1445 ret = PTR_ERR(info->micd_pol_gpio);
1446 dev_err(arizona->dev,
1447 "Failed to get microphone polarity GPIO: %d\n",
1448 ret);
1449 goto err_register;
1450 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001451 }
1452
Mark Brown1eda6aa2013-01-11 08:55:54 +09001453 if (arizona->pdata.hpdet_id_gpio > 0) {
1454 ret = devm_gpio_request_one(&pdev->dev,
1455 arizona->pdata.hpdet_id_gpio,
1456 GPIOF_OUT_INIT_LOW,
1457 "HPDET");
1458 if (ret != 0) {
1459 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1460 arizona->pdata.hpdet_id_gpio, ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001461 goto err_gpio;
Mark Brown1eda6aa2013-01-11 08:55:54 +09001462 }
1463 }
1464
Mark Brownb17e5462013-01-11 08:55:24 +09001465 if (arizona->pdata.micd_bias_start_time)
1466 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1467 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1468 arizona->pdata.micd_bias_start_time
1469 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1470
Mark Brown2e033db2013-01-21 17:36:33 +09001471 if (arizona->pdata.micd_rate)
1472 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1473 ARIZONA_MICD_RATE_MASK,
1474 arizona->pdata.micd_rate
1475 << ARIZONA_MICD_RATE_SHIFT);
1476
Charles Keepaxbb327e92015-06-30 13:32:39 +01001477 switch (arizona->pdata.micd_dbtime) {
1478 case MICD_DBTIME_FOUR_READINGS:
Mark Brown2e033db2013-01-21 17:36:33 +09001479 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1480 ARIZONA_MICD_DBTIME_MASK,
Charles Keepaxbb327e92015-06-30 13:32:39 +01001481 ARIZONA_MICD_DBTIME);
1482 break;
1483 case MICD_DBTIME_TWO_READINGS:
1484 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1485 ARIZONA_MICD_DBTIME_MASK, 0);
1486 break;
1487 default:
1488 break;
1489 }
Mark Brown2e033db2013-01-21 17:36:33 +09001490
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001491 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) <
1492 ARIZONA_NUM_MICD_BUTTON_LEVELS);
Mark Brown6fed4d82013-04-01 22:03:06 +01001493
1494 if (arizona->pdata.num_micd_ranges) {
1495 info->micd_ranges = pdata->micd_ranges;
1496 info->num_micd_ranges = pdata->num_micd_ranges;
1497 } else {
1498 info->micd_ranges = micd_default_ranges;
1499 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1500 }
1501
1502 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1503 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1504 arizona->pdata.num_micd_ranges);
1505 }
1506
1507 if (info->num_micd_ranges > 1) {
1508 for (i = 1; i < info->num_micd_ranges; i++) {
1509 if (info->micd_ranges[i - 1].max >
1510 info->micd_ranges[i].max) {
1511 dev_err(arizona->dev,
1512 "MICD ranges must be sorted\n");
1513 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001514 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001515 }
1516 }
1517 }
1518
1519 /* Disable all buttons by default */
1520 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1521 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1522
1523 /* Set up all the buttons the user specified */
1524 for (i = 0; i < info->num_micd_ranges; i++) {
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001525 for (j = 0; j < ARIZONA_NUM_MICD_BUTTON_LEVELS; j++)
Mark Brown6fed4d82013-04-01 22:03:06 +01001526 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1527 break;
1528
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001529 if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
Mark Brown6fed4d82013-04-01 22:03:06 +01001530 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1531 info->micd_ranges[i].max);
1532 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001533 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001534 }
1535
1536 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1537 arizona_micd_levels[j], i);
1538
1539 arizona_micd_set_level(arizona, i, j);
1540 input_set_capability(info->input, EV_KEY,
1541 info->micd_ranges[i].key);
1542
1543 /* Enable reporting of that range */
1544 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1545 1 << i, 1 << i);
1546 }
1547
1548 /* Set all the remaining keys to a maximum */
1549 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1550 arizona_micd_set_level(arizona, i, 0x3f);
1551
Mark Browndab63eb2013-01-11 08:55:36 +09001552 /*
Mark Brown92a49872013-01-11 08:55:39 +09001553 * If we have a clamp use it, activating in conjunction with
1554 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001555 */
1556 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001557 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001558 /* Put the GPIO into input mode with optional pull */
1559 val = 0xc101;
1560 if (arizona->pdata.jd_gpio5_nopull)
1561 val &= ~ARIZONA_GPN_PU;
1562
Mark Brown92a49872013-01-11 08:55:39 +09001563 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001564 val);
Mark Brown92a49872013-01-11 08:55:39 +09001565
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001566 if (arizona->pdata.jd_invert)
1567 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1568 else
1569 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001570 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001571 if (arizona->pdata.jd_invert)
1572 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1573 else
1574 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001575 }
1576
Mark Browndab63eb2013-01-11 08:55:36 +09001577 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001578 ARIZONA_MICD_CLAMP_CONTROL,
1579 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1580
1581 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001582 ARIZONA_JACK_DETECT_DEBOUNCE,
1583 ARIZONA_MICD_CLAMP_DB,
1584 ARIZONA_MICD_CLAMP_DB);
1585 }
1586
Mark Brownf2c32a82012-06-24 12:09:45 +01001587 arizona_extcon_set_mode(info, 0);
1588
1589 pm_runtime_enable(&pdev->dev);
1590 pm_runtime_idle(&pdev->dev);
1591 pm_runtime_get_sync(&pdev->dev);
1592
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001593 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001594 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1595 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1596 } else {
1597 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1598 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1599 }
1600
1601 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001602 "JACKDET rise", arizona_jackdet, info);
1603 if (ret != 0) {
1604 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1605 ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001606 goto err_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +01001607 }
1608
Mark Brown92a49872013-01-11 08:55:39 +09001609 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001610 if (ret != 0) {
1611 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1612 ret);
1613 goto err_rise;
1614 }
1615
Mark Brown92a49872013-01-11 08:55:39 +09001616 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001617 "JACKDET fall", arizona_jackdet, info);
1618 if (ret != 0) {
1619 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1620 goto err_rise_wake;
1621 }
1622
Mark Brown92a49872013-01-11 08:55:39 +09001623 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001624 if (ret != 0) {
1625 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1626 ret);
1627 goto err_fall;
1628 }
1629
1630 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1631 "MICDET", arizona_micdet, info);
1632 if (ret != 0) {
1633 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1634 goto err_fall_wake;
1635 }
1636
Mark Brown4f340332013-01-11 08:55:43 +09001637 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1638 "HPDET", arizona_hpdet_irq, info);
1639 if (ret != 0) {
1640 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1641 goto err_micdet;
1642 }
1643
Mark Brownf2c32a82012-06-24 12:09:45 +01001644 arizona_clk32k_enable(arizona);
1645 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1646 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1647 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1648 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1649
Mark Brownb8575a12012-09-07 17:01:15 +08001650 ret = regulator_allow_bypass(info->micvdd, true);
1651 if (ret != 0)
1652 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1653 ret);
1654
Mark Brownf2c32a82012-06-24 12:09:45 +01001655 pm_runtime_put(&pdev->dev);
1656
Mark Brown34efe4d2012-07-20 17:07:29 +01001657 ret = input_register_device(info->input);
1658 if (ret) {
1659 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001660 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001661 }
1662
Mark Brownf2c32a82012-06-24 12:09:45 +01001663 return 0;
1664
Mark Brown4f340332013-01-11 08:55:43 +09001665err_hpdet:
1666 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001667err_micdet:
1668 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001669err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001670 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001671err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001672 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001673err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001674 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001675err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001676 arizona_free_irq(arizona, jack_irq_rise, info);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001677err_gpio:
1678 gpiod_put(info->micd_pol_gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +01001679err_register:
1680 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001681 return ret;
1682}
1683
Bill Pemberton93ed0322012-11-19 13:25:49 -05001684static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001685{
1686 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1687 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001688 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001689
Charles Keepax8e5838d2015-06-19 17:23:31 +01001690 gpiod_put(info->micd_pol_gpio);
1691
Mark Brownf2c32a82012-06-24 12:09:45 +01001692 pm_runtime_disable(&pdev->dev);
1693
Mark Browndab63eb2013-01-11 08:55:36 +09001694 regmap_update_bits(arizona->regmap,
1695 ARIZONA_MICD_CLAMP_CONTROL,
1696 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1697
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001698 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001699 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1700 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1701 } else {
1702 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1703 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1704 }
1705
1706 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1707 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1708 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001709 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001710 arizona_free_irq(arizona, jack_irq_rise, info);
1711 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001712 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001713 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1714 ARIZONA_JD1_ENA, 0);
1715 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001716
1717 return 0;
1718}
1719
1720static struct platform_driver arizona_extcon_driver = {
1721 .driver = {
1722 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001723 },
1724 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001725 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001726};
1727
1728module_platform_driver(arizona_extcon_driver);
1729
1730MODULE_DESCRIPTION("Arizona Extcon driver");
1731MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1732MODULE_LICENSE("GPL");
1733MODULE_ALIAS("platform:extcon-arizona");