blob: ec9a14e05fddd22313c25615570cbc0515d62ec9 [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";
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001133 info->edev.dev.parent = arizona->dev;
Mark Brownf2c32a82012-06-24 12:09:45 +01001134 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001135
Chanwoo Choi42d7d752013-09-27 09:20:26 +09001136 ret = extcon_dev_register(&info->edev);
Mark Brownf2c32a82012-06-24 12:09:45 +01001137 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001138 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001139 ret);
1140 goto err;
1141 }
1142
Mark Brown6fed4d82013-04-01 22:03:06 +01001143 info->input = devm_input_allocate_device(&pdev->dev);
1144 if (!info->input) {
1145 dev_err(arizona->dev, "Can't allocate input dev\n");
1146 ret = -ENOMEM;
1147 goto err_register;
1148 }
1149
1150 info->input->name = "Headset";
1151 info->input->phys = "arizona/extcon";
1152 info->input->dev.parent = &pdev->dev;
1153
Mark Brownf2c32a82012-06-24 12:09:45 +01001154 if (pdata->num_micd_configs) {
1155 info->micd_modes = pdata->micd_configs;
1156 info->micd_num_modes = pdata->num_micd_configs;
1157 } else {
1158 info->micd_modes = micd_default_modes;
1159 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1160 }
1161
1162 if (arizona->pdata.micd_pol_gpio > 0) {
1163 if (info->micd_modes[0].gpio)
1164 mode = GPIOF_OUT_INIT_HIGH;
1165 else
1166 mode = GPIOF_OUT_INIT_LOW;
1167
1168 ret = devm_gpio_request_one(&pdev->dev,
1169 arizona->pdata.micd_pol_gpio,
1170 mode,
1171 "MICD polarity");
1172 if (ret != 0) {
1173 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1174 arizona->pdata.micd_pol_gpio, ret);
1175 goto err_register;
1176 }
1177 }
1178
Mark Brown1eda6aa2013-01-11 08:55:54 +09001179 if (arizona->pdata.hpdet_id_gpio > 0) {
1180 ret = devm_gpio_request_one(&pdev->dev,
1181 arizona->pdata.hpdet_id_gpio,
1182 GPIOF_OUT_INIT_LOW,
1183 "HPDET");
1184 if (ret != 0) {
1185 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1186 arizona->pdata.hpdet_id_gpio, ret);
1187 goto err_register;
1188 }
1189 }
1190
Mark Brownb17e5462013-01-11 08:55:24 +09001191 if (arizona->pdata.micd_bias_start_time)
1192 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1193 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1194 arizona->pdata.micd_bias_start_time
1195 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1196
Mark Brown2e033db2013-01-21 17:36:33 +09001197 if (arizona->pdata.micd_rate)
1198 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1199 ARIZONA_MICD_RATE_MASK,
1200 arizona->pdata.micd_rate
1201 << ARIZONA_MICD_RATE_SHIFT);
1202
1203 if (arizona->pdata.micd_dbtime)
1204 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1205 ARIZONA_MICD_DBTIME_MASK,
1206 arizona->pdata.micd_dbtime
1207 << ARIZONA_MICD_DBTIME_SHIFT);
1208
Mark Brown6fed4d82013-04-01 22:03:06 +01001209 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1210
1211 if (arizona->pdata.num_micd_ranges) {
1212 info->micd_ranges = pdata->micd_ranges;
1213 info->num_micd_ranges = pdata->num_micd_ranges;
1214 } else {
1215 info->micd_ranges = micd_default_ranges;
1216 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1217 }
1218
1219 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1220 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1221 arizona->pdata.num_micd_ranges);
1222 }
1223
1224 if (info->num_micd_ranges > 1) {
1225 for (i = 1; i < info->num_micd_ranges; i++) {
1226 if (info->micd_ranges[i - 1].max >
1227 info->micd_ranges[i].max) {
1228 dev_err(arizona->dev,
1229 "MICD ranges must be sorted\n");
1230 ret = -EINVAL;
1231 goto err_input;
1232 }
1233 }
1234 }
1235
1236 /* Disable all buttons by default */
1237 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1238 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1239
1240 /* Set up all the buttons the user specified */
1241 for (i = 0; i < info->num_micd_ranges; i++) {
1242 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1243 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1244 break;
1245
1246 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1247 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1248 info->micd_ranges[i].max);
1249 ret = -EINVAL;
1250 goto err_input;
1251 }
1252
1253 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1254 arizona_micd_levels[j], i);
1255
1256 arizona_micd_set_level(arizona, i, j);
1257 input_set_capability(info->input, EV_KEY,
1258 info->micd_ranges[i].key);
1259
1260 /* Enable reporting of that range */
1261 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1262 1 << i, 1 << i);
1263 }
1264
1265 /* Set all the remaining keys to a maximum */
1266 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1267 arizona_micd_set_level(arizona, i, 0x3f);
1268
Mark Browndab63eb2013-01-11 08:55:36 +09001269 /*
Mark Brown92a49872013-01-11 08:55:39 +09001270 * If we have a clamp use it, activating in conjunction with
1271 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001272 */
1273 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001274 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001275 /* Put the GPIO into input mode with optional pull */
1276 val = 0xc101;
1277 if (arizona->pdata.jd_gpio5_nopull)
1278 val &= ~ARIZONA_GPN_PU;
1279
Mark Brown92a49872013-01-11 08:55:39 +09001280 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001281 val);
Mark Brown92a49872013-01-11 08:55:39 +09001282
1283 regmap_update_bits(arizona->regmap,
1284 ARIZONA_MICD_CLAMP_CONTROL,
1285 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1286 } else {
1287 regmap_update_bits(arizona->regmap,
1288 ARIZONA_MICD_CLAMP_CONTROL,
1289 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1290 }
1291
Mark Browndab63eb2013-01-11 08:55:36 +09001292 regmap_update_bits(arizona->regmap,
1293 ARIZONA_JACK_DETECT_DEBOUNCE,
1294 ARIZONA_MICD_CLAMP_DB,
1295 ARIZONA_MICD_CLAMP_DB);
1296 }
1297
Mark Brownf2c32a82012-06-24 12:09:45 +01001298 arizona_extcon_set_mode(info, 0);
1299
1300 pm_runtime_enable(&pdev->dev);
1301 pm_runtime_idle(&pdev->dev);
1302 pm_runtime_get_sync(&pdev->dev);
1303
Mark Brown92a49872013-01-11 08:55:39 +09001304 if (arizona->pdata.jd_gpio5) {
1305 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1306 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1307 } else {
1308 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1309 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1310 }
1311
1312 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001313 "JACKDET rise", arizona_jackdet, info);
1314 if (ret != 0) {
1315 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1316 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001317 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001318 }
1319
Mark Brown92a49872013-01-11 08:55:39 +09001320 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001321 if (ret != 0) {
1322 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1323 ret);
1324 goto err_rise;
1325 }
1326
Mark Brown92a49872013-01-11 08:55:39 +09001327 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001328 "JACKDET fall", arizona_jackdet, info);
1329 if (ret != 0) {
1330 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1331 goto err_rise_wake;
1332 }
1333
Mark Brown92a49872013-01-11 08:55:39 +09001334 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001335 if (ret != 0) {
1336 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1337 ret);
1338 goto err_fall;
1339 }
1340
1341 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1342 "MICDET", arizona_micdet, info);
1343 if (ret != 0) {
1344 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1345 goto err_fall_wake;
1346 }
1347
Mark Brown4f340332013-01-11 08:55:43 +09001348 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1349 "HPDET", arizona_hpdet_irq, info);
1350 if (ret != 0) {
1351 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1352 goto err_micdet;
1353 }
1354
Mark Brownf2c32a82012-06-24 12:09:45 +01001355 arizona_clk32k_enable(arizona);
1356 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1357 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1358 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1359 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1360
Mark Brownb8575a12012-09-07 17:01:15 +08001361 ret = regulator_allow_bypass(info->micvdd, true);
1362 if (ret != 0)
1363 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1364 ret);
1365
Mark Brownf2c32a82012-06-24 12:09:45 +01001366 pm_runtime_put(&pdev->dev);
1367
Mark Brown34efe4d2012-07-20 17:07:29 +01001368 ret = input_register_device(info->input);
1369 if (ret) {
1370 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001371 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001372 }
1373
Mark Brownf2c32a82012-06-24 12:09:45 +01001374 return 0;
1375
Mark Brown4f340332013-01-11 08:55:43 +09001376err_hpdet:
1377 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001378err_micdet:
1379 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001380err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001381 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001382err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001383 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001384err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001385 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001386err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001387 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001388err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001389err_register:
1390 pm_runtime_disable(&pdev->dev);
1391 extcon_dev_unregister(&info->edev);
1392err:
1393 return ret;
1394}
1395
Bill Pemberton93ed0322012-11-19 13:25:49 -05001396static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001397{
1398 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1399 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001400 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001401
1402 pm_runtime_disable(&pdev->dev);
1403
Mark Browndab63eb2013-01-11 08:55:36 +09001404 regmap_update_bits(arizona->regmap,
1405 ARIZONA_MICD_CLAMP_CONTROL,
1406 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1407
Mark Brown92a49872013-01-11 08:55:39 +09001408 if (arizona->pdata.jd_gpio5) {
1409 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1410 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1411 } else {
1412 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1413 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1414 }
1415
1416 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1417 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1418 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001419 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001420 arizona_free_irq(arizona, jack_irq_rise, info);
1421 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001422 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001423 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1424 ARIZONA_JD1_ENA, 0);
1425 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001426 extcon_dev_unregister(&info->edev);
1427
1428 return 0;
1429}
1430
1431static struct platform_driver arizona_extcon_driver = {
1432 .driver = {
1433 .name = "arizona-extcon",
1434 .owner = THIS_MODULE,
1435 },
1436 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001437 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001438};
1439
1440module_platform_driver(arizona_extcon_driver);
1441
1442MODULE_DESCRIPTION("Arizona Extcon driver");
1443MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1444MODULE_LICENSE("GPL");
1445MODULE_ALIAS("platform:extcon-arizona");