blob: aae82db542a5ecab9b9e03f43bc9130480e44bca [file] [log] [blame]
Thomas Gleixnerc942fdd2019-05-27 08:55:06 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Mark Brownf2c32a82012-06-24 12:09:45 +01002/*
3 * extcon-arizona.c - Extcon driver Wolfson Arizona devices
4 *
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +01005 * Copyright (C) 2012-2014 Wolfson Microelectronics plc
Mark Brownf2c32a82012-06-24 12:09:45 +01006 */
7
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <linux/i2c.h>
11#include <linux/slab.h>
12#include <linux/interrupt.h>
13#include <linux/err.h>
Charles Keepax8e5838d2015-06-19 17:23:31 +010014#include <linux/gpio/consumer.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010015#include <linux/gpio.h>
Mark Brown34efe4d2012-07-20 17:07:29 +010016#include <linux/input.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010017#include <linux/platform_device.h>
18#include <linux/pm_runtime.h>
Charles Keepaxfeffb0c2015-06-19 17:23:29 +010019#include <linux/property.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010020#include <linux/regulator/consumer.h>
Chanwoo Choi176aa362017-09-21 12:11:24 +090021#include <linux/extcon-provider.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010022
Mark Brownbbbd46e2013-01-10 19:38:43 +000023#include <sound/soc.h>
24
Mark Brownf2c32a82012-06-24 12:09:45 +010025#include <linux/mfd/arizona/core.h>
26#include <linux/mfd/arizona/pdata.h>
27#include <linux/mfd/arizona/registers.h>
Inha Song9e86b2a2015-05-04 13:42:13 +090028#include <dt-bindings/mfd/arizona.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010029
Mark Brown6fed4d82013-04-01 22:03:06 +010030#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010031
Richard Fitzgeralda288d642014-05-23 12:54:57 +010032#define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
33#define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
34#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
35#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
36
Charles Keepaxf719ae32015-09-16 10:42:18 +010037#define ARIZONA_TST_CAP_DEFAULT 0x3
38#define ARIZONA_TST_CAP_CLAMP 0x1
39
Mark Brown9dd5e532013-04-01 19:09:45 +010040#define ARIZONA_HPDET_MAX 10000
41
Mark Brown2643fd62013-04-01 19:07:28 +010042#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010043#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010044
Charles Keepaxe57bb432017-01-25 09:34:06 +000045#define ARIZONA_HPDET_WAIT_COUNT 15
46#define ARIZONA_HPDET_WAIT_DELAY_MS 20
47
Charles Keepaxdf8b6772015-09-16 10:42:16 +010048#define QUICK_HEADPHONE_MAX_OHM 3
49#define MICROPHONE_MIN_OHM 1257
50#define MICROPHONE_MAX_OHM 30000
51
Charles Keepaxbb327e922015-06-30 13:32:39 +010052#define MICD_DBTIME_TWO_READINGS 2
53#define MICD_DBTIME_FOUR_READINGS 4
54
Charles Keepaxffae24f2013-11-14 16:18:21 +000055#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
56 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
57 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
58 ARIZONA_MICD_LVL_7)
59
60#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
61
62#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
63
Mark Brownf2c32a82012-06-24 12:09:45 +010064struct arizona_extcon_info {
65 struct device *dev;
66 struct arizona *arizona;
67 struct mutex lock;
68 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010069 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010070
Mark Browna3e20782013-04-01 19:05:27 +010071 u16 last_jackdet;
72
Mark Brownf2c32a82012-06-24 12:09:45 +010073 int micd_mode;
74 const struct arizona_micd_config *micd_modes;
75 int micd_num_modes;
76
Mark Brown6fed4d82013-04-01 22:03:06 +010077 const struct arizona_micd_range *micd_ranges;
78 int num_micd_ranges;
79
Mark Brownf2c32a82012-06-24 12:09:45 +010080 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090081 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010082
Mark Brown0e27bd32013-02-05 21:00:15 +000083 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010084 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010085 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000086
Mark Brown4f340332013-01-11 08:55:43 +090087 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000088 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010089 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090090
Mark Browndd235ee2013-01-11 08:55:51 +090091 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090092 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090093
Mark Brownf2c32a82012-06-24 12:09:45 +010094 bool mic;
95 bool detecting;
96 int jack_flips;
97
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +010098 int hpdet_ip_version;
Mark Brown4f340332013-01-11 08:55:43 +090099
Chanwoo Choief70a212014-04-21 20:47:31 +0900100 struct extcon_dev *edev;
Charles Keepax8e5838d2015-06-19 17:23:31 +0100101
102 struct gpio_desc *micd_pol_gpio;
Mark Brownf2c32a82012-06-24 12:09:45 +0100103};
104
105static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +0100106 { ARIZONA_ACCDET_SRC, 1, 0 },
107 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +0100108};
109
Mark Brown6fed4d82013-04-01 22:03:06 +0100110static const struct arizona_micd_range micd_default_ranges[] = {
111 { .max = 11, .key = BTN_0 },
112 { .max = 28, .key = BTN_1 },
113 { .max = 54, .key = BTN_2 },
114 { .max = 100, .key = BTN_3 },
115 { .max = 186, .key = BTN_4 },
116 { .max = 430, .key = BTN_5 },
117};
118
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100119/* The number of levels in arizona_micd_levels valid for button thresholds */
120#define ARIZONA_NUM_MICD_BUTTON_LEVELS 64
121
Mark Brown6fed4d82013-04-01 22:03:06 +0100122static const int arizona_micd_levels[] = {
123 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
124 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
125 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
126 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100127 1257, 30000,
Mark Brown34efe4d2012-07-20 17:07:29 +0100128};
129
Chanwoo Choi73b6ecd2015-06-12 11:10:06 +0900130static const unsigned int arizona_cable[] = {
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900131 EXTCON_MECHANICAL,
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900132 EXTCON_JACK_MICROPHONE,
133 EXTCON_JACK_HEADPHONE,
134 EXTCON_JACK_LINE_OUT,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +0900135 EXTCON_NONE,
Mark Brownf2c32a82012-06-24 12:09:45 +0100136};
137
Mark Brown9dd5e532013-04-01 19:09:45 +0100138static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
139
Charles Keepax112bdfa2015-02-16 15:41:02 +0000140static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
141 bool clamp)
Mark Brown03409072013-02-12 13:00:31 +0000142{
143 struct arizona *arizona = info->arizona;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000144 unsigned int mask = 0, val = 0;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100145 unsigned int cap_sel = 0;
Mark Brown03409072013-02-12 13:00:31 +0000146 int ret;
147
Charles Keepax43f0acd2015-02-16 15:41:03 +0000148 switch (arizona->type) {
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100149 case WM8998:
150 case WM1814:
151 mask = 0;
152 break;
Charles Keepax43f0acd2015-02-16 15:41:03 +0000153 case WM5110:
Charles Keepax2b51f9c2015-04-30 23:43:37 +0900154 case WM8280:
Charles Keepax43f0acd2015-02-16 15:41:03 +0000155 mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
156 ARIZONA_HP1L_SHRTI;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100157 if (clamp) {
Charles Keepax43f0acd2015-02-16 15:41:03 +0000158 val = ARIZONA_HP1L_SHRTO;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100159 cap_sel = ARIZONA_TST_CAP_CLAMP;
160 } else {
Charles Keepax43f0acd2015-02-16 15:41:03 +0000161 val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
Charles Keepaxf719ae32015-09-16 10:42:18 +0100162 cap_sel = ARIZONA_TST_CAP_DEFAULT;
163 }
164
165 ret = regmap_update_bits(arizona->regmap,
166 ARIZONA_HP_TEST_CTRL_1,
167 ARIZONA_HP1_TST_CAP_SEL_MASK,
168 cap_sel);
169 if (ret != 0)
170 dev_warn(arizona->dev,
171 "Failed to set TST_CAP_SEL: %d\n", ret);
Charles Keepax43f0acd2015-02-16 15:41:03 +0000172 break;
173 default:
174 mask = ARIZONA_RMV_SHRT_HP1L;
175 if (clamp)
176 val = ARIZONA_RMV_SHRT_HP1L;
177 break;
Charles Keepaxc19dc202016-07-19 13:23:56 +0100178 }
Charles Keepax112bdfa2015-02-16 15:41:02 +0000179
Charles Keepax03bf1ad2015-12-29 16:32:03 +0000180 snd_soc_dapm_mutex_lock(arizona->dapm);
Mark Brown03409072013-02-12 13:00:31 +0000181
Charles Keepax112bdfa2015-02-16 15:41:02 +0000182 arizona->hpdet_clamp = clamp;
Mark Browndf8c3db2013-02-22 18:38:03 +0000183
Charles Keepax112bdfa2015-02-16 15:41:02 +0000184 /* Keep the HP output stages disabled while doing the clamp */
185 if (clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000186 ret = regmap_update_bits(arizona->regmap,
187 ARIZONA_OUTPUT_ENABLES_1,
188 ARIZONA_OUT1L_ENA |
189 ARIZONA_OUT1R_ENA, 0);
190 if (ret != 0)
191 dev_warn(arizona->dev,
192 "Failed to disable headphone outputs: %d\n",
193 ret);
Mark Brown03409072013-02-12 13:00:31 +0000194 }
195
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100196 if (mask) {
197 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
198 mask, val);
199 if (ret != 0)
200 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000201 ret);
202
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +0100203 ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
204 mask, val);
205 if (ret != 0)
206 dev_warn(arizona->dev, "Failed to do clamp: %d\n",
207 ret);
208 }
Mark Browndf8c3db2013-02-22 18:38:03 +0000209
Charles Keepax112bdfa2015-02-16 15:41:02 +0000210 /* Restore the desired state while not doing the clamp */
211 if (!clamp) {
Mark Browndf8c3db2013-02-22 18:38:03 +0000212 ret = regmap_update_bits(arizona->regmap,
213 ARIZONA_OUTPUT_ENABLES_1,
214 ARIZONA_OUT1L_ENA |
215 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000216 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000217 dev_warn(arizona->dev,
218 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000219 ret);
220 }
221
Charles Keepax03bf1ad2015-12-29 16:32:03 +0000222 snd_soc_dapm_mutex_unlock(arizona->dapm);
Mark Brown03409072013-02-12 13:00:31 +0000223}
224
Mark Brownf2c32a82012-06-24 12:09:45 +0100225static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
226{
227 struct arizona *arizona = info->arizona;
228
Mark Brown6fed4d82013-04-01 22:03:06 +0100229 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800230
Charles Keepax6c467a12016-11-25 13:44:36 +0000231 gpiod_set_value_cansleep(info->micd_pol_gpio,
232 info->micd_modes[mode].gpio);
Charles Keepax8e5838d2015-06-19 17:23:31 +0100233
Mark Brownf2c32a82012-06-24 12:09:45 +0100234 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
235 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100236 info->micd_modes[mode].bias <<
237 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100238 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
239 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
240
241 info->micd_mode = mode;
242
243 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
244}
245
Mark Brownbbbd46e2013-01-10 19:38:43 +0000246static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
247{
Charles Keepax41024242013-09-23 14:33:59 +0100248 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000249 case 1:
250 return "MICBIAS1";
251 case 2:
252 return "MICBIAS2";
253 case 3:
254 return "MICBIAS3";
255 default:
256 return "MICVDD";
257 }
258}
259
260static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
261{
262 struct arizona *arizona = info->arizona;
263 const char *widget = arizona_extcon_get_micbias(info);
264 struct snd_soc_dapm_context *dapm = arizona->dapm;
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000265 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000266 int ret;
267
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000268 ret = snd_soc_component_force_enable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000269 if (ret != 0)
270 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
271 widget, ret);
272
Mark Brownbbbd46e2013-01-10 19:38:43 +0000273 snd_soc_dapm_sync(dapm);
274
275 if (!arizona->pdata.micd_force_micbias) {
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000276 ret = snd_soc_component_disable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000277 if (ret != 0)
278 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
279 widget, ret);
280
Mark Brownbbbd46e2013-01-10 19:38:43 +0000281 snd_soc_dapm_sync(dapm);
282 }
283}
284
Mark Brown9b1270c2013-01-11 08:55:46 +0900285static void arizona_start_mic(struct arizona_extcon_info *info)
286{
287 struct arizona *arizona = info->arizona;
288 bool change;
289 int ret;
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100290 unsigned int mode;
Mark Brown9b1270c2013-01-11 08:55:46 +0900291
Mark Brown9b1270c2013-01-11 08:55:46 +0900292 /* Microphone detection can't use idle mode */
293 pm_runtime_get(info->dev);
294
Mark Brownbbbd46e2013-01-10 19:38:43 +0000295 if (info->detecting) {
296 ret = regulator_allow_bypass(info->micvdd, false);
297 if (ret != 0) {
298 dev_err(arizona->dev,
299 "Failed to regulate MICVDD: %d\n",
300 ret);
301 }
302 }
303
Mark Brown9b1270c2013-01-11 08:55:46 +0900304 ret = regulator_enable(info->micvdd);
305 if (ret != 0) {
306 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
307 ret);
308 }
309
310 if (info->micd_reva) {
Charles Keepaxb82f8712019-12-09 11:09:08 +0000311 const struct reg_sequence reva[] = {
312 { 0x80, 0x3 },
313 { 0x294, 0x0 },
314 { 0x80, 0x0 },
315 };
316
317 regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
Mark Brown9b1270c2013-01-11 08:55:46 +0900318 }
319
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100320 if (info->detecting && arizona->pdata.micd_software_compare)
321 mode = ARIZONA_ACCDET_MODE_ADC;
322 else
323 mode = ARIZONA_ACCDET_MODE_MIC;
324
Mark Brown9b1270c2013-01-11 08:55:46 +0900325 regmap_update_bits(arizona->regmap,
326 ARIZONA_ACCESSORY_DETECT_MODE_1,
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100327 ARIZONA_ACCDET_MODE_MASK, mode);
Mark Brown9b1270c2013-01-11 08:55:46 +0900328
Mark Brownbbbd46e2013-01-10 19:38:43 +0000329 arizona_extcon_pulse_micbias(info);
330
Charles Keepaxfbdc60b2019-05-29 10:46:05 +0100331 ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
332 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
333 &change);
334 if (ret < 0) {
335 dev_err(arizona->dev, "Failed to enable micd: %d\n", ret);
336 } else if (!change) {
Mark Brown9b1270c2013-01-11 08:55:46 +0900337 regulator_disable(info->micvdd);
338 pm_runtime_put_autosuspend(info->dev);
339 }
340}
341
342static void arizona_stop_mic(struct arizona_extcon_info *info)
343{
344 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000345 const char *widget = arizona_extcon_get_micbias(info);
346 struct snd_soc_dapm_context *dapm = arizona->dapm;
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000347 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
Charles Keepaxfbdc60b2019-05-29 10:46:05 +0100348 bool change = false;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000349 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900350
Charles Keepaxfbdc60b2019-05-29 10:46:05 +0100351 ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
352 ARIZONA_MICD_ENA, 0,
353 &change);
354 if (ret < 0)
355 dev_err(arizona->dev, "Failed to disable micd: %d\n", ret);
Mark Brown9b1270c2013-01-11 08:55:46 +0900356
Richard Fitzgeraldefd95c72016-11-29 15:44:41 +0000357 ret = snd_soc_component_disable_pin(component, widget);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000358 if (ret != 0)
359 dev_warn(arizona->dev,
360 "Failed to disable %s: %d\n",
361 widget, ret);
362
Mark Brownbbbd46e2013-01-10 19:38:43 +0000363 snd_soc_dapm_sync(dapm);
364
Mark Brown9b1270c2013-01-11 08:55:46 +0900365 if (info->micd_reva) {
Charles Keepaxb82f8712019-12-09 11:09:08 +0000366 const struct reg_sequence reva[] = {
367 { 0x80, 0x3 },
368 { 0x294, 0x2 },
369 { 0x80, 0x0 },
370 };
371
372 regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
Mark Brown9b1270c2013-01-11 08:55:46 +0900373 }
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
Charles Keepax3dfa7432019-12-09 11:09:14 +0000536 if (!arizona->pdata.hpdet_acc_id)
537 return 0;
538
Mark Browndd235ee2013-01-11 08:55:51 +0900539 /*
540 * If we're using HPDET for accessory identification we need
541 * to take multiple measurements, step through them in sequence.
542 */
Charles Keepax3dfa7432019-12-09 11:09:14 +0000543 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900544
Charles Keepax3dfa7432019-12-09 11:09:14 +0000545 /* Only check the mic directly if we didn't already ID it */
546 if (id_gpio && info->num_hpdet_res == 1) {
547 dev_dbg(arizona->dev, "Measuring mic\n");
Mark Brown1eda6aa2013-01-11 08:55:54 +0900548
Mark Browndd235ee2013-01-11 08:55:51 +0900549 regmap_update_bits(arizona->regmap,
550 ARIZONA_ACCESSORY_DETECT_MODE_1,
Charles Keepax3dfa7432019-12-09 11:09:14 +0000551 ARIZONA_ACCDET_MODE_MASK |
Mark Browndd235ee2013-01-11 08:55:51 +0900552 ARIZONA_ACCDET_SRC,
Charles Keepax3dfa7432019-12-09 11:09:14 +0000553 ARIZONA_ACCDET_MODE_HPR |
Mark Browndd235ee2013-01-11 08:55:51 +0900554 info->micd_modes[0].src);
Charles Keepax3dfa7432019-12-09 11:09:14 +0000555
556 gpio_set_value_cansleep(id_gpio, 1);
557
558 regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
559 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
560 return -EAGAIN;
Mark Browndd235ee2013-01-11 08:55:51 +0900561 }
562
Charles Keepax3dfa7432019-12-09 11:09:14 +0000563 /* OK, got both. Now, compare... */
564 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
565 info->hpdet_res[0], info->hpdet_res[1]);
566
567 /* Take the headphone impedance for the main report */
568 *reading = info->hpdet_res[0];
569
570 /* Sometimes we get false readings due to slow insert */
571 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
572 dev_dbg(arizona->dev, "Retrying high impedance\n");
573 info->num_hpdet_res = 0;
574 info->hpdet_retried = true;
575 arizona_start_hpdet_acc_id(info);
576 pm_runtime_put(info->dev);
577 return -EAGAIN;
578 }
579
580 /*
581 * If we measure the mic as high impedance
582 */
583 if (!id_gpio || info->hpdet_res[1] > 50) {
584 dev_dbg(arizona->dev, "Detected mic\n");
585 *mic = true;
586 info->detecting = true;
587 } else {
588 dev_dbg(arizona->dev, "Detected headphone\n");
589 }
590
591 /* Make sure everything is reset back to the real polarity */
592 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
593 ARIZONA_ACCDET_SRC, info->micd_modes[0].src);
594
Mark Browndd235ee2013-01-11 08:55:51 +0900595 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
Mark Brown4f340332013-01-11 08:55:43 +0900669 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000670 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900671 arizona_start_mic(info);
672
673 if (info->hpdet_active) {
674 pm_runtime_put_autosuspend(info->dev);
675 info->hpdet_active = false;
676 }
677
Mark Brownbf14ee52013-02-05 20:20:17 +0000678 info->hpdet_done = true;
679
Mark Brown4f340332013-01-11 08:55:43 +0900680out:
681 mutex_unlock(&info->lock);
682
683 return IRQ_HANDLED;
684}
685
686static void arizona_identify_headphone(struct arizona_extcon_info *info)
687{
688 struct arizona *arizona = info->arizona;
689 int ret;
690
Mark Brownbf14ee52013-02-05 20:20:17 +0000691 if (info->hpdet_done)
692 return;
693
Mark Brown4f340332013-01-11 08:55:43 +0900694 dev_dbg(arizona->dev, "Starting HPDET\n");
695
696 /* Make sure we keep the device enabled during the measurement */
697 pm_runtime_get(info->dev);
698
699 info->hpdet_active = true;
700
Charles Keepaxd5aa46d2019-12-09 11:09:11 +0000701 arizona_stop_mic(info);
Mark Brown4f340332013-01-11 08:55:43 +0900702
Charles Keepax112bdfa2015-02-16 15:41:02 +0000703 arizona_extcon_hp_clamp(info, true);
Mark Brown4f340332013-01-11 08:55:43 +0900704
705 ret = regmap_update_bits(arizona->regmap,
706 ARIZONA_ACCESSORY_DETECT_MODE_1,
707 ARIZONA_ACCDET_MODE_MASK,
Inha Song9e86b2a2015-05-04 13:42:13 +0900708 arizona->pdata.hpdet_channel);
Mark Brown4f340332013-01-11 08:55:43 +0900709 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900710 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +0900711 goto err;
712 }
713
714 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
715 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
716 if (ret != 0) {
717 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
718 ret);
719 goto err;
720 }
721
722 return;
723
724err:
Charles Keepax9c8eaec2019-12-09 11:09:07 +0000725 arizona_extcon_hp_clamp(info, false);
726 pm_runtime_put_autosuspend(info->dev);
727
Mark Brown4f340332013-01-11 08:55:43 +0900728 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900729 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Brown4f340332013-01-11 08:55:43 +0900730 if (ret != 0)
731 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
732
733 if (info->mic)
734 arizona_start_mic(info);
735
736 info->hpdet_active = false;
737}
Mark Browndd235ee2013-01-11 08:55:51 +0900738
739static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
740{
741 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000742 int hp_reading = 32;
743 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900744 int ret;
745
746 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
747
748 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000749 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900750
751 info->hpdet_active = true;
752
Charles Keepax112bdfa2015-02-16 15:41:02 +0000753 arizona_extcon_hp_clamp(info, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900754
755 ret = regmap_update_bits(arizona->regmap,
756 ARIZONA_ACCESSORY_DETECT_MODE_1,
757 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
758 info->micd_modes[0].src |
Inha Song9e86b2a2015-05-04 13:42:13 +0900759 arizona->pdata.hpdet_channel);
Mark Browndd235ee2013-01-11 08:55:51 +0900760 if (ret != 0) {
Inha Song9e86b2a2015-05-04 13:42:13 +0900761 dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
Mark Browndd235ee2013-01-11 08:55:51 +0900762 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900763 }
764
Mark Brown9c2ba272013-02-25 23:42:31 +0000765 if (arizona->pdata.hpdet_acc_id_line) {
766 ret = regmap_update_bits(arizona->regmap,
767 ARIZONA_HEADPHONE_DETECT_1,
768 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
769 if (ret != 0) {
770 dev_err(arizona->dev,
771 "Can't start HPDETL measurement: %d\n",
772 ret);
773 goto err;
774 }
775 } else {
776 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900777 }
778
779 return;
780
781err:
Mark Browndd235ee2013-01-11 08:55:51 +0900782 /* Just report headphone */
Chanwoo Choi8670b452016-08-16 15:55:34 +0900783 ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
Mark Browndd235ee2013-01-11 08:55:51 +0900784 if (ret != 0)
785 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
786
Mark Brown4f340332013-01-11 08:55:43 +0900787 info->hpdet_active = false;
788}
789
Mark Brown939c5672013-04-01 19:17:34 +0100790static void arizona_micd_timeout_work(struct work_struct *work)
791{
792 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900793 struct arizona_extcon_info,
794 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100795
796 mutex_lock(&info->lock);
797
798 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
Mark Brown939c5672013-04-01 19:17:34 +0100799
800 info->detecting = false;
801
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100802 arizona_identify_headphone(info);
803
Mark Brown939c5672013-04-01 19:17:34 +0100804 mutex_unlock(&info->lock);
805}
806
Charles Keepax7e14fc42019-12-09 11:09:15 +0000807static int arizona_micd_adc_read(struct arizona_extcon_info *info)
808{
809 struct arizona *arizona = info->arizona;
810 unsigned int val;
811 int ret;
812
813 /* Must disable MICD before we read the ADCVAL */
814 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
815 ARIZONA_MICD_ENA, 0);
816
817 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
818 if (ret != 0) {
819 dev_err(arizona->dev,
820 "Failed to read MICDET_ADCVAL: %d\n", ret);
821 return ret;
822 }
823
824 dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
825
826 val &= ARIZONA_MICDET_ADCVAL_MASK;
827 if (val < ARRAY_SIZE(arizona_micd_levels))
828 val = arizona_micd_levels[val];
829 else
830 val = INT_MAX;
831
832 if (val <= QUICK_HEADPHONE_MAX_OHM)
833 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
834 else if (val <= MICROPHONE_MIN_OHM)
835 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
836 else if (val <= MICROPHONE_MAX_OHM)
837 val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
838 else
839 val = ARIZONA_MICD_LVL_8;
840
841 return val;
842}
843
844static int arizona_micd_read(struct arizona_extcon_info *info)
845{
846 struct arizona *arizona = info->arizona;
847 unsigned int val = 0;
848 int ret, i;
849
850 for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
851 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
852 if (ret != 0) {
853 dev_err(arizona->dev,
854 "Failed to read MICDET: %d\n", ret);
855 return ret;
856 }
857
858 dev_dbg(arizona->dev, "MICDET: %x\n", val);
859
860 if (!(val & ARIZONA_MICD_VALID)) {
861 dev_warn(arizona->dev,
862 "Microphone detection state invalid\n");
863 return -EINVAL;
864 }
865 }
866
867 if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
868 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
869 return -EINVAL;
870 }
871
872 return val;
873}
874
Charles Keepax4b28b252019-12-09 11:09:16 +0000875static int arizona_micdet_reading(void *priv)
Mark Brownf2c32a82012-06-24 12:09:45 +0100876{
Charles Keepax4b28b252019-12-09 11:09:16 +0000877 struct arizona_extcon_info *info = priv;
Mark Brownf2c32a82012-06-24 12:09:45 +0100878 struct arizona *arizona = info->arizona;
Charles Keepax4b28b252019-12-09 11:09:16 +0000879 int ret, val;
Charles Keepax31a847e2013-11-14 16:18:23 +0000880
Charles Keepax7e14fc42019-12-09 11:09:15 +0000881 if (info->detecting && arizona->pdata.micd_software_compare)
882 ret = arizona_micd_adc_read(info);
883 else
884 ret = arizona_micd_read(info);
885 if (ret < 0)
Charles Keepax4b28b252019-12-09 11:09:16 +0000886 return ret;
Charles Keepaxdf8b6772015-09-16 10:42:16 +0100887
Charles Keepax7e14fc42019-12-09 11:09:15 +0000888 val = ret;
Mark Brownf2c32a82012-06-24 12:09:45 +0100889
890 /* Due to jack detect this should never happen */
891 if (!(val & ARIZONA_MICD_STS)) {
892 dev_warn(arizona->dev, "Detected open circuit\n");
Charles Keepax57f70ef2015-06-25 16:47:02 +0100893 info->mic = false;
Mark Brownf2c32a82012-06-24 12:09:45 +0100894 info->detecting = false;
Charles Keepax57f70ef2015-06-25 16:47:02 +0100895 arizona_identify_headphone(info);
Charles Keepax4b28b252019-12-09 11:09:16 +0000896 return 0;
Mark Brownf2c32a82012-06-24 12:09:45 +0100897 }
898
899 /* If we got a high impedence we should have a headset, report it. */
Charles Keepax4b28b252019-12-09 11:09:16 +0000900 if (val & ARIZONA_MICD_LVL_8) {
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100901 info->mic = true;
902 info->detecting = false;
903
Mark Brown4f340332013-01-11 08:55:43 +0900904 arizona_identify_headphone(info);
905
Chanwoo Choi8670b452016-08-16 15:55:34 +0900906 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi11eecf92015-10-03 14:15:13 +0900907 EXTCON_JACK_MICROPHONE, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100908 if (ret != 0)
909 dev_err(arizona->dev, "Headset report failed: %d\n",
910 ret);
911
Mark Brownbbbd46e2013-01-10 19:38:43 +0000912 /* Don't need to regulate for button detection */
Charles Keepaxe368f522014-05-29 16:27:54 +0100913 ret = regulator_allow_bypass(info->micvdd, true);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000914 if (ret != 0) {
915 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
916 ret);
917 }
918
Charles Keepax4b28b252019-12-09 11:09:16 +0000919 return 0;
Mark Brownf2c32a82012-06-24 12:09:45 +0100920 }
921
922 /* If we detected a lower impedence during initial startup
923 * then we probably have the wrong polarity, flip it. Don't
924 * do this for the lowest impedences to speed up detection of
925 * plain headphones. If both polarities report a low
926 * impedence then give up and report headphones.
927 */
Charles Keepax4b28b252019-12-09 11:09:16 +0000928 if (val & MICD_LVL_1_TO_7) {
Mark Brown84eaa132013-01-25 20:14:44 +0800929 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900930 dev_dbg(arizona->dev, "Detected HP/line\n");
Mark Brown9ef2224d2012-06-28 13:08:31 +0100931
Mark Brown4f340332013-01-11 08:55:43 +0900932 info->detecting = false;
933
Charles Keepax0ffe8cb2015-06-19 17:23:32 +0100934 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100935 } else {
936 info->micd_mode++;
937 if (info->micd_mode == info->micd_num_modes)
938 info->micd_mode = 0;
939 arizona_extcon_set_mode(info, info->micd_mode);
940
941 info->jack_flips++;
Charles Keepax4b28b252019-12-09 11:09:16 +0000942
943 if (arizona->pdata.micd_software_compare)
944 regmap_update_bits(arizona->regmap,
945 ARIZONA_MIC_DETECT_1,
946 ARIZONA_MICD_ENA,
947 ARIZONA_MICD_ENA);
948
949 queue_delayed_work(system_power_efficient_wq,
950 &info->micd_timeout_work,
951 msecs_to_jiffies(arizona->pdata.micd_timeout));
Mark Brownf2c32a82012-06-24 12:09:45 +0100952 }
953
Charles Keepax4b28b252019-12-09 11:09:16 +0000954 return 0;
Mark Brownf2c32a82012-06-24 12:09:45 +0100955 }
956
957 /*
958 * If we're still detecting and we detect a short then we've
Charles Keepax4b28b252019-12-09 11:09:16 +0000959 * got a headphone.
960 */
961 dev_dbg(arizona->dev, "Headphone detected\n");
962 info->detecting = false;
963
964 arizona_identify_headphone(info);
965
966 return 0;
967}
968
969static int arizona_button_reading(void *priv)
970{
971 struct arizona_extcon_info *info = priv;
972 struct arizona *arizona = info->arizona;
973 int val, key, lvl, i;
974
975 val = arizona_micd_read(info);
976 if (val < 0)
977 return val;
978
979 /*
980 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100981 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100982 */
Charles Keepaxffae24f2013-11-14 16:18:21 +0000983 if (val & MICD_LVL_0_TO_7) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100984 if (info->mic) {
985 dev_dbg(arizona->dev, "Mic button detected\n");
986
Mark Brown34efe4d2012-07-20 17:07:29 +0100987 lvl = val & ARIZONA_MICD_LVL_MASK;
988 lvl >>= ARIZONA_MICD_LVL_SHIFT;
989
Mark Brown41a57852013-04-01 19:18:18 +0100990 for (i = 0; i < info->num_micd_ranges; i++)
991 input_report_key(info->input,
992 info->micd_ranges[i].key, 0);
993
Mark Brown6fed4d82013-04-01 22:03:06 +0100994 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
995 key = info->micd_ranges[ffs(lvl) - 1].key;
996 input_report_key(info->input, key, 1);
997 input_sync(info->input);
Charles Keepax8267ebc2019-12-09 11:09:13 +0000998 } else {
999 dev_err(arizona->dev, "Button out of range\n");
Mark Brown6fed4d82013-04-01 22:03:06 +01001000 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001001 } else {
1002 dev_warn(arizona->dev, "Button with no mic: %x\n",
1003 val);
1004 }
1005 } else {
1006 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +01001007 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001008 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001009 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001010 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +00001011 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001012 }
1013
Charles Keepax4b28b252019-12-09 11:09:16 +00001014 return 0;
1015}
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001016
Charles Keepax4b28b252019-12-09 11:09:16 +00001017static void arizona_micd_detect(struct work_struct *work)
1018{
1019 struct arizona_extcon_info *info = container_of(work,
1020 struct arizona_extcon_info,
1021 micd_detect_work.work);
1022 struct arizona *arizona = info->arizona;
1023 int ret;
1024
1025 cancel_delayed_work_sync(&info->micd_timeout_work);
1026
1027 mutex_lock(&info->lock);
1028
1029 /* If the cable was removed while measuring ignore the result */
1030 ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
1031 if (ret < 0) {
1032 dev_err(arizona->dev, "Failed to check cable state: %d\n",
1033 ret);
1034 mutex_unlock(&info->lock);
1035 return;
1036 } else if (!ret) {
1037 dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
1038 mutex_unlock(&info->lock);
1039 return;
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001040 }
Mark Brown939c5672013-04-01 19:17:34 +01001041
Charles Keepax4b28b252019-12-09 11:09:16 +00001042 if (info->detecting)
1043 arizona_micdet_reading(info);
1044 else
1045 arizona_button_reading(info);
1046
Mark Brownf2c32a82012-06-24 12:09:45 +01001047 pm_runtime_mark_last_busy(info->dev);
1048 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +01001049}
1050
1051static irqreturn_t arizona_micdet(int irq, void *data)
1052{
1053 struct arizona_extcon_info *info = data;
1054 struct arizona *arizona = info->arizona;
1055 int debounce = arizona->pdata.micd_detect_debounce;
1056
1057 cancel_delayed_work_sync(&info->micd_detect_work);
1058 cancel_delayed_work_sync(&info->micd_timeout_work);
1059
1060 mutex_lock(&info->lock);
1061 if (!info->detecting)
1062 debounce = 0;
1063 mutex_unlock(&info->lock);
1064
1065 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001066 queue_delayed_work(system_power_efficient_wq,
1067 &info->micd_detect_work,
1068 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +01001069 else
1070 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001071
1072 return IRQ_HANDLED;
1073}
1074
Mark Brown0e27bd32013-02-05 21:00:15 +00001075static void arizona_hpdet_work(struct work_struct *work)
1076{
1077 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001078 struct arizona_extcon_info,
1079 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +00001080
1081 mutex_lock(&info->lock);
1082 arizona_start_hpdet_acc_id(info);
1083 mutex_unlock(&info->lock);
1084}
1085
Charles Keepaxe57bb432017-01-25 09:34:06 +00001086static int arizona_hpdet_wait(struct arizona_extcon_info *info)
1087{
1088 struct arizona *arizona = info->arizona;
1089 unsigned int val;
1090 int i, ret;
1091
1092 for (i = 0; i < ARIZONA_HPDET_WAIT_COUNT; i++) {
1093 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2,
1094 &val);
1095 if (ret) {
1096 dev_err(arizona->dev,
1097 "Failed to read HPDET state: %d\n", ret);
1098 return ret;
1099 }
1100
1101 switch (info->hpdet_ip_version) {
1102 case 0:
1103 if (val & ARIZONA_HP_DONE)
1104 return 0;
1105 break;
1106 default:
1107 if (val & ARIZONA_HP_DONE_B)
1108 return 0;
1109 break;
1110 }
1111
1112 msleep(ARIZONA_HPDET_WAIT_DELAY_MS);
1113 }
1114
1115 dev_warn(arizona->dev, "HPDET did not appear to complete\n");
1116
1117 return -ETIMEDOUT;
1118}
1119
Mark Brownf2c32a82012-06-24 12:09:45 +01001120static irqreturn_t arizona_jackdet(int irq, void *data)
1121{
1122 struct arizona_extcon_info *info = data;
1123 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001124 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +01001125 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +01001126 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +01001127
Mark Brown939c5672013-04-01 19:17:34 +01001128 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
1129 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001130
Mark Browna3e20782013-04-01 19:05:27 +01001131 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +00001132
Mark Brownf2c32a82012-06-24 12:09:45 +01001133 mutex_lock(&info->lock);
1134
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001135 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001136 mask = ARIZONA_MICD_CLAMP_STS;
Nariman Poushina0ef6422015-09-16 10:42:19 +01001137 present = 0;
Mark Brown92a49872013-01-11 08:55:39 +09001138 } else {
1139 mask = ARIZONA_JD1_STS;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001140 if (arizona->pdata.jd_invert)
1141 present = 0;
1142 else
1143 present = ARIZONA_JD1_STS;
Mark Brown92a49872013-01-11 08:55:39 +09001144 }
1145
Mark Brownf2c32a82012-06-24 12:09:45 +01001146 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
1147 if (ret != 0) {
1148 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
1149 ret);
1150 mutex_unlock(&info->lock);
1151 pm_runtime_put_autosuspend(info->dev);
1152 return IRQ_NONE;
1153 }
1154
Mark Browna3e20782013-04-01 19:05:27 +01001155 val &= mask;
1156 if (val == info->last_jackdet) {
1157 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +01001158 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +01001159 queue_delayed_work(system_power_efficient_wq,
1160 &info->hpdet_work,
1161 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +01001162
Chanwoo Choic2275d22013-08-23 10:21:37 +09001163 if (cancelled_mic) {
Charles Keepaxbe87cb72019-12-09 11:09:09 +00001164 int micd_timeout = arizona->pdata.micd_timeout;
Chanwoo Choic2275d22013-08-23 10:21:37 +09001165
Mark Browndf9a5ab2013-07-18 22:42:22 +01001166 queue_delayed_work(system_power_efficient_wq,
1167 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +09001168 msecs_to_jiffies(micd_timeout));
1169 }
Mark Brown939c5672013-04-01 19:17:34 +01001170
Mark Browna3e20782013-04-01 19:05:27 +01001171 goto out;
1172 }
1173 info->last_jackdet = val;
1174
1175 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001176 dev_dbg(arizona->dev, "Detected jack\n");
Chanwoo Choi8670b452016-08-16 15:55:34 +09001177 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi2a9de9c2015-04-24 19:16:05 +09001178 EXTCON_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +01001179
1180 if (ret != 0)
1181 dev_err(arizona->dev, "Mechanical report failed: %d\n",
1182 ret);
1183
Charles Keepaxac7614f2019-12-09 11:09:10 +00001184 info->detecting = true;
1185 info->mic = false;
1186 info->jack_flips = 0;
Mark Browndd235ee2013-01-11 08:55:51 +09001187
Charles Keepaxac7614f2019-12-09 11:09:10 +00001188 if (!arizona->pdata.hpdet_acc_id) {
Mark Browndd235ee2013-01-11 08:55:51 +09001189 arizona_start_mic(info);
1190 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001191 queue_delayed_work(system_power_efficient_wq,
1192 &info->hpdet_work,
1193 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001194 }
Mark Brown4e616872013-01-15 22:09:20 +09001195
Charles Keepax6c20b932015-09-16 10:42:21 +01001196 if (info->micd_clamp || !arizona->pdata.jd_invert)
1197 regmap_update_bits(arizona->regmap,
1198 ARIZONA_JACK_DETECT_DEBOUNCE,
1199 ARIZONA_MICD_CLAMP_DB |
1200 ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001201 } else {
1202 dev_dbg(arizona->dev, "Detected jack removal\n");
1203
1204 arizona_stop_mic(info);
1205
Mark Browndd235ee2013-01-11 08:55:51 +09001206 info->num_hpdet_res = 0;
1207 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1208 info->hpdet_res[i] = 0;
1209 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001210 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001211 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001212
Mark Brown6fed4d82013-04-01 22:03:06 +01001213 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001214 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001215 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001216 input_sync(info->input);
1217
Chanwoo Choi5475e632016-07-01 02:36:49 +09001218 for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) {
Chanwoo Choi8670b452016-08-16 15:55:34 +09001219 ret = extcon_set_state_sync(info->edev,
Chanwoo Choi5475e632016-07-01 02:36:49 +09001220 arizona_cable[i], false);
1221 if (ret != 0)
1222 dev_err(arizona->dev,
1223 "Removal report failed: %d\n", ret);
1224 }
Mark Brown4e616872013-01-15 22:09:20 +09001225
Charles Keepaxe57bb432017-01-25 09:34:06 +00001226 /*
1227 * If the jack was removed during a headphone detection we
1228 * need to wait for the headphone detection to finish, as
1229 * it can not be aborted. We don't want to be able to start
1230 * a new headphone detection from a fresh insert until this
1231 * one is finished.
1232 */
1233 arizona_hpdet_wait(info);
1234
Mark Brown4e616872013-01-15 22:09:20 +09001235 regmap_update_bits(arizona->regmap,
1236 ARIZONA_JACK_DETECT_DEBOUNCE,
1237 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1238 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001239 }
1240
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001241out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001242 /* Clear trig_sts to make sure DCVDD is not forced up */
1243 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1244 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1245 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1246 ARIZONA_JD1_FALL_TRIG_STS |
1247 ARIZONA_JD1_RISE_TRIG_STS);
1248
Mark Brownf2c32a82012-06-24 12:09:45 +01001249 mutex_unlock(&info->lock);
1250
1251 pm_runtime_mark_last_busy(info->dev);
1252 pm_runtime_put_autosuspend(info->dev);
1253
1254 return IRQ_HANDLED;
1255}
1256
Mark Brown6fed4d82013-04-01 22:03:06 +01001257/* Map a level onto a slot in the register bank */
1258static void arizona_micd_set_level(struct arizona *arizona, int index,
1259 unsigned int level)
1260{
1261 int reg;
1262 unsigned int mask;
1263
1264 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1265
1266 if (!(index % 2)) {
1267 mask = 0x3f00;
1268 level <<= 8;
1269 } else {
1270 mask = 0x3f;
1271 }
1272
1273 /* Program the level itself */
1274 regmap_update_bits(arizona->regmap, reg, mask, level);
1275}
1276
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001277static int arizona_extcon_get_micd_configs(struct device *dev,
1278 struct arizona *arizona)
1279{
1280 const char * const prop = "wlf,micd-configs";
1281 const int entries_per_config = 3;
1282 struct arizona_micd_config *micd_configs;
1283 int nconfs, ret;
1284 int i, j;
1285 u32 *vals;
1286
Andy Shevchenkoa104dbc2019-07-23 20:40:21 +03001287 nconfs = device_property_count_u32(arizona->dev, prop);
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001288 if (nconfs <= 0)
1289 return 0;
1290
1291 vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
1292 if (!vals)
1293 return -ENOMEM;
1294
1295 ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
1296 if (ret < 0)
1297 goto out;
1298
1299 nconfs /= entries_per_config;
Markus Elfringcf5459a2017-04-23 22:44:19 +02001300 micd_configs = devm_kcalloc(dev, nconfs, sizeof(*micd_configs),
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001301 GFP_KERNEL);
1302 if (!micd_configs) {
1303 ret = -ENOMEM;
1304 goto out;
1305 }
1306
1307 for (i = 0, j = 0; i < nconfs; ++i) {
1308 micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
1309 micd_configs[i].bias = vals[j++];
1310 micd_configs[i].gpio = vals[j++];
1311 }
1312
1313 arizona->pdata.micd_configs = micd_configs;
1314 arizona->pdata.num_micd_configs = nconfs;
1315
1316out:
1317 kfree(vals);
1318 return ret;
1319}
1320
1321static int arizona_extcon_device_get_pdata(struct device *dev,
1322 struct arizona *arizona)
Inha Song9e86b2a2015-05-04 13:42:13 +09001323{
1324 struct arizona_pdata *pdata = &arizona->pdata;
1325 unsigned int val = ARIZONA_ACCDET_MODE_HPL;
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001326 int ret;
Inha Song9e86b2a2015-05-04 13:42:13 +09001327
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001328 device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
Inha Song9e86b2a2015-05-04 13:42:13 +09001329 switch (val) {
1330 case ARIZONA_ACCDET_MODE_HPL:
1331 case ARIZONA_ACCDET_MODE_HPR:
1332 pdata->hpdet_channel = val;
1333 break;
1334 default:
1335 dev_err(arizona->dev,
1336 "Wrong wlf,hpdet-channel DT value %d\n", val);
1337 pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
1338 }
1339
Charles Keepax4778d442015-06-19 17:23:30 +01001340 device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
1341 &pdata->micd_detect_debounce);
1342
1343 device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
1344 &pdata->micd_bias_start_time);
1345
1346 device_property_read_u32(arizona->dev, "wlf,micd-rate",
1347 &pdata->micd_rate);
1348
1349 device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
1350 &pdata->micd_dbtime);
1351
Charles Keepax7a7ef0f2015-11-23 14:51:30 +00001352 device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
Charles Keepax4778d442015-06-19 17:23:30 +01001353 &pdata->micd_timeout);
1354
1355 pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
1356 "wlf,micd-force-micbias");
1357
Charles Keepax2e87b7a2015-11-19 15:45:35 +00001358 pdata->micd_software_compare = device_property_read_bool(arizona->dev,
1359 "wlf,micd-software-compare");
1360
Charles Keepax3d7a8722015-11-19 15:45:37 +00001361 pdata->jd_invert = device_property_read_bool(arizona->dev,
1362 "wlf,jd-invert");
1363
Charles Keepax99374222015-11-19 15:45:36 +00001364 device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
1365
Charles Keepax35247c12015-11-19 15:45:38 +00001366 pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001367 "wlf,use-jd2");
Charles Keepax35247c12015-11-19 15:45:38 +00001368 pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
Charles Keepax832df9e2015-11-20 17:53:59 +09001369 "wlf,use-jd2-nopull");
Charles Keepax35247c12015-11-19 15:45:38 +00001370
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001371 ret = arizona_extcon_get_micd_configs(dev, arizona);
1372 if (ret < 0)
1373 dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
1374
Inha Song9e86b2a2015-05-04 13:42:13 +09001375 return 0;
1376}
1377
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001378static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001379{
1380 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
Charles Keepax6ac6b472013-09-28 15:34:57 +01001381 struct arizona_pdata *pdata = &arizona->pdata;
Mark Brownf2c32a82012-06-24 12:09:45 +01001382 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001383 unsigned int val;
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001384 unsigned int clamp_mode;
Mark Brown92a49872013-01-11 08:55:39 +09001385 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001386 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001387
Mark Brownbbbd46e2013-01-10 19:38:43 +00001388 if (!arizona->dapm || !arizona->dapm->card)
1389 return -EPROBE_DEFER;
1390
Mark Brownf2c32a82012-06-24 12:09:45 +01001391 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Jingoo Han0a16ee62014-07-23 10:07:09 +09001392 if (!info)
Sangjung Wood88cc362014-04-21 19:10:15 +09001393 return -ENOMEM;
Mark Brownf2c32a82012-06-24 12:09:45 +01001394
Charles Keepaxfeffb0c2015-06-19 17:23:29 +01001395 if (!dev_get_platdata(arizona->dev))
Charles Keepaxbb6da5d2015-12-14 10:37:11 +00001396 arizona_extcon_device_get_pdata(&pdev->dev, arizona);
Inha Song9e86b2a2015-05-04 13:42:13 +09001397
Charles Keepax17271f62014-07-18 12:59:00 +01001398 info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
Mark Brownf2c32a82012-06-24 12:09:45 +01001399 if (IS_ERR(info->micvdd)) {
1400 ret = PTR_ERR(info->micvdd);
1401 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001402 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001403 }
1404
1405 mutex_init(&info->lock);
1406 info->arizona = arizona;
1407 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001408 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001409 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001410 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001411 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001412 platform_set_drvdata(pdev, info);
1413
1414 switch (arizona->type) {
1415 case WM5102:
1416 switch (arizona->rev) {
1417 case 0:
1418 info->micd_reva = true;
1419 break;
1420 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001421 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001422 info->hpdet_ip_version = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001423 break;
1424 }
1425 break;
Charles Keepax77438612013-11-14 16:18:25 +00001426 case WM5110:
Richard Fitzgerald2f2b6aa2015-01-17 15:21:26 +00001427 case WM8280:
Charles Keepax77438612013-11-14 16:18:25 +00001428 switch (arizona->rev) {
1429 case 0 ... 2:
1430 break;
1431 default:
1432 info->micd_clamp = true;
Richard Fitzgeraldd0fd5fb2015-04-28 13:34:27 +01001433 info->hpdet_ip_version = 2;
Charles Keepax77438612013-11-14 16:18:25 +00001434 break;
1435 }
1436 break;
Richard Fitzgeraldd8d09562015-09-28 12:41:42 +01001437 case WM8998:
1438 case WM1814:
1439 info->micd_clamp = true;
1440 info->hpdet_ip_version = 2;
1441 break;
Mark Brownf2c32a82012-06-24 12:09:45 +01001442 default:
1443 break;
1444 }
1445
Chanwoo Choief70a212014-04-21 20:47:31 +09001446 info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
1447 if (IS_ERR(info->edev)) {
1448 dev_err(&pdev->dev, "failed to allocate extcon device\n");
1449 return -ENOMEM;
1450 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001451
Chanwoo Choief70a212014-04-21 20:47:31 +09001452 ret = devm_extcon_dev_register(&pdev->dev, info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001453 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001454 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001455 ret);
Sangjung Wood88cc362014-04-21 19:10:15 +09001456 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001457 }
1458
Mark Brown6fed4d82013-04-01 22:03:06 +01001459 info->input = devm_input_allocate_device(&pdev->dev);
1460 if (!info->input) {
1461 dev_err(arizona->dev, "Can't allocate input dev\n");
1462 ret = -ENOMEM;
Dinghao Liub2e55752020-05-23 14:17:26 +08001463 return ret;
Mark Brown6fed4d82013-04-01 22:03:06 +01001464 }
1465
1466 info->input->name = "Headset";
1467 info->input->phys = "arizona/extcon";
Mark Brown6fed4d82013-04-01 22:03:06 +01001468
Charles Keepaxbe87cb72019-12-09 11:09:09 +00001469 if (!pdata->micd_timeout)
1470 pdata->micd_timeout = DEFAULT_MICD_TIMEOUT;
1471
Mark Brownf2c32a82012-06-24 12:09:45 +01001472 if (pdata->num_micd_configs) {
1473 info->micd_modes = pdata->micd_configs;
1474 info->micd_num_modes = pdata->num_micd_configs;
1475 } else {
1476 info->micd_modes = micd_default_modes;
1477 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1478 }
1479
Charles Keepax6772a5a2015-09-16 10:42:17 +01001480 if (arizona->pdata.gpsw > 0)
1481 regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
1482 ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
1483
Charles Keepax6c467a12016-11-25 13:44:36 +00001484 if (pdata->micd_pol_gpio > 0) {
Mark Brownf2c32a82012-06-24 12:09:45 +01001485 if (info->micd_modes[0].gpio)
1486 mode = GPIOF_OUT_INIT_HIGH;
1487 else
1488 mode = GPIOF_OUT_INIT_LOW;
1489
Charles Keepax6c467a12016-11-25 13:44:36 +00001490 ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio,
1491 mode, "MICD polarity");
Mark Brownf2c32a82012-06-24 12:09:45 +01001492 if (ret != 0) {
1493 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
Charles Keepax6c467a12016-11-25 13:44:36 +00001494 pdata->micd_pol_gpio, ret);
Dinghao Liub2e55752020-05-23 14:17:26 +08001495 return ret;
Mark Brownf2c32a82012-06-24 12:09:45 +01001496 }
Charles Keepax6c467a12016-11-25 13:44:36 +00001497
1498 info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001499 } else {
1500 if (info->micd_modes[0].gpio)
1501 mode = GPIOD_OUT_HIGH;
1502 else
1503 mode = GPIOD_OUT_LOW;
1504
1505 /* We can't use devm here because we need to do the get
1506 * against the MFD device, as that is where the of_node
1507 * will reside, but if we devm against that the GPIO
1508 * will not be freed if the extcon driver is unloaded.
1509 */
1510 info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
1511 "wlf,micd-pol",
1512 GPIOD_OUT_LOW);
1513 if (IS_ERR(info->micd_pol_gpio)) {
1514 ret = PTR_ERR(info->micd_pol_gpio);
1515 dev_err(arizona->dev,
1516 "Failed to get microphone polarity GPIO: %d\n",
1517 ret);
Dinghao Liub2e55752020-05-23 14:17:26 +08001518 return ret;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001519 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001520 }
1521
Mark Brown1eda6aa2013-01-11 08:55:54 +09001522 if (arizona->pdata.hpdet_id_gpio > 0) {
1523 ret = devm_gpio_request_one(&pdev->dev,
1524 arizona->pdata.hpdet_id_gpio,
1525 GPIOF_OUT_INIT_LOW,
1526 "HPDET");
1527 if (ret != 0) {
1528 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1529 arizona->pdata.hpdet_id_gpio, ret);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001530 goto err_gpio;
Mark Brown1eda6aa2013-01-11 08:55:54 +09001531 }
1532 }
1533
Mark Brownb17e5462013-01-11 08:55:24 +09001534 if (arizona->pdata.micd_bias_start_time)
1535 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1536 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1537 arizona->pdata.micd_bias_start_time
1538 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1539
Mark Brown2e033db2013-01-21 17:36:33 +09001540 if (arizona->pdata.micd_rate)
1541 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1542 ARIZONA_MICD_RATE_MASK,
1543 arizona->pdata.micd_rate
1544 << ARIZONA_MICD_RATE_SHIFT);
1545
Charles Keepaxbb327e922015-06-30 13:32:39 +01001546 switch (arizona->pdata.micd_dbtime) {
1547 case MICD_DBTIME_FOUR_READINGS:
Mark Brown2e033db2013-01-21 17:36:33 +09001548 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1549 ARIZONA_MICD_DBTIME_MASK,
Charles Keepaxbb327e922015-06-30 13:32:39 +01001550 ARIZONA_MICD_DBTIME);
1551 break;
1552 case MICD_DBTIME_TWO_READINGS:
1553 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1554 ARIZONA_MICD_DBTIME_MASK, 0);
1555 break;
1556 default:
1557 break;
1558 }
Mark Brown2e033db2013-01-21 17:36:33 +09001559
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001560 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) <
1561 ARIZONA_NUM_MICD_BUTTON_LEVELS);
Mark Brown6fed4d82013-04-01 22:03:06 +01001562
1563 if (arizona->pdata.num_micd_ranges) {
1564 info->micd_ranges = pdata->micd_ranges;
1565 info->num_micd_ranges = pdata->num_micd_ranges;
1566 } else {
1567 info->micd_ranges = micd_default_ranges;
1568 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1569 }
1570
1571 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1572 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1573 arizona->pdata.num_micd_ranges);
1574 }
1575
1576 if (info->num_micd_ranges > 1) {
1577 for (i = 1; i < info->num_micd_ranges; i++) {
1578 if (info->micd_ranges[i - 1].max >
1579 info->micd_ranges[i].max) {
1580 dev_err(arizona->dev,
1581 "MICD ranges must be sorted\n");
1582 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001583 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001584 }
1585 }
1586 }
1587
1588 /* Disable all buttons by default */
1589 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1590 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1591
1592 /* Set up all the buttons the user specified */
1593 for (i = 0; i < info->num_micd_ranges; i++) {
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001594 for (j = 0; j < ARIZONA_NUM_MICD_BUTTON_LEVELS; j++)
Mark Brown6fed4d82013-04-01 22:03:06 +01001595 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1596 break;
1597
Charles Keepaxdf8b6772015-09-16 10:42:16 +01001598 if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
Mark Brown6fed4d82013-04-01 22:03:06 +01001599 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1600 info->micd_ranges[i].max);
1601 ret = -EINVAL;
Charles Keepax8e5838d2015-06-19 17:23:31 +01001602 goto err_gpio;
Mark Brown6fed4d82013-04-01 22:03:06 +01001603 }
1604
1605 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1606 arizona_micd_levels[j], i);
1607
1608 arizona_micd_set_level(arizona, i, j);
1609 input_set_capability(info->input, EV_KEY,
1610 info->micd_ranges[i].key);
1611
1612 /* Enable reporting of that range */
1613 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1614 1 << i, 1 << i);
1615 }
1616
1617 /* Set all the remaining keys to a maximum */
1618 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1619 arizona_micd_set_level(arizona, i, 0x3f);
1620
Mark Browndab63eb2013-01-11 08:55:36 +09001621 /*
Mark Brown92a49872013-01-11 08:55:39 +09001622 * If we have a clamp use it, activating in conjunction with
1623 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001624 */
1625 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001626 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001627 /* Put the GPIO into input mode with optional pull */
1628 val = 0xc101;
1629 if (arizona->pdata.jd_gpio5_nopull)
1630 val &= ~ARIZONA_GPN_PU;
1631
Mark Brown92a49872013-01-11 08:55:39 +09001632 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001633 val);
Mark Brown92a49872013-01-11 08:55:39 +09001634
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001635 if (arizona->pdata.jd_invert)
1636 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
1637 else
1638 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
Mark Brown92a49872013-01-11 08:55:39 +09001639 } else {
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001640 if (arizona->pdata.jd_invert)
1641 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
1642 else
1643 clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
Mark Brown92a49872013-01-11 08:55:39 +09001644 }
1645
Mark Browndab63eb2013-01-11 08:55:36 +09001646 regmap_update_bits(arizona->regmap,
Richard Fitzgeralda288d642014-05-23 12:54:57 +01001647 ARIZONA_MICD_CLAMP_CONTROL,
1648 ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
1649
1650 regmap_update_bits(arizona->regmap,
Mark Browndab63eb2013-01-11 08:55:36 +09001651 ARIZONA_JACK_DETECT_DEBOUNCE,
1652 ARIZONA_MICD_CLAMP_DB,
1653 ARIZONA_MICD_CLAMP_DB);
1654 }
1655
Mark Brownf2c32a82012-06-24 12:09:45 +01001656 arizona_extcon_set_mode(info, 0);
1657
1658 pm_runtime_enable(&pdev->dev);
1659 pm_runtime_idle(&pdev->dev);
1660 pm_runtime_get_sync(&pdev->dev);
1661
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001662 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001663 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1664 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1665 } else {
1666 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1667 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1668 }
1669
1670 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001671 "JACKDET rise", arizona_jackdet, info);
1672 if (ret != 0) {
1673 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1674 ret);
Dinghao Liub2e55752020-05-23 14:17:26 +08001675 goto err_pm;
Mark Brownf2c32a82012-06-24 12:09:45 +01001676 }
1677
Mark Brown92a49872013-01-11 08:55:39 +09001678 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001679 if (ret != 0) {
1680 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1681 ret);
1682 goto err_rise;
1683 }
1684
Mark Brown92a49872013-01-11 08:55:39 +09001685 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001686 "JACKDET fall", arizona_jackdet, info);
1687 if (ret != 0) {
1688 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1689 goto err_rise_wake;
1690 }
1691
Mark Brown92a49872013-01-11 08:55:39 +09001692 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001693 if (ret != 0) {
1694 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1695 ret);
1696 goto err_fall;
1697 }
1698
1699 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1700 "MICDET", arizona_micdet, info);
1701 if (ret != 0) {
1702 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1703 goto err_fall_wake;
1704 }
1705
Mark Brown4f340332013-01-11 08:55:43 +09001706 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1707 "HPDET", arizona_hpdet_irq, info);
1708 if (ret != 0) {
1709 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1710 goto err_micdet;
1711 }
1712
Mark Brownf2c32a82012-06-24 12:09:45 +01001713 arizona_clk32k_enable(arizona);
1714 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1715 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1716 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1717 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1718
Mark Brownb8575a12012-09-07 17:01:15 +08001719 ret = regulator_allow_bypass(info->micvdd, true);
1720 if (ret != 0)
1721 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1722 ret);
1723
Mark Brown34efe4d2012-07-20 17:07:29 +01001724 ret = input_register_device(info->input);
1725 if (ret) {
1726 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001727 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001728 }
1729
Dinghao Liub2e55752020-05-23 14:17:26 +08001730 pm_runtime_put(&pdev->dev);
1731
Mark Brownf2c32a82012-06-24 12:09:45 +01001732 return 0;
1733
Mark Brown4f340332013-01-11 08:55:43 +09001734err_hpdet:
1735 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001736err_micdet:
1737 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001738err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001739 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001740err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001741 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001742err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001743 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001744err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001745 arizona_free_irq(arizona, jack_irq_rise, info);
Dinghao Liub2e55752020-05-23 14:17:26 +08001746err_pm:
1747 pm_runtime_put(&pdev->dev);
1748 pm_runtime_disable(&pdev->dev);
Charles Keepax8e5838d2015-06-19 17:23:31 +01001749err_gpio:
1750 gpiod_put(info->micd_pol_gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +01001751 return ret;
1752}
1753
Bill Pemberton93ed0322012-11-19 13:25:49 -05001754static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001755{
1756 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1757 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001758 int jack_irq_rise, jack_irq_fall;
Charles Keepax00053de2019-04-04 17:33:56 +01001759 bool change;
Charles Keepaxfbdc60b2019-05-29 10:46:05 +01001760 int ret;
Charles Keepax00053de2019-04-04 17:33:56 +01001761
Charles Keepaxfbdc60b2019-05-29 10:46:05 +01001762 ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
1763 ARIZONA_MICD_ENA, 0,
1764 &change);
1765 if (ret < 0) {
1766 dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
1767 ret);
1768 } else if (change) {
Charles Keepax00053de2019-04-04 17:33:56 +01001769 regulator_disable(info->micvdd);
1770 pm_runtime_put(info->dev);
1771 }
Mark Brownf2c32a82012-06-24 12:09:45 +01001772
Charles Keepax8e5838d2015-06-19 17:23:31 +01001773 gpiod_put(info->micd_pol_gpio);
1774
Mark Brownf2c32a82012-06-24 12:09:45 +01001775 pm_runtime_disable(&pdev->dev);
1776
Mark Browndab63eb2013-01-11 08:55:36 +09001777 regmap_update_bits(arizona->regmap,
1778 ARIZONA_MICD_CLAMP_CONTROL,
1779 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1780
Charles Keepaxff1cb0e2015-09-16 10:42:20 +01001781 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001782 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1783 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1784 } else {
1785 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1786 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1787 }
1788
1789 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1790 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1791 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001792 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001793 arizona_free_irq(arizona, jack_irq_rise, info);
1794 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001795 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001796 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1797 ARIZONA_JD1_ENA, 0);
1798 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001799
1800 return 0;
1801}
1802
1803static struct platform_driver arizona_extcon_driver = {
1804 .driver = {
1805 .name = "arizona-extcon",
Mark Brownf2c32a82012-06-24 12:09:45 +01001806 },
1807 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001808 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001809};
1810
1811module_platform_driver(arizona_extcon_driver);
1812
1813MODULE_DESCRIPTION("Arizona Extcon driver");
1814MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1815MODULE_LICENSE("GPL");
1816MODULE_ALIAS("platform:extcon-arizona");