blob: 4c0b6df8b5ddbcbca9d494dc9475f31bfaae4e09 [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;
277 int ret;
278
Mark Brownbbbd46e2013-01-10 19:38:43 +0000279 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
280 if (ret != 0)
281 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
282 widget, ret);
283
Mark Brownbbbd46e2013-01-10 19:38:43 +0000284 snd_soc_dapm_sync(dapm);
285
286 if (!arizona->pdata.micd_force_micbias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000287 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
288 if (ret != 0)
289 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
290 widget, ret);
291
Mark Brownbbbd46e2013-01-10 19:38:43 +0000292 snd_soc_dapm_sync(dapm);
293 }
294}
295
Mark Brown9b1270c2013-01-11 08:55:46 +0900296static void arizona_start_mic(struct arizona_extcon_info *info)
297{
298 struct arizona *arizona = info->arizona;
299 bool change;
300 int ret;
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100301 unsigned int mode;
Mark Brown9b1270c2013-01-11 08:55:46 +0900302
Mark Brown9b1270c2013-01-11 08:55:46 +0900303 /* Microphone detection can't use idle mode */
304 pm_runtime_get(info->dev);
305
Mark Brownbbbd46e2013-01-10 19:38:43 +0000306 if (info->detecting) {
307 ret = regulator_allow_bypass(info->micvdd, false);
308 if (ret != 0) {
309 dev_err(arizona->dev,
310 "Failed to regulate MICVDD: %d\n",
311 ret);
312 }
313 }
314
Mark Brown9b1270c2013-01-11 08:55:46 +0900315 ret = regulator_enable(info->micvdd);
316 if (ret != 0) {
317 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
318 ret);
319 }
320
321 if (info->micd_reva) {
322 regmap_write(arizona->regmap, 0x80, 0x3);
323 regmap_write(arizona->regmap, 0x294, 0);
324 regmap_write(arizona->regmap, 0x80, 0x0);
325 }
326
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100327 if (info->detecting && arizona->pdata.micd_software_compare)
328 mode = ARIZONA_ACCDET_MODE_ADC;
329 else
330 mode = ARIZONA_ACCDET_MODE_MIC;
331
Mark Brown9b1270c2013-01-11 08:55:46 +0900332 regmap_update_bits(arizona->regmap,
333 ARIZONA_ACCESSORY_DETECT_MODE_1,
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100334 ARIZONA_ACCDET_MODE_MASK, mode);
Mark Brown9b1270c2013-01-11 08:55:46 +0900335
Mark Brownbbbd46e2013-01-10 19:38:43 +0000336 arizona_extcon_pulse_micbias(info);
337
Mark Brown9b1270c2013-01-11 08:55:46 +0900338 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
339 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
340 &change);
341 if (!change) {
342 regulator_disable(info->micvdd);
343 pm_runtime_put_autosuspend(info->dev);
344 }
345}
346
347static void arizona_stop_mic(struct arizona_extcon_info *info)
348{
349 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000350 const char *widget = arizona_extcon_get_micbias(info);
351 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900352 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000353 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900354
355 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
356 ARIZONA_MICD_ENA, 0,
357 &change);
358
Mark Brownbbbd46e2013-01-10 19:38:43 +0000359 ret = snd_soc_dapm_disable_pin(dapm, widget);
360 if (ret != 0)
361 dev_warn(arizona->dev,
362 "Failed to disable %s: %d\n",
363 widget, ret);
364
Mark Brownbbbd46e2013-01-10 19:38:43 +0000365 snd_soc_dapm_sync(dapm);
366
Mark Brown9b1270c2013-01-11 08:55:46 +0900367 if (info->micd_reva) {
368 regmap_write(arizona->regmap, 0x80, 0x3);
369 regmap_write(arizona->regmap, 0x294, 2);
370 regmap_write(arizona->regmap, 0x80, 0x0);
371 }
372
Mark Brownbbbd46e2013-01-10 19:38:43 +0000373 ret = regulator_allow_bypass(info->micvdd, true);
374 if (ret != 0) {
375 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
376 ret);
377 }
378
Mark Brown9b1270c2013-01-11 08:55:46 +0900379 if (change) {
380 regulator_disable(info->micvdd);
381 pm_runtime_mark_last_busy(info->dev);
382 pm_runtime_put_autosuspend(info->dev);
383 }
384}
385
Mark Brown4f340332013-01-11 08:55:43 +0900386static struct {
Charles Keepax24a279b2014-05-30 13:19:17 +0100387 unsigned int threshold;
Mark Brown4f340332013-01-11 08:55:43 +0900388 unsigned int factor_a;
389 unsigned int factor_b;
390} arizona_hpdet_b_ranges[] = {
Charles Keepax24a279b2014-05-30 13:19:17 +0100391 { 100, 5528, 362464 },
392 { 169, 11084, 6186851 },
393 { 169, 11065, 65460395 },
Mark Brown4f340332013-01-11 08:55:43 +0900394};
395
Charles Keepax24a279b2014-05-30 13:19:17 +0100396#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
397
Mark Brown4f340332013-01-11 08:55:43 +0900398static struct {
399 int min;
400 int max;
401} arizona_hpdet_c_ranges[] = {
402 { 0, 30 },
403 { 8, 100 },
404 { 100, 1000 },
405 { 1000, 10000 },
406};
407
408static int arizona_hpdet_read(struct arizona_extcon_info *info)
409{
410 struct arizona *arizona = info->arizona;
411 unsigned int val, range;
412 int ret;
413
414 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
415 if (ret != 0) {
416 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
417 ret);
418 return ret;
419 }
420
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +0100421 switch (info->hpdet_ip_version) {
Mark Brown4f340332013-01-11 08:55:43 +0900422 case 0:
423 if (!(val & ARIZONA_HP_DONE)) {
424 dev_err(arizona->dev, "HPDET did not complete: %x\n",
425 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900426 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900427 }
428
429 val &= ARIZONA_HP_LVL_MASK;
430 break;
431
432 case 1:
433 if (!(val & ARIZONA_HP_DONE_B)) {
434 dev_err(arizona->dev, "HPDET did not complete: %x\n",
435 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900436 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900437 }
438
439 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
440 if (ret != 0) {
441 dev_err(arizona->dev, "Failed to read HP value: %d\n",
442 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900443 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900444 }
445
446 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
447 &range);
448 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
449 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
450
451 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax24a279b2014-05-30 13:19:17 +0100452 (val < arizona_hpdet_b_ranges[range].threshold ||
453 val >= ARIZONA_HPDET_B_RANGE_MAX)) {
Mark Brown4f340332013-01-11 08:55:43 +0900454 range++;
455 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
456 range);
457 regmap_update_bits(arizona->regmap,
458 ARIZONA_HEADPHONE_DETECT_1,
459 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
460 range <<
461 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
462 return -EAGAIN;
463 }
464
465 /* If we go out of range report top of range */
Charles Keepax24a279b2014-05-30 13:19:17 +0100466 if (val < arizona_hpdet_b_ranges[range].threshold ||
467 val >= ARIZONA_HPDET_B_RANGE_MAX) {
Mark Brown4f340332013-01-11 08:55:43 +0900468 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100469 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900470 }
471
472 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
473 val, range);
474
475 val = arizona_hpdet_b_ranges[range].factor_b
476 / ((val * 100) -
477 arizona_hpdet_b_ranges[range].factor_a);
478 break;
479
Mark Brown4f340332013-01-11 08:55:43 +0900480 case 2:
481 if (!(val & ARIZONA_HP_DONE_B)) {
482 dev_err(arizona->dev, "HPDET did not complete: %x\n",
483 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900484 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900485 }
486
487 val &= ARIZONA_HP_LVL_B_MASK;
Charles Keepax77438612013-11-14 16:18:25 +0000488 /* Convert to ohms, the value is in 0.5 ohm increments */
489 val /= 2;
Mark Brown4f340332013-01-11 08:55:43 +0900490
491 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
492 &range);
493 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
494 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
495
Charles Keepax91414612013-11-14 16:18:24 +0000496 /* Skip up a range, or report? */
Mark Brown4f340332013-01-11 08:55:43 +0900497 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
498 (val >= arizona_hpdet_c_ranges[range].max)) {
499 range++;
500 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
501 arizona_hpdet_c_ranges[range].min,
502 arizona_hpdet_c_ranges[range].max);
503 regmap_update_bits(arizona->regmap,
504 ARIZONA_HEADPHONE_DETECT_1,
505 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
506 range <<
507 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
508 return -EAGAIN;
509 }
Charles Keepax91414612013-11-14 16:18:24 +0000510
511 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
512 dev_dbg(arizona->dev, "Reporting range boundary %d\n",
513 arizona_hpdet_c_ranges[range].min);
514 val = arizona_hpdet_c_ranges[range].min;
515 }
Chanwoo Choie9844b22015-09-29 19:06:31 +0900516 break;
517
518 default:
519 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
520 info->hpdet_ip_version);
521 return -EINVAL;
Mark Brown4f340332013-01-11 08:55:43 +0900522 }
523
524 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
525 return val;
526}
527
Mark Brown9c2ba272013-02-25 23:42:31 +0000528static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
529 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900530{
531 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900532 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900533
534 /*
535 * If we're using HPDET for accessory identification we need
536 * to take multiple measurements, step through them in sequence.
537 */
538 if (arizona->pdata.hpdet_acc_id) {
539 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900540
541 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000542 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900543 dev_dbg(arizona->dev, "Measuring mic\n");
544
545 regmap_update_bits(arizona->regmap,
546 ARIZONA_ACCESSORY_DETECT_MODE_1,
547 ARIZONA_ACCDET_MODE_MASK |
548 ARIZONA_ACCDET_SRC,
549 ARIZONA_ACCDET_MODE_HPR |
550 info->micd_modes[0].src);
551
552 gpio_set_value_cansleep(id_gpio, 1);
553
Mark Browndd235ee2013-01-11 08:55:51 +0900554 regmap_update_bits(arizona->regmap,
555 ARIZONA_HEADPHONE_DETECT_1,
556 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
557 return -EAGAIN;
558 }
559
560 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000561 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
562 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000563
564 /* Take the headphone impedance for the main report */
565 *reading = info->hpdet_res[0];
566
Mark Brown9dd5e532013-04-01 19:09:45 +0100567 /* Sometimes we get false readings due to slow insert */
568 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
569 dev_dbg(arizona->dev, "Retrying high impedance\n");
570 info->num_hpdet_res = 0;
571 info->hpdet_retried = true;
572 arizona_start_hpdet_acc_id(info);
573 pm_runtime_put(info->dev);
574 return -EAGAIN;
575 }
576
Mark Brown1eda6aa2013-01-11 08:55:54 +0900577 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530578 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900579 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000580 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900581 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000582 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000583 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900584 } else {
585 dev_dbg(arizona->dev, "Detected headphone\n");
586 }
587
588 /* Make sure everything is reset back to the real polarity */
589 regmap_update_bits(arizona->regmap,
590 ARIZONA_ACCESSORY_DETECT_MODE_1,
591 ARIZONA_ACCDET_SRC,
592 info->micd_modes[0].src);
593 }
594
595 return 0;
596}
597
Mark Brown4f340332013-01-11 08:55:43 +0900598static irqreturn_t arizona_hpdet_irq(int irq, void *data)
599{
600 struct arizona_extcon_info *info = data;
601 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900602 int id_gpio = arizona->pdata.hpdet_id_gpio;
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900603 unsigned int report = EXTCON_JACK_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900604 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000605 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900606
607 mutex_lock(&info->lock);
608
609 /* If we got a spurious IRQ for some reason then ignore it */
610 if (!info->hpdet_active) {
611 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
612 mutex_unlock(&info->lock);
613 return IRQ_NONE;
614 }
615
616 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900617 ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
Mark Brown4f340332013-01-11 08:55:43 +0900618 if (ret < 0) {
619 dev_err(arizona->dev, "Failed to check cable state: %d\n",
620 ret);
621 goto out;
622 } else if (!ret) {
623 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
624 goto done;
625 }
626
627 ret = arizona_hpdet_read(info);
Chanwoo Choid6675662013-08-23 10:21:39 +0900628 if (ret == -EAGAIN)
Mark Brown4f340332013-01-11 08:55:43 +0900629 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900630 else if (ret < 0)
Mark Brown4f340332013-01-11 08:55:43 +0900631 goto done;
Mark Browndd235ee2013-01-11 08:55:51 +0900632 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900633
634 /* Reset back to starting range */
635 regmap_update_bits(arizona->regmap,
636 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900637 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
638 0);
639
Mark Brown9c2ba272013-02-25 23:42:31 +0000640 ret = arizona_hpdet_do_id(info, &reading, &mic);
Chanwoo Choid6675662013-08-23 10:21:39 +0900641 if (ret == -EAGAIN)
Mark Browndd235ee2013-01-11 08:55:51 +0900642 goto out;
Chanwoo Choid6675662013-08-23 10:21:39 +0900643 else if (ret < 0)
Mark Browndd235ee2013-01-11 08:55:51 +0900644 goto done;
Mark Brown4f340332013-01-11 08:55:43 +0900645
646 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900647 if (reading >= 5000)
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900648 report = EXTCON_JACK_LINE_OUT;
Mark Brown4f340332013-01-11 08:55:43 +0900649 else
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900650 report = EXTCON_JACK_HEADPHONE;
Mark Brown4f340332013-01-11 08:55:43 +0900651
Chanwoo Choi8670b452016-08-16 15:55:34 +0900652 ret = extcon_set_state_sync(info->edev, report, true);
Mark Brown4f340332013-01-11 08:55:43 +0900653 if (ret != 0)
654 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
655 ret);
656
Charles Keepaxa3e00d42013-11-14 16:18:22 +0000657done:
658 /* Reset back to starting range */
659 regmap_update_bits(arizona->regmap,
660 ARIZONA_HEADPHONE_DETECT_1,
661 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
662 0);
663
Charles Keepax112bdfa2015-02-16 15:41:02 +0000664 arizona_extcon_hp_clamp(info, false);
Mark Brown4f340332013-01-11 08:55:43 +0900665
Mark Brown1eda6aa2013-01-11 08:55:54 +0900666 if (id_gpio)
667 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900668
669 /* Revert back to MICDET mode */
670 regmap_update_bits(arizona->regmap,
671 ARIZONA_ACCESSORY_DETECT_MODE_1,
672 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
673
674 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000675 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900676 arizona_start_mic(info);
677
678 if (info->hpdet_active) {
679 pm_runtime_put_autosuspend(info->dev);
680 info->hpdet_active = false;
681 }
682
Mark Brownbf14ee52013-02-05 20:20:17 +0000683 info->hpdet_done = true;
684
Mark Brown4f340332013-01-11 08:55:43 +0900685out:
686 mutex_unlock(&info->lock);
687
688 return IRQ_HANDLED;
689}
690
691static void arizona_identify_headphone(struct arizona_extcon_info *info)
692{
693 struct arizona *arizona = info->arizona;
694 int ret;
695
Mark Brownbf14ee52013-02-05 20:20:17 +0000696 if (info->hpdet_done)
697 return;
698
Mark Brown4f340332013-01-11 08:55:43 +0900699 dev_dbg(arizona->dev, "Starting HPDET\n");
700
701 /* Make sure we keep the device enabled during the measurement */
702 pm_runtime_get(info->dev);
703
704 info->hpdet_active = true;
705
706 if (info->mic)
707 arizona_stop_mic(info);
708
Charles Keepax112bdfa2015-02-16 15:41:02 +0000709 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900710
711 ret = regmap_update_bits(arizona->regmap,
712 ARIZONA_ACCESSORY_DETECT_MODE_1,
713 ARIZONA_ACCDET_MODE_MASK,
Inha Song9e86b2a2015-05-04 13:42:13 +0900714 arizona->pdata.hpdet_channel);
Mark Brown4f340332013-01-11 08:55:43 +0900715 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900716 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +0900717 goto err;
718 }
719
720 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
721 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
722 if (ret != 0) {
723 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
724 ret);
725 goto err;
726 }
727
728 return;
729
730err:
731 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
732 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
733
734 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900735 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900736 if (ret != 0)
737 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
738
739 if (info->mic)
740 arizona_start_mic(info);
741
742 info->hpdet_active = false;
743}
Mark Browndd235ee2013-01-11 08:55:51 +0900744
745static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
746{
747 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000748 int hp_reading = 32;
749 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900750 int ret;
751
752 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
753
754 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000755 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900756
757 info->hpdet_active = true;
758
Charles Keepax112bdfa2015-02-16 15:41:02 +0000759 arizona_extcon_hp_clamp(info, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900760
761 ret = regmap_update_bits(arizona->regmap,
762 ARIZONA_ACCESSORY_DETECT_MODE_1,
763 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
764 info->micd_modes[0].src |
Inha Song9e86b2a2015-05-04 13:42:13 +0900765 arizona->pdata.hpdet_channel);
Mark Browndd235ee2013-01-11 08:55:51 +0900766 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900767 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Browndd235ee2013-01-11 08:55:51 +0900768 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900769 }
770
Mark Brown9c2ba272013-02-25 23:42:31 +0000771 if (arizona->pdata.hpdet_acc_id_line) {
772 ret = regmap_update_bits(arizona->regmap,
773 ARIZONA_HEADPHONE_DETECT_1,
774 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
775 if (ret != 0) {
776 dev_err(arizona->dev,
777 "Can't start HPDETL measurement: %d\n",
778 ret);
779 goto err;
780 }
781 } else {
782 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900783 }
784
785 return;
786
787err:
788 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
789 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
790
791 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900792 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900793 if (ret != 0)
794 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
795
Mark Brown4f340332013-01-11 08:55:43 +0900796 info->hpdet_active = false;
797}
798
Mark Brown939c5672013-04-01 19:17:34 +0100799static void arizona_micd_timeout_work(struct work_struct *work)
800{
801 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900802 struct arizona_extcon_info,
803 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100804
805 mutex_lock(&info->lock);
806
807 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
Mark Brown939c5672013-04-01 19:17:34 +0100808
809 info->detecting = false;
810
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100811 arizona_identify_headphone(info);
812
Mark Brown939c5672013-04-01 19:17:34 +0100813 arizona_stop_mic(info);
814
815 mutex_unlock(&info->lock);
816}
817
Mark Browncd59e792013-04-01 19:21:48 +0100818static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100819{
Mark Browncd59e792013-04-01 19:21:48 +0100820 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900821 struct arizona_extcon_info,
822 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100823 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100824 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100825 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100826
Mark Brown939c5672013-04-01 19:17:34 +0100827 cancel_delayed_work_sync(&info->micd_timeout_work);
828
Mark Brownf2c32a82012-06-24 12:09:45 +0100829 mutex_lock(&info->lock);
830
Charles Keepax31a847e2013-11-14 16:18:23 +0000831 /* If the cable was removed while measuring ignore the result */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900832 ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
Charles Keepax31a847e2013-11-14 16:18:23 +0000833 if (ret < 0) {
834 dev_err(arizona->dev, "Failed to check cable state: %d\n",
835 ret);
836 mutex_unlock(&info->lock);
837 return;
838 } else if (!ret) {
839 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
840 mutex_unlock(&info->lock);
841 return;
842 }
843
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100844 if (info->detecting && arizona->pdata.micd_software_compare) {
845 /* Must disable MICD before we read the ADCVAL */
846 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
847 ARIZONA_MICD_ENA, 0);
848 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
849 if (ret != 0) {
850 dev_err(arizona->dev,
851 "Failed to read MICDET_ADCVAL: %d\n",
852 ret);
853 mutex_unlock(&info->lock);
854 return;
855 }
856
857 dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
858
859 val &= ARIZONA_MICDET_ADCVAL_MASK;
860 if (val < ARRAY_SIZE(arizona_micd_levels))
861 val = arizona_micd_levels[val];
862 else
863 val = INT_MAX;
864
865 if (val <= QUICK_HEADPHONE_MAX_OHM)
866 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
867 else if (val <= MICROPHONE_MIN_OHM)
868 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
869 else if (val <= MICROPHONE_MAX_OHM)
870 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
871 else
872 val = ARIZONA_MICD_LVL_8;
873 }
874
Charles Keepaxffae24f2013-11-14 16:18:21 +0000875 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100876 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
877 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900878 dev_err(arizona->dev,
879 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100880 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100881 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100882 }
883
884 dev_dbg(arizona->dev, "MICDET: %x\n", val);
885
886 if (!(val & ARIZONA_MICD_VALID)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900887 dev_warn(arizona->dev,
888 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100889 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100890 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100891 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100892 }
893
Charles Keepaxffae24f2013-11-14 16:18:21 +0000894 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100895 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100896 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100897 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100898 }
899
900 /* Due to jack detect this should never happen */
901 if (!(val & ARIZONA_MICD_STS)) {
902 dev_warn(arizona->dev, "Detected open circuit\n");
Charles Keepax57f70ef2015-06-25 16:47:02 +0100903 info->mic = false;
904 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100905 info->detecting = false;
Charles Keepax57f70ef2015-06-25 16:47:02 +0100906 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100907 goto handled;
908 }
909
910 /* If we got a high impedence we should have a headset, report it. */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000911 if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100912 info->mic = true;
913 info->detecting = false;
914
Mark Brown4f340332013-01-11 08:55:43 +0900915 arizona_identify_headphone(info);
916
Chanwoo Choi8670b452016-08-16 15:55:34 +0900917 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900918 EXTCON_JACK_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100919 if (ret != 0)
920 dev_err(arizona->dev, "Headset report failed: %d\n",
921 ret);
922
Mark Brownbbbd46e2013-01-10 19:38:43 +0000923 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100924 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000925 if (ret != 0) {
926 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
927 ret);
928 }
929
Mark Brownf2c32a82012-06-24 12:09:45 +0100930 goto handled;
931 }
932
933 /* If we detected a lower impedence during initial startup
934 * then we probably have the wrong polarity, flip it. Don't
935 * do this for the lowest impedences to speed up detection of
936 * plain headphones. If both polarities report a low
937 * impedence then give up and report headphones.
938 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000939 if (info->detecting && (val & MICD_LVL_1_TO_7)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800940 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900941 dev_dbg(arizona->dev, "Detected HP/line\n");
Mark Brown9ef2224d2012-06-28 13:08:31 +0100942
Mark Brown4f340332013-01-11 08:55:43 +0900943 info->detecting = false;
944
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100945 arizona_identify_headphone(info);
946
Mark Brown4f340332013-01-11 08:55:43 +0900947 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100948 } else {
949 info->micd_mode++;
950 if (info->micd_mode == info->micd_num_modes)
951 info->micd_mode = 0;
952 arizona_extcon_set_mode(info, info->micd_mode);
953
954 info->jack_flips++;
955 }
956
957 goto handled;
958 }
959
960 /*
961 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100962 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100963 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000964 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100965 if (info->mic) {
966 dev_dbg(arizona->dev, "Mic button detected\n");
967
Mark Brown34efe4d2012-07-20 17:07:29 +0100968 lvl = val & ARIZONA_MICD_LVL_MASK;
969 lvl >>= ARIZONA_MICD_LVL_SHIFT;
970
Mark Brown41a57852013-04-01 19:18:18 +0100971 for (i = 0; i < info->num_micd_ranges; i++)
972 input_report_key(info->input,
973 info->micd_ranges[i].key, 0);
974
Mark Brown6fed4d82013-04-01 22:03:06 +0100975 WARN_ON(!lvl);
976 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
977 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
978 key = info->micd_ranges[ffs(lvl) - 1].key;
979 input_report_key(info->input, key, 1);
980 input_sync(info->input);
981 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100982
Mark Brownf2c32a82012-06-24 12:09:45 +0100983 } else if (info->detecting) {
984 dev_dbg(arizona->dev, "Headphone detected\n");
985 info->detecting = false;
986 arizona_stop_mic(info);
987
Mark Brown4f340332013-01-11 08:55:43 +0900988 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100989 } else {
990 dev_warn(arizona->dev, "Button with no mic: %x\n",
991 val);
992 }
993 } else {
994 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100995 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100996 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100997 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100998 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000999 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001000 }
1001
1002handled:
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001003 if (info->detecting) {
1004 if (arizona->pdata.micd_software_compare)
1005 regmap_update_bits(arizona->regmap,
1006 ARIZONA_MIC_DETECT_1,
1007 ARIZONA_MICD_ENA,
1008 ARIZONA_MICD_ENA);
1009
Mark Browndf9a5ab2013-07-18 22:42:22 +01001010 queue_delayed_work(system_power_efficient_wq,
1011 &info->micd_timeout_work,
1012 msecs_to_jiffies(info->micd_timeout));
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001013 }
Mark Brown939c5672013-04-01 19:17:34 +01001014
Mark Brownf2c32a82012-06-24 12:09:45 +01001015 pm_runtime_mark_last_busy(info->dev);
1016 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +01001017}
1018
1019static irqreturn_t arizona_micdet(int irq, void *data)
1020{
1021 struct arizona_extcon_info *info = data;
1022 struct arizona *arizona = info->arizona;
1023 int debounce = arizona->pdata.micd_detect_debounce;
1024
1025 cancel_delayed_work_sync(&info->micd_detect_work);
1026 cancel_delayed_work_sync(&info->micd_timeout_work);
1027
1028 mutex_lock(&info->lock);
1029 if (!info->detecting)
1030 debounce = 0;
1031 mutex_unlock(&info->lock);
1032
1033 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001034 queue_delayed_work(system_power_efficient_wq,
1035 &info->micd_detect_work,
1036 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +01001037 else
1038 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001039
1040 return IRQ_HANDLED;
1041}
1042
Mark Brown0e27bd32013-02-05 21:00:15 +00001043static void arizona_hpdet_work(struct work_struct *work)
1044{
1045 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001046 struct arizona_extcon_info,
1047 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +00001048
1049 mutex_lock(&info->lock);
1050 arizona_start_hpdet_acc_id(info);
1051 mutex_unlock(&info->lock);
1052}
1053
Mark Brownf2c32a82012-06-24 12:09:45 +01001054static irqreturn_t arizona_jackdet(int irq, void *data)
1055{
1056 struct arizona_extcon_info *info = data;
1057 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001058 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +01001059 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +01001060 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +01001061
Mark Brown939c5672013-04-01 19:17:34 +01001062 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
1063 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001064
Mark Browna3e20782013-04-01 19:05:27 +01001065 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +00001066
Mark Brownf2c32a82012-06-24 12:09:45 +01001067 mutex_lock(&info->lock);
1068
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001069 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001070 mask = ARIZONA_MICD_CLAMP_STS;
Nariman Poushina0ef6422015-09-16 10:42:19 +01001071 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +09001072 } else {
1073 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001074 if (arizona->pdata.jd_invert)
1075 present = 0;
1076 else
1077 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +09001078 }
1079
Mark Brownf2c32a82012-06-24 12:09:45 +01001080 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
1081 if (ret != 0) {
1082 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
1083 ret);
1084 mutex_unlock(&info->lock);
1085 pm_runtime_put_autosuspend(info->dev);
1086 return IRQ_NONE;
1087 }
1088
Mark Browna3e20782013-04-01 19:05:27 +01001089 val &= mask;
1090 if (val == info->last_jackdet) {
1091 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001092 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001093 queue_delayed_work(system_power_efficient_wq,
1094 &info->hpdet_work,
1095 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001096
Chanwoo Choic2275d22013-08-23 10:21:37 +09001097 if (cancelled_mic) {
1098 int micd_timeout = info->micd_timeout;
1099
Mark Browndf9a5ab2013-07-18 22:42:22 +01001100 queue_delayed_work(system_power_efficient_wq,
1101 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001102 msecs_to_jiffies(micd_timeout));
1103 }
Mark Brown939c5672013-04-01 19:17:34 +01001104
Mark Browna3e20782013-04-01 19:05:27 +01001105 goto out;
1106 }
1107 info->last_jackdet = val;
1108
1109 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001110 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choi8670b452016-08-16 15:55:34 +09001111 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +09001112 EXTCON_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001113
1114 if (ret != 0)
1115 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1116 ret);
1117
Mark Browndd235ee2013-01-11 08:55:51 +09001118 if (!arizona->pdata.hpdet_acc_id) {
1119 info->detecting = true;
1120 info->mic = false;
1121 info->jack_flips = 0;
1122
1123 arizona_start_mic(info);
1124 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001125 queue_delayed_work(system_power_efficient_wq,
1126 &info->hpdet_work,
1127 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001128 }
Mark Brown4e616872013-01-15 22:09:20 +09001129
Charles Keepax6c20b932015-09-16 10:42:21 +01001130 if (info->micd_clamp || !arizona->pdata.jd_invert)
1131 regmap_update_bits(arizona->regmap,
1132 ARIZONA_JACK_DETECT_DEBOUNCE,
1133 ARIZONA_MICD_CLAMP_DB |
1134 ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001135 } else {
1136 dev_dbg(arizona->dev, "Detected jack removal\n");
1137
1138 arizona_stop_mic(info);
1139
Mark Browndd235ee2013-01-11 08:55:51 +09001140 info->num_hpdet_res = 0;
1141 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1142 info->hpdet_res[i] = 0;
1143 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001144 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001145 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001146
Mark Brown6fed4d82013-04-01 22:03:06 +01001147 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001148 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001149 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001150 input_sync(info->input);
1151
Chanwoo Choi5475e632016-07-01 02:36:49 +09001152 for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) {
Chanwoo Choi8670b452016-08-16 15:55:34 +09001153 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi5475e632016-07-01 02:36:49 +09001154 arizona_cable[i], false);
1155 if (ret != 0)
1156 dev_err(arizona->dev,
1157 "Removal report failed: %d\n", ret);
1158 }
Mark Brown4e616872013-01-15 22:09:20 +09001159
1160 regmap_update_bits(arizona->regmap,
1161 ARIZONA_JACK_DETECT_DEBOUNCE,
1162 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1163 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001164 }
1165
Mark Brown7abd4e22013-04-01 19:25:55 +01001166 if (arizona->pdata.micd_timeout)
1167 info->micd_timeout = arizona->pdata.micd_timeout;
1168 else
1169 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1170
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001171out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001172 /* Clear trig_sts to make sure DCVDD is not forced up */
1173 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1174 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1175 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1176 ARIZONA_JD1_FALL_TRIG_STS |
1177 ARIZONA_JD1_RISE_TRIG_STS);
1178
Mark Brownf2c32a82012-06-24 12:09:45 +01001179 mutex_unlock(&info->lock);
1180
1181 pm_runtime_mark_last_busy(info->dev);
1182 pm_runtime_put_autosuspend(info->dev);
1183
1184 return IRQ_HANDLED;
1185}
1186
Mark Brown6fed4d82013-04-01 22:03:06 +01001187/* Map a level onto a slot in the register bank */
1188static void arizona_micd_set_level(struct arizona *arizona, int index,
1189 unsigned int level)
1190{
1191 int reg;
1192 unsigned int mask;
1193
1194 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1195
1196 if (!(index % 2)) {
1197 mask = 0x3f00;
1198 level <<= 8;
1199 } else {
1200 mask = 0x3f;
1201 }
1202
1203 /* Program the level itself */
1204 regmap_update_bits(arizona->regmap, reg, mask, level);
1205}
1206
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001207static int arizona_extcon_get_micd_configs(struct device *dev,
1208 struct arizona *arizona)
1209{
1210 const char * const prop = "wlf,micd-configs";
1211 const int entries_per_config = 3;
1212 struct arizona_micd_config *micd_configs;
1213 int nconfs, ret;
1214 int i, j;
1215 u32 *vals;
1216
1217 nconfs = device_property_read_u32_array(arizona->dev, prop, NULL, 0);
1218 if (nconfs <= 0)
1219 return 0;
1220
1221 vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
1222 if (!vals)
1223 return -ENOMEM;
1224
1225 ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
1226 if (ret < 0)
1227 goto out;
1228
1229 nconfs /= entries_per_config;
1230
1231 micd_configs = devm_kzalloc(dev,
1232 nconfs * sizeof(struct arizona_micd_range),
1233 GFP_KERNEL);
1234 if (!micd_configs) {
1235 ret = -ENOMEM;
1236 goto out;
1237 }
1238
1239 for (i = 0, j = 0; i < nconfs; ++i) {
1240 micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
1241 micd_configs[i].bias = vals[j++];
1242 micd_configs[i].gpio = vals[j++];
1243 }
1244
1245 arizona->pdata.micd_configs = micd_configs;
1246 arizona->pdata.num_micd_configs = nconfs;
1247
1248out:
1249 kfree(vals);
1250 return ret;
1251}
1252
1253static int arizona_extcon_device_get_pdata(struct device *dev,
1254 struct arizona *arizona)
Inha Song9e86b2a2015-05-04 13:42:13 +09001255{
1256 struct arizona_pdata *pdata = &arizona->pdata;
1257 unsigned int val = ARIZONA_ACCDET_MODE_HPL;
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001258 int ret;
Inha Song9e86b2a2015-05-04 13:42:13 +09001259
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001260 device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
Inha Song9e86b2a2015-05-04 13:42:13 +09001261 switch (val) {
1262 case ARIZONA_ACCDET_MODE_HPL:
1263 case ARIZONA_ACCDET_MODE_HPR:
1264 pdata->hpdet_channel = val;
1265 break;
1266 default:
1267 dev_err(arizona->dev,
1268 "Wrong wlf,hpdet-channel DT value %d\n", val);
1269 pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
1270 }
1271
Charles Keepax4778d442015-06-19 17:23:30 +01001272 device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
1273 &pdata->micd_detect_debounce);
1274
1275 device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
1276 &pdata->micd_bias_start_time);
1277
1278 device_property_read_u32(arizona->dev, "wlf,micd-rate",
1279 &pdata->micd_rate);
1280
1281 device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
1282 &pdata->micd_dbtime);
1283
Charles Keepax7a7ef0f2015-11-23 14:51:30 +00001284 device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
Charles Keepax4778d442015-06-19 17:23:30 +01001285 &pdata->micd_timeout);
1286
1287 pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
1288 "wlf,micd-force-micbias");
1289
Charles Keepax2e87b7a2015-11-19 15:45:35 +00001290 pdata->micd_software_compare = device_property_read_bool(arizona->dev,
1291 "wlf,micd-software-compare");
1292
Charles Keepax3d7a8722015-11-19 15:45:37 +00001293 pdata->jd_invert = device_property_read_bool(arizona->dev,
1294 "wlf,jd-invert");
1295
Charles Keepax99374222015-11-19 15:45:36 +00001296 device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
1297
Charles Keepax35247c12015-11-19 15:45:38 +00001298 pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001299 "wlf,use-jd2");
Charles Keepax35247c12015-11-19 15:45:38 +00001300 pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001301 "wlf,use-jd2-nopull");
Charles Keepax35247c12015-11-19 15:45:38 +00001302
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001303 ret = arizona_extcon_get_micd_configs(dev, arizona);
1304 if (ret < 0)
1305 dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
1306
Inha Song9e86b2a2015-05-04 13:42:13 +09001307 return 0;
1308}
1309
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001310static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001311{
1312 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001313 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001314 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001315 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001316 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001317 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001318 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001319
Mark Brownbbbd46e2013-01-10 19:38:43 +00001320 if (!arizona->dapm || !arizona->dapm->card)
1321 return -EPROBE_DEFER;
1322
Mark Brownf2c32a82012-06-24 12:09:45 +01001323 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001324 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001325 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001326
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001327 if (!dev_get_platdata(arizona->dev))
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001328 arizona_extcon_device_get_pdata(&pdev->dev, arizona);
Inha Song9e86b2a2015-05-04 13:42:13 +09001329
Charles Keepax17271f62014-07-18 12:59:00 +01001330 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001331 if (IS_ERR(info->micvdd)) {
1332 ret = PTR_ERR(info->micvdd);
1333 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001334 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001335 }
1336
1337 mutex_init(&info->lock);
1338 info->arizona = arizona;
1339 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001340 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001341 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001342 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001343 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001344 platform_set_drvdata(pdev, info);
1345
1346 switch (arizona->type) {
1347 case WM5102:
1348 switch (arizona->rev) {
1349 case 0:
1350 info->micd_reva = true;
1351 break;
1352 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001353 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001354 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001355 break;
1356 }
1357 break;
Charles Keepax77438612013-11-14 16:18:25 +00001358 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001359 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001360 switch (arizona->rev) {
1361 case 0 ... 2:
1362 break;
1363 default:
1364 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001365 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001366 break;
1367 }
1368 break;
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +01001369 case WM8998:
1370 case WM1814:
1371 info->micd_clamp = true;
1372 info->hpdet_ip_version = 2;
1373 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001374 default:
1375 break;
1376 }
1377
Chanwoo Choief70a212014-04-21 20:47:31 +09001378 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1379 if (IS_ERR(info->edev)) {
1380 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1381 return -ENOMEM;
1382 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001383
Chanwoo Choief70a212014-04-21 20:47:31 +09001384 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001385 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001386 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001387 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001388 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001389 }
1390
Mark Brown6fed4d82013-04-01 22:03:06 +01001391 info->input = devm_input_allocate_device(&pdev->dev);
1392 if (!info->input) {
1393 dev_err(arizona->dev, "Can't allocate input dev\n");
1394 ret = -ENOMEM;
1395 goto err_register;
1396 }
1397
1398 info->input->name = "Headset";
1399 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001400
Mark Brownf2c32a82012-06-24 12:09:45 +01001401 if (pdata->num_micd_configs) {
1402 info->micd_modes = pdata->micd_configs;
1403 info->micd_num_modes = pdata->num_micd_configs;
1404 } else {
1405 info->micd_modes = micd_default_modes;
1406 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1407 }
1408
Charles Keepax6772a5a2015-09-16 10:42:17 +01001409 if (arizona->pdata.gpsw > 0)
1410 regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
1411 ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
1412
Mark Brownf2c32a82012-06-24 12:09:45 +01001413 if (arizona->pdata.micd_pol_gpio > 0) {
1414 if (info->micd_modes[0].gpio)
1415 mode = GPIOF_OUT_INIT_HIGH;
1416 else
1417 mode = GPIOF_OUT_INIT_LOW;
1418
1419 ret = devm_gpio_request_one(&pdev->dev,
1420 arizona->pdata.micd_pol_gpio,
1421 mode,
1422 "MICD polarity");
1423 if (ret != 0) {
1424 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1425 arizona->pdata.micd_pol_gpio, ret);
1426 goto err_register;
1427 }
Charles Keepax8e5838d2015-06-19 17:23:31 +01001428 } else {
1429 if (info->micd_modes[0].gpio)
1430 mode = GPIOD_OUT_HIGH;
1431 else
1432 mode = GPIOD_OUT_LOW;
1433
1434 /* We can't use devm here because we need to do the get
1435 * against the MFD device, as that is where the of_node
1436 * will reside, but if we devm against that the GPIO
1437 * will not be freed if the extcon driver is unloaded.
1438 */
1439 info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
1440 "wlf,micd-pol",
1441 GPIOD_OUT_LOW);
1442 if (IS_ERR(info->micd_pol_gpio)) {
1443 ret = PTR_ERR(info->micd_pol_gpio);
1444 dev_err(arizona->dev,
1445 "Failed to get microphone polarity GPIO: %d\n",
1446 ret);
1447 goto err_register;
1448 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001449 }
1450
Mark Brown1eda6aa2013-01-11 08:55:54 +09001451 if (arizona->pdata.hpdet_id_gpio > 0) {
1452 ret = devm_gpio_request_one(&pdev->dev,
1453 arizona->pdata.hpdet_id_gpio,
1454 GPIOF_OUT_INIT_LOW,
1455 "HPDET");
1456 if (ret != 0) {
1457 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1458 arizona->pdata.hpdet_id_gpio, ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001459 goto err_gpio;
Mark Brown1eda6aa2013-01-11 08:55:54 +09001460 }
1461 }
1462
Mark Brownb17e5462013-01-11 08:55:24 +09001463 if (arizona->pdata.micd_bias_start_time)
1464 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1465 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1466 arizona->pdata.micd_bias_start_time
1467 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1468
Mark Brown2e033db2013-01-21 17:36:33 +09001469 if (arizona->pdata.micd_rate)
1470 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1471 ARIZONA_MICD_RATE_MASK,
1472 arizona->pdata.micd_rate
1473 << ARIZONA_MICD_RATE_SHIFT);
1474
Charles Keepaxbb327e92015-06-30 13:32:39 +01001475 switch (arizona->pdata.micd_dbtime) {
1476 case MICD_DBTIME_FOUR_READINGS:
Mark Brown2e033db2013-01-21 17:36:33 +09001477 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1478 ARIZONA_MICD_DBTIME_MASK,
Charles Keepaxbb327e92015-06-30 13:32:39 +01001479 ARIZONA_MICD_DBTIME);
1480 break;
1481 case MICD_DBTIME_TWO_READINGS:
1482 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1483 ARIZONA_MICD_DBTIME_MASK, 0);
1484 break;
1485 default:
1486 break;
1487 }
Mark Brown2e033db2013-01-21 17:36:33 +09001488
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001489 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) <
1490 ARIZONA_NUM_MICD_BUTTON_LEVELS);
Mark Brown6fed4d82013-04-01 22:03:06 +01001491
1492 if (arizona->pdata.num_micd_ranges) {
1493 info->micd_ranges = pdata->micd_ranges;
1494 info->num_micd_ranges = pdata->num_micd_ranges;
1495 } else {
1496 info->micd_ranges = micd_default_ranges;
1497 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1498 }
1499
1500 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1501 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1502 arizona->pdata.num_micd_ranges);
1503 }
1504
1505 if (info->num_micd_ranges > 1) {
1506 for (i = 1; i < info->num_micd_ranges; i++) {
1507 if (info->micd_ranges[i - 1].max >
1508 info->micd_ranges[i].max) {
1509 dev_err(arizona->dev,
1510 "MICD ranges must be sorted\n");
1511 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001512 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001513 }
1514 }
1515 }
1516
1517 /* Disable all buttons by default */
1518 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1519 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1520
1521 /* Set up all the buttons the user specified */
1522 for (i = 0; i < info->num_micd_ranges; i++) {
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001523 for (j = 0; j < ARIZONA_NUM_MICD_BUTTON_LEVELS; j++)
Mark Brown6fed4d82013-04-01 22:03:06 +01001524 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1525 break;
1526
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001527 if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
Mark Brown6fed4d82013-04-01 22:03:06 +01001528 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1529 info->micd_ranges[i].max);
1530 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001531 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001532 }
1533
1534 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1535 arizona_micd_levels[j], i);
1536
1537 arizona_micd_set_level(arizona, i, j);
1538 input_set_capability(info->input, EV_KEY,
1539 info->micd_ranges[i].key);
1540
1541 /* Enable reporting of that range */
1542 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1543 1 << i, 1 << i);
1544 }
1545
1546 /* Set all the remaining keys to a maximum */
1547 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1548 arizona_micd_set_level(arizona, i, 0x3f);
1549
Mark Browndab63eb2013-01-11 08:55:36 +09001550 /*
Mark Brown92a49872013-01-11 08:55:39 +09001551 * If we have a clamp use it, activating in conjunction with
1552 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001553 */
1554 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001555 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001556 /* Put the GPIO into input mode with optional pull */
1557 val = 0xc101;
1558 if (arizona->pdata.jd_gpio5_nopull)
1559 val &= ~ARIZONA_GPN_PU;
1560
Mark Brown92a49872013-01-11 08:55:39 +09001561 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001562 val);
Mark Brown92a49872013-01-11 08:55:39 +09001563
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001564 if (arizona->pdata.jd_invert)
1565 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1566 else
1567 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001568 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001569 if (arizona->pdata.jd_invert)
1570 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1571 else
1572 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001573 }
1574
Mark Browndab63eb2013-01-11 08:55:36 +09001575 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001576 ARIZONA_MICD_CLAMP_CONTROL,
1577 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1578
1579 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001580 ARIZONA_JACK_DETECT_DEBOUNCE,
1581 ARIZONA_MICD_CLAMP_DB,
1582 ARIZONA_MICD_CLAMP_DB);
1583 }
1584
Mark Brownf2c32a82012-06-24 12:09:45 +01001585 arizona_extcon_set_mode(info, 0);
1586
1587 pm_runtime_enable(&pdev->dev);
1588 pm_runtime_idle(&pdev->dev);
1589 pm_runtime_get_sync(&pdev->dev);
1590
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001591 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001592 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1593 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1594 } else {
1595 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1596 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1597 }
1598
1599 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001600 "JACKDET rise", arizona_jackdet, info);
1601 if (ret != 0) {
1602 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1603 ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001604 goto err_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +01001605 }
1606
Mark Brown92a49872013-01-11 08:55:39 +09001607 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001608 if (ret != 0) {
1609 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1610 ret);
1611 goto err_rise;
1612 }
1613
Mark Brown92a49872013-01-11 08:55:39 +09001614 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001615 "JACKDET fall", arizona_jackdet, info);
1616 if (ret != 0) {
1617 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1618 goto err_rise_wake;
1619 }
1620
Mark Brown92a49872013-01-11 08:55:39 +09001621 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001622 if (ret != 0) {
1623 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1624 ret);
1625 goto err_fall;
1626 }
1627
1628 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1629 "MICDET", arizona_micdet, info);
1630 if (ret != 0) {
1631 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1632 goto err_fall_wake;
1633 }
1634
Mark Brown4f340332013-01-11 08:55:43 +09001635 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1636 "HPDET", arizona_hpdet_irq, info);
1637 if (ret != 0) {
1638 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1639 goto err_micdet;
1640 }
1641
Mark Brownf2c32a82012-06-24 12:09:45 +01001642 arizona_clk32k_enable(arizona);
1643 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1644 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1645 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1646 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1647
Mark Brownb8575a12012-09-07 17:01:15 +08001648 ret = regulator_allow_bypass(info->micvdd, true);
1649 if (ret != 0)
1650 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1651 ret);
1652
Mark Brownf2c32a82012-06-24 12:09:45 +01001653 pm_runtime_put(&pdev->dev);
1654
Mark Brown34efe4d2012-07-20 17:07:29 +01001655 ret = input_register_device(info->input);
1656 if (ret) {
1657 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001658 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001659 }
1660
Mark Brownf2c32a82012-06-24 12:09:45 +01001661 return 0;
1662
Mark Brown4f340332013-01-11 08:55:43 +09001663err_hpdet:
1664 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001665err_micdet:
1666 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001667err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001668 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001669err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001670 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001671err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001672 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001673err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001674 arizona_free_irq(arizona, jack_irq_rise, info);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001675err_gpio:
1676 gpiod_put(info->micd_pol_gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +01001677err_register:
1678 pm_runtime_disable(&pdev->dev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001679 return ret;
1680}
1681
Bill Pemberton93ed0322012-11-19 13:25:49 -05001682static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001683{
1684 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1685 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001686 int jack_irq_rise, jack_irq_fall;
Charles Keepaxffd48ee2019-04-04 17:33:56 +01001687 bool change;
1688
1689 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
1690 ARIZONA_MICD_ENA, 0,
1691 &change);
1692
1693 if (change) {
1694 regulator_disable(info->micvdd);
1695 pm_runtime_put(info->dev);
1696 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001697
Charles Keepax8e5838d2015-06-19 17:23:31 +01001698 gpiod_put(info->micd_pol_gpio);
1699
Mark Brownf2c32a82012-06-24 12:09:45 +01001700 pm_runtime_disable(&pdev->dev);
1701
Mark Browndab63eb2013-01-11 08:55:36 +09001702 regmap_update_bits(arizona->regmap,
1703 ARIZONA_MICD_CLAMP_CONTROL,
1704 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1705
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001706 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001707 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1708 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1709 } else {
1710 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1711 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1712 }
1713
1714 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1715 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1716 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001717 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001718 arizona_free_irq(arizona, jack_irq_rise, info);
1719 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001720 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001721 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1722 ARIZONA_JD1_ENA, 0);
1723 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001724
1725 return 0;
1726}
1727
1728static struct platform_driver arizona_extcon_driver = {
1729 .driver = {
1730 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001731 },
1732 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001733 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001734};
1735
1736module_platform_driver(arizona_extcon_driver);
1737
1738MODULE_DESCRIPTION("Arizona Extcon driver");
1739MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1740MODULE_LICENSE("GPL");
1741MODULE_ALIAS("platform:extcon-arizona");