blob: e54ce08f669cb1b5b9c1b6a6b18cd2c4a99eb99e [file] [log] [blame]
Mark Brownf2c32a82012-06-24 12:09:45 +01001/*
2 * extcon-arizona.c - Extcon driver Wolfson Arizona devices
3 *
4 * Copyright (C) 2012 Wolfson Microelectronics plc
5 *
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>
23#include <linux/gpio.h>
Mark Brown34efe4d2012-07-20 17:07:29 +010024#include <linux/input.h>
Mark Brownf2c32a82012-06-24 12:09:45 +010025#include <linux/platform_device.h>
26#include <linux/pm_runtime.h>
27#include <linux/regulator/consumer.h>
28#include <linux/extcon.h>
29
Mark Brownbbbd46e2013-01-10 19:38:43 +000030#include <sound/soc.h>
31
Mark Brownf2c32a82012-06-24 12:09:45 +010032#include <linux/mfd/arizona/core.h>
33#include <linux/mfd/arizona/pdata.h>
34#include <linux/mfd/arizona/registers.h>
35
Mark Brown6fed4d82013-04-01 22:03:06 +010036#define ARIZONA_MAX_MICD_RANGE 8
Mark Brown34efe4d2012-07-20 17:07:29 +010037
Mark Brown4f340332013-01-11 08:55:43 +090038#define ARIZONA_ACCDET_MODE_MIC 0
39#define ARIZONA_ACCDET_MODE_HPL 1
40#define ARIZONA_ACCDET_MODE_HPR 2
41
Mark Brown9dd5e532013-04-01 19:09:45 +010042#define ARIZONA_HPDET_MAX 10000
43
Mark Brown2643fd62013-04-01 19:07:28 +010044#define HPDET_DEBOUNCE 500
Mark Brown7abd4e22013-04-01 19:25:55 +010045#define DEFAULT_MICD_TIMEOUT 2000
Mark Browna3e20782013-04-01 19:05:27 +010046
Mark Brownf2c32a82012-06-24 12:09:45 +010047struct arizona_extcon_info {
48 struct device *dev;
49 struct arizona *arizona;
50 struct mutex lock;
51 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010052 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010053
Mark Browna3e20782013-04-01 19:05:27 +010054 u16 last_jackdet;
55
Mark Brownf2c32a82012-06-24 12:09:45 +010056 int micd_mode;
57 const struct arizona_micd_config *micd_modes;
58 int micd_num_modes;
59
Mark Brown6fed4d82013-04-01 22:03:06 +010060 const struct arizona_micd_range *micd_ranges;
61 int num_micd_ranges;
62
Mark Brown7abd4e22013-04-01 19:25:55 +010063 int micd_timeout;
64
Mark Brownf2c32a82012-06-24 12:09:45 +010065 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090066 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010067
Mark Brown0e27bd32013-02-05 21:00:15 +000068 struct delayed_work hpdet_work;
Mark Browncd59e792013-04-01 19:21:48 +010069 struct delayed_work micd_detect_work;
Mark Brown939c5672013-04-01 19:17:34 +010070 struct delayed_work micd_timeout_work;
Mark Brown0e27bd32013-02-05 21:00:15 +000071
Mark Brown4f340332013-01-11 08:55:43 +090072 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000073 bool hpdet_done;
Mark Brown9dd5e532013-04-01 19:09:45 +010074 bool hpdet_retried;
Mark Brown4f340332013-01-11 08:55:43 +090075
Mark Browndd235ee2013-01-11 08:55:51 +090076 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090077 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090078
Mark Brownf2c32a82012-06-24 12:09:45 +010079 bool mic;
80 bool detecting;
81 int jack_flips;
82
Mark Brown4f340332013-01-11 08:55:43 +090083 int hpdet_ip;
84
Mark Brownf2c32a82012-06-24 12:09:45 +010085 struct extcon_dev edev;
86};
87
88static const struct arizona_micd_config micd_default_modes[] = {
Charles Keepax41024242013-09-23 14:33:59 +010089 { ARIZONA_ACCDET_SRC, 1, 0 },
90 { 0, 2, 1 },
Mark Brownf2c32a82012-06-24 12:09:45 +010091};
92
Mark Brown6fed4d82013-04-01 22:03:06 +010093static const struct arizona_micd_range micd_default_ranges[] = {
94 { .max = 11, .key = BTN_0 },
95 { .max = 28, .key = BTN_1 },
96 { .max = 54, .key = BTN_2 },
97 { .max = 100, .key = BTN_3 },
98 { .max = 186, .key = BTN_4 },
99 { .max = 430, .key = BTN_5 },
100};
101
102static const int arizona_micd_levels[] = {
103 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
104 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
105 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
106 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
107 1257,
Mark Brown34efe4d2012-07-20 17:07:29 +0100108};
109
Mark Brown325c6422012-06-28 13:08:30 +0100110#define ARIZONA_CABLE_MECHANICAL 0
111#define ARIZONA_CABLE_MICROPHONE 1
112#define ARIZONA_CABLE_HEADPHONE 2
Mark Brown4f340332013-01-11 08:55:43 +0900113#define ARIZONA_CABLE_LINEOUT 3
Mark Brownf2c32a82012-06-24 12:09:45 +0100114
115static const char *arizona_cable[] = {
Mark Brown325c6422012-06-28 13:08:30 +0100116 "Mechanical",
117 "Microphone",
118 "Headphone",
Mark Brown4f340332013-01-11 08:55:43 +0900119 "Line-out",
Mark Brownf2c32a82012-06-24 12:09:45 +0100120 NULL,
121};
122
Mark Brown9dd5e532013-04-01 19:09:45 +0100123static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
124
Mark Brown03409072013-02-12 13:00:31 +0000125static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
126 unsigned int magic)
127{
128 struct arizona *arizona = info->arizona;
Mark Brown03409072013-02-12 13:00:31 +0000129 int ret;
130
131 mutex_lock(&arizona->dapm->card->dapm_mutex);
132
Mark Browndf8c3db2013-02-22 18:38:03 +0000133 arizona->hpdet_magic = magic;
134
135 /* Keep the HP output stages disabled while doing the magic */
136 if (magic) {
137 ret = regmap_update_bits(arizona->regmap,
138 ARIZONA_OUTPUT_ENABLES_1,
139 ARIZONA_OUT1L_ENA |
140 ARIZONA_OUT1R_ENA, 0);
141 if (ret != 0)
142 dev_warn(arizona->dev,
143 "Failed to disable headphone outputs: %d\n",
144 ret);
Mark Brown03409072013-02-12 13:00:31 +0000145 }
146
Mark Browndf8c3db2013-02-22 18:38:03 +0000147 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
148 magic);
149 if (ret != 0)
150 dev_warn(arizona->dev, "Failed to do magic: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000151 ret);
152
Mark Browndf8c3db2013-02-22 18:38:03 +0000153 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
154 magic);
155 if (ret != 0)
156 dev_warn(arizona->dev, "Failed to do magic: %d\n",
157 ret);
158
159 /* Restore the desired state while not doing the magic */
160 if (!magic) {
161 ret = regmap_update_bits(arizona->regmap,
162 ARIZONA_OUTPUT_ENABLES_1,
163 ARIZONA_OUT1L_ENA |
164 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000165 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000166 dev_warn(arizona->dev,
167 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000168 ret);
169 }
170
171 mutex_unlock(&arizona->dapm->card->dapm_mutex);
172}
173
Mark Brownf2c32a82012-06-24 12:09:45 +0100174static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
175{
176 struct arizona *arizona = info->arizona;
177
Mark Brown6fed4d82013-04-01 22:03:06 +0100178 mode %= info->micd_num_modes;
Mark Brown84eaa132013-01-25 20:14:44 +0800179
Mark Browncd74f7b2012-11-27 16:14:26 +0900180 if (arizona->pdata.micd_pol_gpio > 0)
181 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
182 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100183 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
184 ARIZONA_MICD_BIAS_SRC_MASK,
Charles Keepax41024242013-09-23 14:33:59 +0100185 info->micd_modes[mode].bias <<
186 ARIZONA_MICD_BIAS_SRC_SHIFT);
Mark Brownf2c32a82012-06-24 12:09:45 +0100187 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
188 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
189
190 info->micd_mode = mode;
191
192 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
193}
194
Mark Brownbbbd46e2013-01-10 19:38:43 +0000195static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
196{
Charles Keepax41024242013-09-23 14:33:59 +0100197 switch (info->micd_modes[0].bias) {
Mark Brownbbbd46e2013-01-10 19:38:43 +0000198 case 1:
199 return "MICBIAS1";
200 case 2:
201 return "MICBIAS2";
202 case 3:
203 return "MICBIAS3";
204 default:
205 return "MICVDD";
206 }
207}
208
209static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
210{
211 struct arizona *arizona = info->arizona;
212 const char *widget = arizona_extcon_get_micbias(info);
213 struct snd_soc_dapm_context *dapm = arizona->dapm;
214 int ret;
215
216 mutex_lock(&dapm->card->dapm_mutex);
217
218 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
219 if (ret != 0)
220 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
221 widget, ret);
222
223 mutex_unlock(&dapm->card->dapm_mutex);
224
225 snd_soc_dapm_sync(dapm);
226
227 if (!arizona->pdata.micd_force_micbias) {
228 mutex_lock(&dapm->card->dapm_mutex);
229
230 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
231 if (ret != 0)
232 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
233 widget, ret);
234
235 mutex_unlock(&dapm->card->dapm_mutex);
236
237 snd_soc_dapm_sync(dapm);
238 }
239}
240
Mark Brown9b1270c2013-01-11 08:55:46 +0900241static void arizona_start_mic(struct arizona_extcon_info *info)
242{
243 struct arizona *arizona = info->arizona;
244 bool change;
245 int ret;
246
Mark Brown9b1270c2013-01-11 08:55:46 +0900247 /* Microphone detection can't use idle mode */
248 pm_runtime_get(info->dev);
249
Mark Brownbbbd46e2013-01-10 19:38:43 +0000250 if (info->detecting) {
251 ret = regulator_allow_bypass(info->micvdd, false);
252 if (ret != 0) {
253 dev_err(arizona->dev,
254 "Failed to regulate MICVDD: %d\n",
255 ret);
256 }
257 }
258
Mark Brown9b1270c2013-01-11 08:55:46 +0900259 ret = regulator_enable(info->micvdd);
260 if (ret != 0) {
261 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
262 ret);
263 }
264
265 if (info->micd_reva) {
266 regmap_write(arizona->regmap, 0x80, 0x3);
267 regmap_write(arizona->regmap, 0x294, 0);
268 regmap_write(arizona->regmap, 0x80, 0x0);
269 }
270
271 regmap_update_bits(arizona->regmap,
272 ARIZONA_ACCESSORY_DETECT_MODE_1,
273 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
274
Mark Brownbbbd46e2013-01-10 19:38:43 +0000275 arizona_extcon_pulse_micbias(info);
276
Mark Brown9b1270c2013-01-11 08:55:46 +0900277 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
278 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
279 &change);
280 if (!change) {
281 regulator_disable(info->micvdd);
282 pm_runtime_put_autosuspend(info->dev);
283 }
284}
285
286static void arizona_stop_mic(struct arizona_extcon_info *info)
287{
288 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000289 const char *widget = arizona_extcon_get_micbias(info);
290 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900291 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000292 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900293
294 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
295 ARIZONA_MICD_ENA, 0,
296 &change);
297
Mark Brownbbbd46e2013-01-10 19:38:43 +0000298 mutex_lock(&dapm->card->dapm_mutex);
299
300 ret = snd_soc_dapm_disable_pin(dapm, widget);
301 if (ret != 0)
302 dev_warn(arizona->dev,
303 "Failed to disable %s: %d\n",
304 widget, ret);
305
306 mutex_unlock(&dapm->card->dapm_mutex);
307
308 snd_soc_dapm_sync(dapm);
309
Mark Brown9b1270c2013-01-11 08:55:46 +0900310 if (info->micd_reva) {
311 regmap_write(arizona->regmap, 0x80, 0x3);
312 regmap_write(arizona->regmap, 0x294, 2);
313 regmap_write(arizona->regmap, 0x80, 0x0);
314 }
315
Mark Brownbbbd46e2013-01-10 19:38:43 +0000316 ret = regulator_allow_bypass(info->micvdd, true);
317 if (ret != 0) {
318 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
319 ret);
320 }
321
Mark Brown9b1270c2013-01-11 08:55:46 +0900322 if (change) {
323 regulator_disable(info->micvdd);
324 pm_runtime_mark_last_busy(info->dev);
325 pm_runtime_put_autosuspend(info->dev);
326 }
327}
328
Mark Brown4f340332013-01-11 08:55:43 +0900329static struct {
330 unsigned int factor_a;
331 unsigned int factor_b;
332} arizona_hpdet_b_ranges[] = {
333 { 5528, 362464 },
334 { 11084, 6186851 },
335 { 11065, 65460395 },
336};
337
338static struct {
339 int min;
340 int max;
341} arizona_hpdet_c_ranges[] = {
342 { 0, 30 },
343 { 8, 100 },
344 { 100, 1000 },
345 { 1000, 10000 },
346};
347
348static int arizona_hpdet_read(struct arizona_extcon_info *info)
349{
350 struct arizona *arizona = info->arizona;
351 unsigned int val, range;
352 int ret;
353
354 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
355 if (ret != 0) {
356 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
357 ret);
358 return ret;
359 }
360
361 switch (info->hpdet_ip) {
362 case 0:
363 if (!(val & ARIZONA_HP_DONE)) {
364 dev_err(arizona->dev, "HPDET did not complete: %x\n",
365 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900366 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900367 }
368
369 val &= ARIZONA_HP_LVL_MASK;
370 break;
371
372 case 1:
373 if (!(val & ARIZONA_HP_DONE_B)) {
374 dev_err(arizona->dev, "HPDET did not complete: %x\n",
375 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900376 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900377 }
378
379 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
380 if (ret != 0) {
381 dev_err(arizona->dev, "Failed to read HP value: %d\n",
382 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900383 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900384 }
385
386 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
387 &range);
388 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
389 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
390
391 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100392 (val < 100 || val >= 0x3fb)) {
Mark Brown4f340332013-01-11 08:55:43 +0900393 range++;
394 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
395 range);
396 regmap_update_bits(arizona->regmap,
397 ARIZONA_HEADPHONE_DETECT_1,
398 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
399 range <<
400 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
401 return -EAGAIN;
402 }
403
404 /* If we go out of range report top of range */
Charles Keepax4ba1a9f2013-09-23 14:33:58 +0100405 if (val < 100 || val >= 0x3fb) {
Mark Brown4f340332013-01-11 08:55:43 +0900406 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100407 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900408 }
409
410 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
411 val, range);
412
413 val = arizona_hpdet_b_ranges[range].factor_b
414 / ((val * 100) -
415 arizona_hpdet_b_ranges[range].factor_a);
416 break;
417
418 default:
419 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
420 info->hpdet_ip);
421 case 2:
422 if (!(val & ARIZONA_HP_DONE_B)) {
423 dev_err(arizona->dev, "HPDET did not complete: %x\n",
424 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900425 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900426 }
427
428 val &= ARIZONA_HP_LVL_B_MASK;
429
430 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
431 &range);
432 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
433 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
434
435 /* Skip up or down a range? */
436 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
437 range--;
438 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
439 arizona_hpdet_c_ranges[range].min,
440 arizona_hpdet_c_ranges[range].max);
441 regmap_update_bits(arizona->regmap,
442 ARIZONA_HEADPHONE_DETECT_1,
443 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
444 range <<
445 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
446 return -EAGAIN;
447 }
448
449 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
450 (val >= arizona_hpdet_c_ranges[range].max)) {
451 range++;
452 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
453 arizona_hpdet_c_ranges[range].min,
454 arizona_hpdet_c_ranges[range].max);
455 regmap_update_bits(arizona->regmap,
456 ARIZONA_HEADPHONE_DETECT_1,
457 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
458 range <<
459 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
460 return -EAGAIN;
461 }
462 }
463
464 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
465 return val;
466}
467
Mark Brown9c2ba272013-02-25 23:42:31 +0000468static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
469 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900470{
471 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900472 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900473
474 /*
475 * If we're using HPDET for accessory identification we need
476 * to take multiple measurements, step through them in sequence.
477 */
478 if (arizona->pdata.hpdet_acc_id) {
479 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900480
481 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000482 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900483 dev_dbg(arizona->dev, "Measuring mic\n");
484
485 regmap_update_bits(arizona->regmap,
486 ARIZONA_ACCESSORY_DETECT_MODE_1,
487 ARIZONA_ACCDET_MODE_MASK |
488 ARIZONA_ACCDET_SRC,
489 ARIZONA_ACCDET_MODE_HPR |
490 info->micd_modes[0].src);
491
492 gpio_set_value_cansleep(id_gpio, 1);
493
Mark Browndd235ee2013-01-11 08:55:51 +0900494 regmap_update_bits(arizona->regmap,
495 ARIZONA_HEADPHONE_DETECT_1,
496 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
497 return -EAGAIN;
498 }
499
500 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000501 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
502 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000503
504 /* Take the headphone impedance for the main report */
505 *reading = info->hpdet_res[0];
506
Mark Brown9dd5e532013-04-01 19:09:45 +0100507 /* Sometimes we get false readings due to slow insert */
508 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
509 dev_dbg(arizona->dev, "Retrying high impedance\n");
510 info->num_hpdet_res = 0;
511 info->hpdet_retried = true;
512 arizona_start_hpdet_acc_id(info);
513 pm_runtime_put(info->dev);
514 return -EAGAIN;
515 }
516
Mark Brown1eda6aa2013-01-11 08:55:54 +0900517 /*
Sachin Kamatd97abdd2013-08-05 14:30:46 +0530518 * If we measure the mic as high impedance
Mark Brown1eda6aa2013-01-11 08:55:54 +0900519 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000520 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900521 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000522 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000523 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900524 } else {
525 dev_dbg(arizona->dev, "Detected headphone\n");
526 }
527
528 /* Make sure everything is reset back to the real polarity */
529 regmap_update_bits(arizona->regmap,
530 ARIZONA_ACCESSORY_DETECT_MODE_1,
531 ARIZONA_ACCDET_SRC,
532 info->micd_modes[0].src);
533 }
534
535 return 0;
536}
537
Mark Brown4f340332013-01-11 08:55:43 +0900538static irqreturn_t arizona_hpdet_irq(int irq, void *data)
539{
540 struct arizona_extcon_info *info = data;
541 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900542 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900543 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900544 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000545 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900546
547 mutex_lock(&info->lock);
548
549 /* If we got a spurious IRQ for some reason then ignore it */
550 if (!info->hpdet_active) {
551 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
552 mutex_unlock(&info->lock);
553 return IRQ_NONE;
554 }
555
556 /* If the cable was removed while measuring ignore the result */
557 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
558 if (ret < 0) {
559 dev_err(arizona->dev, "Failed to check cable state: %d\n",
560 ret);
561 goto out;
562 } else if (!ret) {
563 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
564 goto done;
565 }
566
567 ret = arizona_hpdet_read(info);
568 if (ret == -EAGAIN) {
569 goto out;
570 } else if (ret < 0) {
571 goto done;
572 }
Mark Browndd235ee2013-01-11 08:55:51 +0900573 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900574
575 /* Reset back to starting range */
576 regmap_update_bits(arizona->regmap,
577 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900578 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
579 0);
580
Mark Brown9c2ba272013-02-25 23:42:31 +0000581 ret = arizona_hpdet_do_id(info, &reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900582 if (ret == -EAGAIN) {
583 goto out;
584 } else if (ret < 0) {
585 goto done;
586 }
Mark Brown4f340332013-01-11 08:55:43 +0900587
588 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900589 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900590 report = ARIZONA_CABLE_LINEOUT;
591 else
592 report = ARIZONA_CABLE_HEADPHONE;
593
594 ret = extcon_set_cable_state_(&info->edev, report, true);
595 if (ret != 0)
596 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
597 ret);
598
Mark Brown03409072013-02-12 13:00:31 +0000599 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900600
601done:
Mark Brown1eda6aa2013-01-11 08:55:54 +0900602 if (id_gpio)
603 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900604
605 /* Revert back to MICDET mode */
606 regmap_update_bits(arizona->regmap,
607 ARIZONA_ACCESSORY_DETECT_MODE_1,
608 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
609
610 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000611 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900612 arizona_start_mic(info);
613
614 if (info->hpdet_active) {
615 pm_runtime_put_autosuspend(info->dev);
616 info->hpdet_active = false;
617 }
618
Mark Brownbf14ee52013-02-05 20:20:17 +0000619 info->hpdet_done = true;
620
Mark Brown4f340332013-01-11 08:55:43 +0900621out:
622 mutex_unlock(&info->lock);
623
624 return IRQ_HANDLED;
625}
626
627static void arizona_identify_headphone(struct arizona_extcon_info *info)
628{
629 struct arizona *arizona = info->arizona;
630 int ret;
631
Mark Brownbf14ee52013-02-05 20:20:17 +0000632 if (info->hpdet_done)
633 return;
634
Mark Brown4f340332013-01-11 08:55:43 +0900635 dev_dbg(arizona->dev, "Starting HPDET\n");
636
637 /* Make sure we keep the device enabled during the measurement */
638 pm_runtime_get(info->dev);
639
640 info->hpdet_active = true;
641
642 if (info->mic)
643 arizona_stop_mic(info);
644
Mark Brown03409072013-02-12 13:00:31 +0000645 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900646
647 ret = regmap_update_bits(arizona->regmap,
648 ARIZONA_ACCESSORY_DETECT_MODE_1,
649 ARIZONA_ACCDET_MODE_MASK,
650 ARIZONA_ACCDET_MODE_HPL);
651 if (ret != 0) {
652 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
653 goto err;
654 }
655
656 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
657 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
658 if (ret != 0) {
659 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
660 ret);
661 goto err;
662 }
663
664 return;
665
666err:
667 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
668 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
669
670 /* Just report headphone */
671 ret = extcon_update_state(&info->edev,
672 1 << ARIZONA_CABLE_HEADPHONE,
673 1 << ARIZONA_CABLE_HEADPHONE);
674 if (ret != 0)
675 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
676
677 if (info->mic)
678 arizona_start_mic(info);
679
680 info->hpdet_active = false;
681}
Mark Browndd235ee2013-01-11 08:55:51 +0900682
683static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
684{
685 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000686 int hp_reading = 32;
687 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900688 int ret;
689
690 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
691
692 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000693 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900694
695 info->hpdet_active = true;
696
Mark Brown03409072013-02-12 13:00:31 +0000697 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900698
699 ret = regmap_update_bits(arizona->regmap,
700 ARIZONA_ACCESSORY_DETECT_MODE_1,
701 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
702 info->micd_modes[0].src |
703 ARIZONA_ACCDET_MODE_HPL);
704 if (ret != 0) {
705 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
706 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900707 }
708
Mark Brown9c2ba272013-02-25 23:42:31 +0000709 if (arizona->pdata.hpdet_acc_id_line) {
710 ret = regmap_update_bits(arizona->regmap,
711 ARIZONA_HEADPHONE_DETECT_1,
712 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
713 if (ret != 0) {
714 dev_err(arizona->dev,
715 "Can't start HPDETL measurement: %d\n",
716 ret);
717 goto err;
718 }
719 } else {
720 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900721 }
722
723 return;
724
725err:
726 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
727 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
728
729 /* Just report headphone */
730 ret = extcon_update_state(&info->edev,
731 1 << ARIZONA_CABLE_HEADPHONE,
732 1 << ARIZONA_CABLE_HEADPHONE);
733 if (ret != 0)
734 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
735
Mark Brown4f340332013-01-11 08:55:43 +0900736 info->hpdet_active = false;
737}
738
Mark Brown939c5672013-04-01 19:17:34 +0100739static void arizona_micd_timeout_work(struct work_struct *work)
740{
741 struct arizona_extcon_info *info = container_of(work,
742 struct arizona_extcon_info,
743 micd_timeout_work.work);
744
745 mutex_lock(&info->lock);
746
747 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
748 arizona_identify_headphone(info);
749
750 info->detecting = false;
751
752 arizona_stop_mic(info);
753
754 mutex_unlock(&info->lock);
755}
756
Mark Browncd59e792013-04-01 19:21:48 +0100757static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100758{
Mark Browncd59e792013-04-01 19:21:48 +0100759 struct arizona_extcon_info *info = container_of(work,
760 struct arizona_extcon_info,
761 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100762 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100763 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100764 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100765
Mark Brown939c5672013-04-01 19:17:34 +0100766 cancel_delayed_work_sync(&info->micd_timeout_work);
767
Mark Brownf2c32a82012-06-24 12:09:45 +0100768 mutex_lock(&info->lock);
769
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100770 for (i = 0; i < 10 && !(val & 0x7fc); i++) {
771 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
772 if (ret != 0) {
773 dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
774 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100775 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100776 }
777
778 dev_dbg(arizona->dev, "MICDET: %x\n", val);
779
780 if (!(val & ARIZONA_MICD_VALID)) {
781 dev_warn(arizona->dev, "Microphone detection state invalid\n");
782 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100783 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100784 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100785 }
786
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100787 if (i == 10 && !(val & 0x7fc)) {
788 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100789 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100790 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100791 }
792
793 /* Due to jack detect this should never happen */
794 if (!(val & ARIZONA_MICD_STS)) {
795 dev_warn(arizona->dev, "Detected open circuit\n");
796 info->detecting = false;
797 goto handled;
798 }
799
800 /* If we got a high impedence we should have a headset, report it. */
801 if (info->detecting && (val & 0x400)) {
Mark Brown4f340332013-01-11 08:55:43 +0900802 arizona_identify_headphone(info);
803
Mark Brown325c6422012-06-28 13:08:30 +0100804 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900805 1 << ARIZONA_CABLE_MICROPHONE,
806 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100807
808 if (ret != 0)
809 dev_err(arizona->dev, "Headset report failed: %d\n",
810 ret);
811
Mark Brownbbbd46e2013-01-10 19:38:43 +0000812 /* Don't need to regulate for button detection */
813 ret = regulator_allow_bypass(info->micvdd, false);
814 if (ret != 0) {
815 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
816 ret);
817 }
818
Mark Brownf2c32a82012-06-24 12:09:45 +0100819 info->mic = true;
820 info->detecting = false;
821 goto handled;
822 }
823
824 /* If we detected a lower impedence during initial startup
825 * then we probably have the wrong polarity, flip it. Don't
826 * do this for the lowest impedences to speed up detection of
827 * plain headphones. If both polarities report a low
828 * impedence then give up and report headphones.
829 */
830 if (info->detecting && (val & 0x3f8)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800831 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900832 dev_dbg(arizona->dev, "Detected HP/line\n");
833 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100834
Mark Brown4f340332013-01-11 08:55:43 +0900835 info->detecting = false;
836
837 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100838 } else {
839 info->micd_mode++;
840 if (info->micd_mode == info->micd_num_modes)
841 info->micd_mode = 0;
842 arizona_extcon_set_mode(info, info->micd_mode);
843
844 info->jack_flips++;
845 }
846
847 goto handled;
848 }
849
850 /*
851 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100852 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100853 */
854 if (val & 0x3fc) {
855 if (info->mic) {
856 dev_dbg(arizona->dev, "Mic button detected\n");
857
Mark Brown34efe4d2012-07-20 17:07:29 +0100858 lvl = val & ARIZONA_MICD_LVL_MASK;
859 lvl >>= ARIZONA_MICD_LVL_SHIFT;
860
Mark Brown41a57852013-04-01 19:18:18 +0100861 for (i = 0; i < info->num_micd_ranges; i++)
862 input_report_key(info->input,
863 info->micd_ranges[i].key, 0);
864
Mark Brown6fed4d82013-04-01 22:03:06 +0100865 WARN_ON(!lvl);
866 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
867 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
868 key = info->micd_ranges[ffs(lvl) - 1].key;
869 input_report_key(info->input, key, 1);
870 input_sync(info->input);
871 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100872
Mark Brownf2c32a82012-06-24 12:09:45 +0100873 } else if (info->detecting) {
874 dev_dbg(arizona->dev, "Headphone detected\n");
875 info->detecting = false;
876 arizona_stop_mic(info);
877
Mark Brown4f340332013-01-11 08:55:43 +0900878 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100879 } else {
880 dev_warn(arizona->dev, "Button with no mic: %x\n",
881 val);
882 }
883 } else {
884 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100885 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100886 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100887 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100888 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000889 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100890 }
891
892handled:
Mark Brown939c5672013-04-01 19:17:34 +0100893 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100894 queue_delayed_work(system_power_efficient_wq,
895 &info->micd_timeout_work,
896 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100897
Mark Brownf2c32a82012-06-24 12:09:45 +0100898 pm_runtime_mark_last_busy(info->dev);
899 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100900}
901
902static irqreturn_t arizona_micdet(int irq, void *data)
903{
904 struct arizona_extcon_info *info = data;
905 struct arizona *arizona = info->arizona;
906 int debounce = arizona->pdata.micd_detect_debounce;
907
908 cancel_delayed_work_sync(&info->micd_detect_work);
909 cancel_delayed_work_sync(&info->micd_timeout_work);
910
911 mutex_lock(&info->lock);
912 if (!info->detecting)
913 debounce = 0;
914 mutex_unlock(&info->lock);
915
916 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100917 queue_delayed_work(system_power_efficient_wq,
918 &info->micd_detect_work,
919 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100920 else
921 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100922
923 return IRQ_HANDLED;
924}
925
Mark Brown0e27bd32013-02-05 21:00:15 +0000926static void arizona_hpdet_work(struct work_struct *work)
927{
928 struct arizona_extcon_info *info = container_of(work,
929 struct arizona_extcon_info,
930 hpdet_work.work);
931
932 mutex_lock(&info->lock);
933 arizona_start_hpdet_acc_id(info);
934 mutex_unlock(&info->lock);
935}
936
Mark Brownf2c32a82012-06-24 12:09:45 +0100937static irqreturn_t arizona_jackdet(int irq, void *data)
938{
939 struct arizona_extcon_info *info = data;
940 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900941 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100942 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100943 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100944
Mark Brown939c5672013-04-01 19:17:34 +0100945 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
946 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100947
Mark Browna3e20782013-04-01 19:05:27 +0100948 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000949
Mark Brownf2c32a82012-06-24 12:09:45 +0100950 mutex_lock(&info->lock);
951
Mark Brown92a49872013-01-11 08:55:39 +0900952 if (arizona->pdata.jd_gpio5) {
953 mask = ARIZONA_MICD_CLAMP_STS;
954 present = 0;
955 } else {
956 mask = ARIZONA_JD1_STS;
957 present = ARIZONA_JD1_STS;
958 }
959
Mark Brownf2c32a82012-06-24 12:09:45 +0100960 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
961 if (ret != 0) {
962 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
963 ret);
964 mutex_unlock(&info->lock);
965 pm_runtime_put_autosuspend(info->dev);
966 return IRQ_NONE;
967 }
968
Mark Browna3e20782013-04-01 19:05:27 +0100969 val &= mask;
970 if (val == info->last_jackdet) {
971 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +0100972 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100973 queue_delayed_work(system_power_efficient_wq,
974 &info->hpdet_work,
975 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +0100976
Mark Brown939c5672013-04-01 19:17:34 +0100977 if (cancelled_mic)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100978 queue_delayed_work(system_power_efficient_wq,
979 &info->micd_timeout_work,
980 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100981
Mark Browna3e20782013-04-01 19:05:27 +0100982 goto out;
983 }
984 info->last_jackdet = val;
985
986 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100987 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +0100988 ret = extcon_set_cable_state_(&info->edev,
989 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100990
991 if (ret != 0)
992 dev_err(arizona->dev, "Mechanical report failed: %d\n",
993 ret);
994
Mark Browndd235ee2013-01-11 08:55:51 +0900995 if (!arizona->pdata.hpdet_acc_id) {
996 info->detecting = true;
997 info->mic = false;
998 info->jack_flips = 0;
999
1000 arizona_start_mic(info);
1001 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001002 queue_delayed_work(system_power_efficient_wq,
1003 &info->hpdet_work,
1004 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001005 }
Mark Brown4e616872013-01-15 22:09:20 +09001006
1007 regmap_update_bits(arizona->regmap,
1008 ARIZONA_JACK_DETECT_DEBOUNCE,
1009 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001010 } else {
1011 dev_dbg(arizona->dev, "Detected jack removal\n");
1012
1013 arizona_stop_mic(info);
1014
Mark Browndd235ee2013-01-11 08:55:51 +09001015 info->num_hpdet_res = 0;
1016 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1017 info->hpdet_res[i] = 0;
1018 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001019 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001020 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001021
Mark Brown6fed4d82013-04-01 22:03:06 +01001022 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001023 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001024 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001025 input_sync(info->input);
1026
Mark Brownf2c32a82012-06-24 12:09:45 +01001027 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
1028 if (ret != 0)
1029 dev_err(arizona->dev, "Removal report failed: %d\n",
1030 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001031
1032 regmap_update_bits(arizona->regmap,
1033 ARIZONA_JACK_DETECT_DEBOUNCE,
1034 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1035 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001036 }
1037
Mark Brown7abd4e22013-04-01 19:25:55 +01001038 if (arizona->pdata.micd_timeout)
1039 info->micd_timeout = arizona->pdata.micd_timeout;
1040 else
1041 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1042
Charles Keepaxcb9005d2013-08-07 12:17:14 +01001043out:
Charles Keepax5d9ab702013-02-05 10:13:38 +00001044 /* Clear trig_sts to make sure DCVDD is not forced up */
1045 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1046 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1047 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1048 ARIZONA_JD1_FALL_TRIG_STS |
1049 ARIZONA_JD1_RISE_TRIG_STS);
1050
Mark Brownf2c32a82012-06-24 12:09:45 +01001051 mutex_unlock(&info->lock);
1052
1053 pm_runtime_mark_last_busy(info->dev);
1054 pm_runtime_put_autosuspend(info->dev);
1055
1056 return IRQ_HANDLED;
1057}
1058
Mark Brown6fed4d82013-04-01 22:03:06 +01001059/* Map a level onto a slot in the register bank */
1060static void arizona_micd_set_level(struct arizona *arizona, int index,
1061 unsigned int level)
1062{
1063 int reg;
1064 unsigned int mask;
1065
1066 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1067
1068 if (!(index % 2)) {
1069 mask = 0x3f00;
1070 level <<= 8;
1071 } else {
1072 mask = 0x3f;
1073 }
1074
1075 /* Program the level itself */
1076 regmap_update_bits(arizona->regmap, reg, mask, level);
1077}
1078
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001079static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001080{
1081 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
1082 struct arizona_pdata *pdata;
1083 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001084 unsigned int val;
Mark Brown92a49872013-01-11 08:55:39 +09001085 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001086 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001087
Mark Brownbbbd46e2013-01-10 19:38:43 +00001088 if (!arizona->dapm || !arizona->dapm->card)
1089 return -EPROBE_DEFER;
1090
Mark Brownf2c32a82012-06-24 12:09:45 +01001091 pdata = dev_get_platdata(arizona->dev);
1092
1093 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1094 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001095 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +01001096 ret = -ENOMEM;
1097 goto err;
1098 }
1099
1100 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1101 if (IS_ERR(info->micvdd)) {
1102 ret = PTR_ERR(info->micvdd);
1103 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
1104 goto err;
1105 }
1106
1107 mutex_init(&info->lock);
1108 info->arizona = arizona;
1109 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001110 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001111 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001112 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001113 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001114 platform_set_drvdata(pdev, info);
1115
1116 switch (arizona->type) {
1117 case WM5102:
1118 switch (arizona->rev) {
1119 case 0:
1120 info->micd_reva = true;
1121 break;
1122 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001123 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001124 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001125 break;
1126 }
1127 break;
1128 default:
1129 break;
1130 }
1131
1132 info->edev.name = "Headset Jack";
1133 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001134
1135 ret = extcon_dev_register(&info->edev, arizona->dev);
1136 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001137 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001138 ret);
1139 goto err;
1140 }
1141
Mark Brown6fed4d82013-04-01 22:03:06 +01001142 info->input = devm_input_allocate_device(&pdev->dev);
1143 if (!info->input) {
1144 dev_err(arizona->dev, "Can't allocate input dev\n");
1145 ret = -ENOMEM;
1146 goto err_register;
1147 }
1148
1149 info->input->name = "Headset";
1150 info->input->phys = "arizona/extcon";
1151 info->input->dev.parent = &pdev->dev;
1152
Mark Brownf2c32a82012-06-24 12:09:45 +01001153 if (pdata->num_micd_configs) {
1154 info->micd_modes = pdata->micd_configs;
1155 info->micd_num_modes = pdata->num_micd_configs;
1156 } else {
1157 info->micd_modes = micd_default_modes;
1158 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1159 }
1160
1161 if (arizona->pdata.micd_pol_gpio > 0) {
1162 if (info->micd_modes[0].gpio)
1163 mode = GPIOF_OUT_INIT_HIGH;
1164 else
1165 mode = GPIOF_OUT_INIT_LOW;
1166
1167 ret = devm_gpio_request_one(&pdev->dev,
1168 arizona->pdata.micd_pol_gpio,
1169 mode,
1170 "MICD polarity");
1171 if (ret != 0) {
1172 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1173 arizona->pdata.micd_pol_gpio, ret);
1174 goto err_register;
1175 }
1176 }
1177
Mark Brown1eda6aa2013-01-11 08:55:54 +09001178 if (arizona->pdata.hpdet_id_gpio > 0) {
1179 ret = devm_gpio_request_one(&pdev->dev,
1180 arizona->pdata.hpdet_id_gpio,
1181 GPIOF_OUT_INIT_LOW,
1182 "HPDET");
1183 if (ret != 0) {
1184 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1185 arizona->pdata.hpdet_id_gpio, ret);
1186 goto err_register;
1187 }
1188 }
1189
Mark Brownb17e5462013-01-11 08:55:24 +09001190 if (arizona->pdata.micd_bias_start_time)
1191 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1192 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1193 arizona->pdata.micd_bias_start_time
1194 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1195
Mark Brown2e033db2013-01-21 17:36:33 +09001196 if (arizona->pdata.micd_rate)
1197 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1198 ARIZONA_MICD_RATE_MASK,
1199 arizona->pdata.micd_rate
1200 << ARIZONA_MICD_RATE_SHIFT);
1201
1202 if (arizona->pdata.micd_dbtime)
1203 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1204 ARIZONA_MICD_DBTIME_MASK,
1205 arizona->pdata.micd_dbtime
1206 << ARIZONA_MICD_DBTIME_SHIFT);
1207
Mark Brown6fed4d82013-04-01 22:03:06 +01001208 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1209
1210 if (arizona->pdata.num_micd_ranges) {
1211 info->micd_ranges = pdata->micd_ranges;
1212 info->num_micd_ranges = pdata->num_micd_ranges;
1213 } else {
1214 info->micd_ranges = micd_default_ranges;
1215 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1216 }
1217
1218 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1219 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1220 arizona->pdata.num_micd_ranges);
1221 }
1222
1223 if (info->num_micd_ranges > 1) {
1224 for (i = 1; i < info->num_micd_ranges; i++) {
1225 if (info->micd_ranges[i - 1].max >
1226 info->micd_ranges[i].max) {
1227 dev_err(arizona->dev,
1228 "MICD ranges must be sorted\n");
1229 ret = -EINVAL;
1230 goto err_input;
1231 }
1232 }
1233 }
1234
1235 /* Disable all buttons by default */
1236 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1237 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1238
1239 /* Set up all the buttons the user specified */
1240 for (i = 0; i < info->num_micd_ranges; i++) {
1241 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1242 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1243 break;
1244
1245 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1246 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1247 info->micd_ranges[i].max);
1248 ret = -EINVAL;
1249 goto err_input;
1250 }
1251
1252 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1253 arizona_micd_levels[j], i);
1254
1255 arizona_micd_set_level(arizona, i, j);
1256 input_set_capability(info->input, EV_KEY,
1257 info->micd_ranges[i].key);
1258
1259 /* Enable reporting of that range */
1260 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1261 1 << i, 1 << i);
1262 }
1263
1264 /* Set all the remaining keys to a maximum */
1265 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1266 arizona_micd_set_level(arizona, i, 0x3f);
1267
Mark Browndab63eb2013-01-11 08:55:36 +09001268 /*
Mark Brown92a49872013-01-11 08:55:39 +09001269 * If we have a clamp use it, activating in conjunction with
1270 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001271 */
1272 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001273 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001274 /* Put the GPIO into input mode with optional pull */
1275 val = 0xc101;
1276 if (arizona->pdata.jd_gpio5_nopull)
1277 val &= ~ARIZONA_GPN_PU;
1278
Mark Brown92a49872013-01-11 08:55:39 +09001279 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001280 val);
Mark Brown92a49872013-01-11 08:55:39 +09001281
1282 regmap_update_bits(arizona->regmap,
1283 ARIZONA_MICD_CLAMP_CONTROL,
1284 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1285 } else {
1286 regmap_update_bits(arizona->regmap,
1287 ARIZONA_MICD_CLAMP_CONTROL,
1288 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1289 }
1290
Mark Browndab63eb2013-01-11 08:55:36 +09001291 regmap_update_bits(arizona->regmap,
1292 ARIZONA_JACK_DETECT_DEBOUNCE,
1293 ARIZONA_MICD_CLAMP_DB,
1294 ARIZONA_MICD_CLAMP_DB);
1295 }
1296
Mark Brownf2c32a82012-06-24 12:09:45 +01001297 arizona_extcon_set_mode(info, 0);
1298
1299 pm_runtime_enable(&pdev->dev);
1300 pm_runtime_idle(&pdev->dev);
1301 pm_runtime_get_sync(&pdev->dev);
1302
Mark Brown92a49872013-01-11 08:55:39 +09001303 if (arizona->pdata.jd_gpio5) {
1304 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1305 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1306 } else {
1307 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1308 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1309 }
1310
1311 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001312 "JACKDET rise", arizona_jackdet, info);
1313 if (ret != 0) {
1314 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1315 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001316 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001317 }
1318
Mark Brown92a49872013-01-11 08:55:39 +09001319 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001320 if (ret != 0) {
1321 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1322 ret);
1323 goto err_rise;
1324 }
1325
Mark Brown92a49872013-01-11 08:55:39 +09001326 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001327 "JACKDET fall", arizona_jackdet, info);
1328 if (ret != 0) {
1329 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1330 goto err_rise_wake;
1331 }
1332
Mark Brown92a49872013-01-11 08:55:39 +09001333 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001334 if (ret != 0) {
1335 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1336 ret);
1337 goto err_fall;
1338 }
1339
1340 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1341 "MICDET", arizona_micdet, info);
1342 if (ret != 0) {
1343 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1344 goto err_fall_wake;
1345 }
1346
Mark Brown4f340332013-01-11 08:55:43 +09001347 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1348 "HPDET", arizona_hpdet_irq, info);
1349 if (ret != 0) {
1350 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1351 goto err_micdet;
1352 }
1353
Mark Brownf2c32a82012-06-24 12:09:45 +01001354 arizona_clk32k_enable(arizona);
1355 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1356 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1357 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1358 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1359
Mark Brownb8575a12012-09-07 17:01:15 +08001360 ret = regulator_allow_bypass(info->micvdd, true);
1361 if (ret != 0)
1362 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1363 ret);
1364
Mark Brownf2c32a82012-06-24 12:09:45 +01001365 pm_runtime_put(&pdev->dev);
1366
Mark Brown34efe4d2012-07-20 17:07:29 +01001367 ret = input_register_device(info->input);
1368 if (ret) {
1369 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001370 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001371 }
1372
Mark Brownf2c32a82012-06-24 12:09:45 +01001373 return 0;
1374
Mark Brown4f340332013-01-11 08:55:43 +09001375err_hpdet:
1376 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001377err_micdet:
1378 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001379err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001380 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001381err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001382 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001383err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001384 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001385err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001386 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001387err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001388err_register:
1389 pm_runtime_disable(&pdev->dev);
1390 extcon_dev_unregister(&info->edev);
1391err:
1392 return ret;
1393}
1394
Bill Pemberton93ed0322012-11-19 13:25:49 -05001395static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001396{
1397 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1398 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001399 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001400
1401 pm_runtime_disable(&pdev->dev);
1402
Mark Browndab63eb2013-01-11 08:55:36 +09001403 regmap_update_bits(arizona->regmap,
1404 ARIZONA_MICD_CLAMP_CONTROL,
1405 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1406
Mark Brown92a49872013-01-11 08:55:39 +09001407 if (arizona->pdata.jd_gpio5) {
1408 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1409 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1410 } else {
1411 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1412 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1413 }
1414
1415 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1416 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1417 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001418 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001419 arizona_free_irq(arizona, jack_irq_rise, info);
1420 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001421 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001422 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1423 ARIZONA_JD1_ENA, 0);
1424 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001425 extcon_dev_unregister(&info->edev);
1426
1427 return 0;
1428}
1429
1430static struct platform_driver arizona_extcon_driver = {
1431 .driver = {
1432 .name = "arizona-extcon",
1433 .owner = THIS_MODULE,
1434 },
1435 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001436 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001437};
1438
1439module_platform_driver(arizona_extcon_driver);
1440
1441MODULE_DESCRIPTION("Arizona Extcon driver");
1442MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1443MODULE_LICENSE("GPL");
1444MODULE_ALIAS("platform:extcon-arizona");