blob: 9431092f52fc07783cabf3c7711ea88974eab69e [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[] = {
Mark Browndd235ee2013-01-11 08:55:51 +090089 { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
Mark Brown6fed4d82013-04-01 22:03:06 +010090 { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 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,
185 info->micd_modes[mode].bias);
186 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
187 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
188
189 info->micd_mode = mode;
190
191 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
192}
193
Mark Brownbbbd46e2013-01-10 19:38:43 +0000194static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
195{
196 switch (info->micd_modes[0].bias >> ARIZONA_MICD_BIAS_SRC_SHIFT) {
197 case 1:
198 return "MICBIAS1";
199 case 2:
200 return "MICBIAS2";
201 case 3:
202 return "MICBIAS3";
203 default:
204 return "MICVDD";
205 }
206}
207
208static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
209{
210 struct arizona *arizona = info->arizona;
211 const char *widget = arizona_extcon_get_micbias(info);
212 struct snd_soc_dapm_context *dapm = arizona->dapm;
213 int ret;
214
215 mutex_lock(&dapm->card->dapm_mutex);
216
217 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
218 if (ret != 0)
219 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
220 widget, ret);
221
222 mutex_unlock(&dapm->card->dapm_mutex);
223
224 snd_soc_dapm_sync(dapm);
225
226 if (!arizona->pdata.micd_force_micbias) {
227 mutex_lock(&dapm->card->dapm_mutex);
228
229 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
230 if (ret != 0)
231 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
232 widget, ret);
233
234 mutex_unlock(&dapm->card->dapm_mutex);
235
236 snd_soc_dapm_sync(dapm);
237 }
238}
239
Mark Brown9b1270c2013-01-11 08:55:46 +0900240static void arizona_start_mic(struct arizona_extcon_info *info)
241{
242 struct arizona *arizona = info->arizona;
243 bool change;
244 int ret;
245
Mark Brown9b1270c2013-01-11 08:55:46 +0900246 /* Microphone detection can't use idle mode */
247 pm_runtime_get(info->dev);
248
Mark Brownbbbd46e2013-01-10 19:38:43 +0000249 if (info->detecting) {
250 ret = regulator_allow_bypass(info->micvdd, false);
251 if (ret != 0) {
252 dev_err(arizona->dev,
253 "Failed to regulate MICVDD: %d\n",
254 ret);
255 }
256 }
257
Mark Brown9b1270c2013-01-11 08:55:46 +0900258 ret = regulator_enable(info->micvdd);
259 if (ret != 0) {
260 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
261 ret);
262 }
263
264 if (info->micd_reva) {
265 regmap_write(arizona->regmap, 0x80, 0x3);
266 regmap_write(arizona->regmap, 0x294, 0);
267 regmap_write(arizona->regmap, 0x80, 0x0);
268 }
269
270 regmap_update_bits(arizona->regmap,
271 ARIZONA_ACCESSORY_DETECT_MODE_1,
272 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
273
Mark Brownbbbd46e2013-01-10 19:38:43 +0000274 arizona_extcon_pulse_micbias(info);
275
Mark Brown9b1270c2013-01-11 08:55:46 +0900276 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
277 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
278 &change);
279 if (!change) {
280 regulator_disable(info->micvdd);
281 pm_runtime_put_autosuspend(info->dev);
282 }
283}
284
285static void arizona_stop_mic(struct arizona_extcon_info *info)
286{
287 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000288 const char *widget = arizona_extcon_get_micbias(info);
289 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900290 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000291 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900292
293 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
294 ARIZONA_MICD_ENA, 0,
295 &change);
296
Mark Brownbbbd46e2013-01-10 19:38:43 +0000297 mutex_lock(&dapm->card->dapm_mutex);
298
299 ret = snd_soc_dapm_disable_pin(dapm, widget);
300 if (ret != 0)
301 dev_warn(arizona->dev,
302 "Failed to disable %s: %d\n",
303 widget, ret);
304
305 mutex_unlock(&dapm->card->dapm_mutex);
306
307 snd_soc_dapm_sync(dapm);
308
Mark Brown9b1270c2013-01-11 08:55:46 +0900309 if (info->micd_reva) {
310 regmap_write(arizona->regmap, 0x80, 0x3);
311 regmap_write(arizona->regmap, 0x294, 2);
312 regmap_write(arizona->regmap, 0x80, 0x0);
313 }
314
Mark Brownbbbd46e2013-01-10 19:38:43 +0000315 ret = regulator_allow_bypass(info->micvdd, true);
316 if (ret != 0) {
317 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
318 ret);
319 }
320
Mark Brown9b1270c2013-01-11 08:55:46 +0900321 if (change) {
322 regulator_disable(info->micvdd);
323 pm_runtime_mark_last_busy(info->dev);
324 pm_runtime_put_autosuspend(info->dev);
325 }
326}
327
Mark Brown4f340332013-01-11 08:55:43 +0900328static struct {
329 unsigned int factor_a;
330 unsigned int factor_b;
331} arizona_hpdet_b_ranges[] = {
332 { 5528, 362464 },
333 { 11084, 6186851 },
334 { 11065, 65460395 },
335};
336
337static struct {
338 int min;
339 int max;
340} arizona_hpdet_c_ranges[] = {
341 { 0, 30 },
342 { 8, 100 },
343 { 100, 1000 },
344 { 1000, 10000 },
345};
346
347static int arizona_hpdet_read(struct arizona_extcon_info *info)
348{
349 struct arizona *arizona = info->arizona;
350 unsigned int val, range;
351 int ret;
352
353 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
354 if (ret != 0) {
355 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
356 ret);
357 return ret;
358 }
359
360 switch (info->hpdet_ip) {
361 case 0:
362 if (!(val & ARIZONA_HP_DONE)) {
363 dev_err(arizona->dev, "HPDET did not complete: %x\n",
364 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900365 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900366 }
367
368 val &= ARIZONA_HP_LVL_MASK;
369 break;
370
371 case 1:
372 if (!(val & ARIZONA_HP_DONE_B)) {
373 dev_err(arizona->dev, "HPDET did not complete: %x\n",
374 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900375 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900376 }
377
378 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
379 if (ret != 0) {
380 dev_err(arizona->dev, "Failed to read HP value: %d\n",
381 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900382 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900383 }
384
385 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
386 &range);
387 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
388 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
389
390 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
391 (val < 100 || val > 0x3fb)) {
392 range++;
393 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
394 range);
395 regmap_update_bits(arizona->regmap,
396 ARIZONA_HEADPHONE_DETECT_1,
397 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
398 range <<
399 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
400 return -EAGAIN;
401 }
402
403 /* If we go out of range report top of range */
404 if (val < 100 || val > 0x3fb) {
405 dev_dbg(arizona->dev, "Measurement out of range\n");
Mark Brown9dd5e532013-04-01 19:09:45 +0100406 return ARIZONA_HPDET_MAX;
Mark Brown4f340332013-01-11 08:55:43 +0900407 }
408
409 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
410 val, range);
411
412 val = arizona_hpdet_b_ranges[range].factor_b
413 / ((val * 100) -
414 arizona_hpdet_b_ranges[range].factor_a);
415 break;
416
417 default:
418 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
419 info->hpdet_ip);
420 case 2:
421 if (!(val & ARIZONA_HP_DONE_B)) {
422 dev_err(arizona->dev, "HPDET did not complete: %x\n",
423 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900424 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900425 }
426
427 val &= ARIZONA_HP_LVL_B_MASK;
428
429 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
430 &range);
431 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
432 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
433
434 /* Skip up or down a range? */
435 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
436 range--;
437 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
438 arizona_hpdet_c_ranges[range].min,
439 arizona_hpdet_c_ranges[range].max);
440 regmap_update_bits(arizona->regmap,
441 ARIZONA_HEADPHONE_DETECT_1,
442 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
443 range <<
444 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
445 return -EAGAIN;
446 }
447
448 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
449 (val >= arizona_hpdet_c_ranges[range].max)) {
450 range++;
451 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
452 arizona_hpdet_c_ranges[range].min,
453 arizona_hpdet_c_ranges[range].max);
454 regmap_update_bits(arizona->regmap,
455 ARIZONA_HEADPHONE_DETECT_1,
456 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
457 range <<
458 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
459 return -EAGAIN;
460 }
461 }
462
463 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
464 return val;
465}
466
Mark Brown9c2ba272013-02-25 23:42:31 +0000467static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
468 bool *mic)
Mark Browndd235ee2013-01-11 08:55:51 +0900469{
470 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900471 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900472
473 /*
474 * If we're using HPDET for accessory identification we need
475 * to take multiple measurements, step through them in sequence.
476 */
477 if (arizona->pdata.hpdet_acc_id) {
478 info->hpdet_res[info->num_hpdet_res++] = *reading;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900479
480 /* Only check the mic directly if we didn't already ID it */
Mark Brown9c2ba272013-02-25 23:42:31 +0000481 if (id_gpio && info->num_hpdet_res == 1) {
Mark Brown1eda6aa2013-01-11 08:55:54 +0900482 dev_dbg(arizona->dev, "Measuring mic\n");
483
484 regmap_update_bits(arizona->regmap,
485 ARIZONA_ACCESSORY_DETECT_MODE_1,
486 ARIZONA_ACCDET_MODE_MASK |
487 ARIZONA_ACCDET_SRC,
488 ARIZONA_ACCDET_MODE_HPR |
489 info->micd_modes[0].src);
490
491 gpio_set_value_cansleep(id_gpio, 1);
492
Mark Browndd235ee2013-01-11 08:55:51 +0900493 regmap_update_bits(arizona->regmap,
494 ARIZONA_HEADPHONE_DETECT_1,
495 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
496 return -EAGAIN;
497 }
498
499 /* OK, got both. Now, compare... */
Mark Brown9c2ba272013-02-25 23:42:31 +0000500 dev_dbg(arizona->dev, "HPDET measured %d %d\n",
501 info->hpdet_res[0], info->hpdet_res[1]);
Mark Brownc37b3872013-02-05 17:48:49 +0000502
503 /* Take the headphone impedance for the main report */
504 *reading = info->hpdet_res[0];
505
Mark Brown9dd5e532013-04-01 19:09:45 +0100506 /* Sometimes we get false readings due to slow insert */
507 if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
508 dev_dbg(arizona->dev, "Retrying high impedance\n");
509 info->num_hpdet_res = 0;
510 info->hpdet_retried = true;
511 arizona_start_hpdet_acc_id(info);
512 pm_runtime_put(info->dev);
513 return -EAGAIN;
514 }
515
Mark Brown1eda6aa2013-01-11 08:55:54 +0900516 /*
Mark Brown9c2ba272013-02-25 23:42:31 +0000517 * If we measure the mic as
Mark Brown1eda6aa2013-01-11 08:55:54 +0900518 */
Mark Brown9c2ba272013-02-25 23:42:31 +0000519 if (!id_gpio || info->hpdet_res[1] > 50) {
Mark Browndd235ee2013-01-11 08:55:51 +0900520 dev_dbg(arizona->dev, "Detected mic\n");
Mark Brown9c2ba272013-02-25 23:42:31 +0000521 *mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000522 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900523 } else {
524 dev_dbg(arizona->dev, "Detected headphone\n");
525 }
526
527 /* Make sure everything is reset back to the real polarity */
528 regmap_update_bits(arizona->regmap,
529 ARIZONA_ACCESSORY_DETECT_MODE_1,
530 ARIZONA_ACCDET_SRC,
531 info->micd_modes[0].src);
532 }
533
534 return 0;
535}
536
Mark Brown4f340332013-01-11 08:55:43 +0900537static irqreturn_t arizona_hpdet_irq(int irq, void *data)
538{
539 struct arizona_extcon_info *info = data;
540 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900541 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900542 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900543 int ret, reading;
Mark Brown9c2ba272013-02-25 23:42:31 +0000544 bool mic = false;
Mark Brown4f340332013-01-11 08:55:43 +0900545
546 mutex_lock(&info->lock);
547
548 /* If we got a spurious IRQ for some reason then ignore it */
549 if (!info->hpdet_active) {
550 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
551 mutex_unlock(&info->lock);
552 return IRQ_NONE;
553 }
554
555 /* If the cable was removed while measuring ignore the result */
556 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
557 if (ret < 0) {
558 dev_err(arizona->dev, "Failed to check cable state: %d\n",
559 ret);
560 goto out;
561 } else if (!ret) {
562 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
563 goto done;
564 }
565
566 ret = arizona_hpdet_read(info);
567 if (ret == -EAGAIN) {
568 goto out;
569 } else if (ret < 0) {
570 goto done;
571 }
Mark Browndd235ee2013-01-11 08:55:51 +0900572 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900573
574 /* Reset back to starting range */
575 regmap_update_bits(arizona->regmap,
576 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900577 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
578 0);
579
Mark Brown9c2ba272013-02-25 23:42:31 +0000580 ret = arizona_hpdet_do_id(info, &reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900581 if (ret == -EAGAIN) {
582 goto out;
583 } else if (ret < 0) {
584 goto done;
585 }
Mark Brown4f340332013-01-11 08:55:43 +0900586
587 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900588 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900589 report = ARIZONA_CABLE_LINEOUT;
590 else
591 report = ARIZONA_CABLE_HEADPHONE;
592
593 ret = extcon_set_cable_state_(&info->edev, report, true);
594 if (ret != 0)
595 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
596 ret);
597
Mark Brown03409072013-02-12 13:00:31 +0000598 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900599
600done:
Mark Brown1eda6aa2013-01-11 08:55:54 +0900601 if (id_gpio)
602 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900603
604 /* Revert back to MICDET mode */
605 regmap_update_bits(arizona->regmap,
606 ARIZONA_ACCESSORY_DETECT_MODE_1,
607 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
608
609 /* If we have a mic then reenable MICDET */
Mark Brown9c2ba272013-02-25 23:42:31 +0000610 if (mic || info->mic)
Mark Brown4f340332013-01-11 08:55:43 +0900611 arizona_start_mic(info);
612
613 if (info->hpdet_active) {
614 pm_runtime_put_autosuspend(info->dev);
615 info->hpdet_active = false;
616 }
617
Mark Brownbf14ee52013-02-05 20:20:17 +0000618 info->hpdet_done = true;
619
Mark Brown4f340332013-01-11 08:55:43 +0900620out:
621 mutex_unlock(&info->lock);
622
623 return IRQ_HANDLED;
624}
625
626static void arizona_identify_headphone(struct arizona_extcon_info *info)
627{
628 struct arizona *arizona = info->arizona;
629 int ret;
630
Mark Brownbf14ee52013-02-05 20:20:17 +0000631 if (info->hpdet_done)
632 return;
633
Mark Brown4f340332013-01-11 08:55:43 +0900634 dev_dbg(arizona->dev, "Starting HPDET\n");
635
636 /* Make sure we keep the device enabled during the measurement */
637 pm_runtime_get(info->dev);
638
639 info->hpdet_active = true;
640
641 if (info->mic)
642 arizona_stop_mic(info);
643
Mark Brown03409072013-02-12 13:00:31 +0000644 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900645
646 ret = regmap_update_bits(arizona->regmap,
647 ARIZONA_ACCESSORY_DETECT_MODE_1,
648 ARIZONA_ACCDET_MODE_MASK,
649 ARIZONA_ACCDET_MODE_HPL);
650 if (ret != 0) {
651 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
652 goto err;
653 }
654
655 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
656 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
657 if (ret != 0) {
658 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
659 ret);
660 goto err;
661 }
662
663 return;
664
665err:
666 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
667 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
668
669 /* Just report headphone */
670 ret = extcon_update_state(&info->edev,
671 1 << ARIZONA_CABLE_HEADPHONE,
672 1 << ARIZONA_CABLE_HEADPHONE);
673 if (ret != 0)
674 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
675
676 if (info->mic)
677 arizona_start_mic(info);
678
679 info->hpdet_active = false;
680}
Mark Browndd235ee2013-01-11 08:55:51 +0900681
682static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
683{
684 struct arizona *arizona = info->arizona;
Mark Brown9c2ba272013-02-25 23:42:31 +0000685 int hp_reading = 32;
686 bool mic;
Mark Browndd235ee2013-01-11 08:55:51 +0900687 int ret;
688
689 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
690
691 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000692 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900693
694 info->hpdet_active = true;
695
Mark Brown03409072013-02-12 13:00:31 +0000696 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900697
698 ret = regmap_update_bits(arizona->regmap,
699 ARIZONA_ACCESSORY_DETECT_MODE_1,
700 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
701 info->micd_modes[0].src |
702 ARIZONA_ACCDET_MODE_HPL);
703 if (ret != 0) {
704 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
705 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900706 }
707
Mark Brown9c2ba272013-02-25 23:42:31 +0000708 if (arizona->pdata.hpdet_acc_id_line) {
709 ret = regmap_update_bits(arizona->regmap,
710 ARIZONA_HEADPHONE_DETECT_1,
711 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
712 if (ret != 0) {
713 dev_err(arizona->dev,
714 "Can't start HPDETL measurement: %d\n",
715 ret);
716 goto err;
717 }
718 } else {
719 arizona_hpdet_do_id(info, &hp_reading, &mic);
Mark Browndd235ee2013-01-11 08:55:51 +0900720 }
721
722 return;
723
724err:
725 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
726 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
727
728 /* Just report headphone */
729 ret = extcon_update_state(&info->edev,
730 1 << ARIZONA_CABLE_HEADPHONE,
731 1 << ARIZONA_CABLE_HEADPHONE);
732 if (ret != 0)
733 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
734
Mark Brown4f340332013-01-11 08:55:43 +0900735 info->hpdet_active = false;
736}
737
Mark Brown939c5672013-04-01 19:17:34 +0100738static void arizona_micd_timeout_work(struct work_struct *work)
739{
740 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900741 struct arizona_extcon_info,
742 micd_timeout_work.work);
Mark Brown939c5672013-04-01 19:17:34 +0100743
744 mutex_lock(&info->lock);
745
746 dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
747 arizona_identify_headphone(info);
748
749 info->detecting = false;
750
751 arizona_stop_mic(info);
752
753 mutex_unlock(&info->lock);
754}
755
Mark Browncd59e792013-04-01 19:21:48 +0100756static void arizona_micd_detect(struct work_struct *work)
Mark Brownf2c32a82012-06-24 12:09:45 +0100757{
Mark Browncd59e792013-04-01 19:21:48 +0100758 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900759 struct arizona_extcon_info,
760 micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100761 struct arizona *arizona = info->arizona;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100762 unsigned int val = 0, lvl;
Mark Brown6fed4d82013-04-01 22:03:06 +0100763 int ret, i, key;
Mark Brownf2c32a82012-06-24 12:09:45 +0100764
Mark Brown939c5672013-04-01 19:17:34 +0100765 cancel_delayed_work_sync(&info->micd_timeout_work);
766
Mark Brownf2c32a82012-06-24 12:09:45 +0100767 mutex_lock(&info->lock);
768
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100769 for (i = 0; i < 10 && !(val & 0x7fc); i++) {
770 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
771 if (ret != 0) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900772 dev_err(arizona->dev,
773 "Failed to read MICDET: %d\n", ret);
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100774 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)) {
Chanwoo Choic2275d22013-08-23 10:21:37 +0900781 dev_warn(arizona->dev,
782 "Microphone detection state invalid\n");
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100783 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100784 return;
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100785 }
Mark Brownf2c32a82012-06-24 12:09:45 +0100786 }
787
Charles Keepaxe2c0f472013-04-01 19:06:29 +0100788 if (i == 10 && !(val & 0x7fc)) {
789 dev_err(arizona->dev, "Failed to get valid MICDET value\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100790 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100791 return;
Mark Brownf2c32a82012-06-24 12:09:45 +0100792 }
793
794 /* Due to jack detect this should never happen */
795 if (!(val & ARIZONA_MICD_STS)) {
796 dev_warn(arizona->dev, "Detected open circuit\n");
797 info->detecting = false;
798 goto handled;
799 }
800
801 /* If we got a high impedence we should have a headset, report it. */
802 if (info->detecting && (val & 0x400)) {
Mark Brown4f340332013-01-11 08:55:43 +0900803 arizona_identify_headphone(info);
804
Mark Brown325c6422012-06-28 13:08:30 +0100805 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900806 1 << ARIZONA_CABLE_MICROPHONE,
807 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100808
809 if (ret != 0)
810 dev_err(arizona->dev, "Headset report failed: %d\n",
811 ret);
812
Mark Brownbbbd46e2013-01-10 19:38:43 +0000813 /* Don't need to regulate for button detection */
814 ret = regulator_allow_bypass(info->micvdd, false);
815 if (ret != 0) {
816 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
817 ret);
818 }
819
Mark Brownf2c32a82012-06-24 12:09:45 +0100820 info->mic = true;
821 info->detecting = false;
822 goto handled;
823 }
824
825 /* If we detected a lower impedence during initial startup
826 * then we probably have the wrong polarity, flip it. Don't
827 * do this for the lowest impedences to speed up detection of
828 * plain headphones. If both polarities report a low
829 * impedence then give up and report headphones.
830 */
831 if (info->detecting && (val & 0x3f8)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800832 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900833 dev_dbg(arizona->dev, "Detected HP/line\n");
834 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100835
Mark Brown4f340332013-01-11 08:55:43 +0900836 info->detecting = false;
837
838 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100839 } else {
840 info->micd_mode++;
841 if (info->micd_mode == info->micd_num_modes)
842 info->micd_mode = 0;
843 arizona_extcon_set_mode(info, info->micd_mode);
844
845 info->jack_flips++;
846 }
847
848 goto handled;
849 }
850
851 /*
852 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100853 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100854 */
855 if (val & 0x3fc) {
856 if (info->mic) {
857 dev_dbg(arizona->dev, "Mic button detected\n");
858
Mark Brown34efe4d2012-07-20 17:07:29 +0100859 lvl = val & ARIZONA_MICD_LVL_MASK;
860 lvl >>= ARIZONA_MICD_LVL_SHIFT;
861
Mark Brown41a57852013-04-01 19:18:18 +0100862 for (i = 0; i < info->num_micd_ranges; i++)
863 input_report_key(info->input,
864 info->micd_ranges[i].key, 0);
865
Mark Brown6fed4d82013-04-01 22:03:06 +0100866 WARN_ON(!lvl);
867 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
868 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
869 key = info->micd_ranges[ffs(lvl) - 1].key;
870 input_report_key(info->input, key, 1);
871 input_sync(info->input);
872 }
Mark Brown34efe4d2012-07-20 17:07:29 +0100873
Mark Brownf2c32a82012-06-24 12:09:45 +0100874 } else if (info->detecting) {
875 dev_dbg(arizona->dev, "Headphone detected\n");
876 info->detecting = false;
877 arizona_stop_mic(info);
878
Mark Brown4f340332013-01-11 08:55:43 +0900879 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100880 } else {
881 dev_warn(arizona->dev, "Button with no mic: %x\n",
882 val);
883 }
884 } else {
885 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown6fed4d82013-04-01 22:03:06 +0100886 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +0100887 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +0100888 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +0100889 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000890 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100891 }
892
893handled:
Mark Brown939c5672013-04-01 19:17:34 +0100894 if (info->detecting)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100895 queue_delayed_work(system_power_efficient_wq,
896 &info->micd_timeout_work,
897 msecs_to_jiffies(info->micd_timeout));
Mark Brown939c5672013-04-01 19:17:34 +0100898
Mark Brownf2c32a82012-06-24 12:09:45 +0100899 pm_runtime_mark_last_busy(info->dev);
900 mutex_unlock(&info->lock);
Mark Browncd59e792013-04-01 19:21:48 +0100901}
902
903static irqreturn_t arizona_micdet(int irq, void *data)
904{
905 struct arizona_extcon_info *info = data;
906 struct arizona *arizona = info->arizona;
907 int debounce = arizona->pdata.micd_detect_debounce;
908
909 cancel_delayed_work_sync(&info->micd_detect_work);
910 cancel_delayed_work_sync(&info->micd_timeout_work);
911
912 mutex_lock(&info->lock);
913 if (!info->detecting)
914 debounce = 0;
915 mutex_unlock(&info->lock);
916
917 if (debounce)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100918 queue_delayed_work(system_power_efficient_wq,
919 &info->micd_detect_work,
920 msecs_to_jiffies(debounce));
Mark Browncd59e792013-04-01 19:21:48 +0100921 else
922 arizona_micd_detect(&info->micd_detect_work.work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100923
924 return IRQ_HANDLED;
925}
926
Mark Brown0e27bd32013-02-05 21:00:15 +0000927static void arizona_hpdet_work(struct work_struct *work)
928{
929 struct arizona_extcon_info *info = container_of(work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900930 struct arizona_extcon_info,
931 hpdet_work.work);
Mark Brown0e27bd32013-02-05 21:00:15 +0000932
933 mutex_lock(&info->lock);
934 arizona_start_hpdet_acc_id(info);
935 mutex_unlock(&info->lock);
936}
937
Mark Brownf2c32a82012-06-24 12:09:45 +0100938static irqreturn_t arizona_jackdet(int irq, void *data)
939{
940 struct arizona_extcon_info *info = data;
941 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900942 unsigned int val, present, mask;
Mark Brown939c5672013-04-01 19:17:34 +0100943 bool cancelled_hp, cancelled_mic;
Mark Brown34efe4d2012-07-20 17:07:29 +0100944 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100945
Mark Brown939c5672013-04-01 19:17:34 +0100946 cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
947 cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100948
Mark Browna3e20782013-04-01 19:05:27 +0100949 pm_runtime_get_sync(info->dev);
Mark Brown0e27bd32013-02-05 21:00:15 +0000950
Mark Brownf2c32a82012-06-24 12:09:45 +0100951 mutex_lock(&info->lock);
952
Mark Brown92a49872013-01-11 08:55:39 +0900953 if (arizona->pdata.jd_gpio5) {
954 mask = ARIZONA_MICD_CLAMP_STS;
955 present = 0;
956 } else {
957 mask = ARIZONA_JD1_STS;
958 present = ARIZONA_JD1_STS;
959 }
960
Mark Brownf2c32a82012-06-24 12:09:45 +0100961 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
962 if (ret != 0) {
963 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
964 ret);
965 mutex_unlock(&info->lock);
966 pm_runtime_put_autosuspend(info->dev);
967 return IRQ_NONE;
968 }
969
Mark Browna3e20782013-04-01 19:05:27 +0100970 val &= mask;
971 if (val == info->last_jackdet) {
972 dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
Mark Brown939c5672013-04-01 19:17:34 +0100973 if (cancelled_hp)
Mark Browndf9a5ab2013-07-18 22:42:22 +0100974 queue_delayed_work(system_power_efficient_wq,
975 &info->hpdet_work,
976 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browna3e20782013-04-01 19:05:27 +0100977
Chanwoo Choic2275d22013-08-23 10:21:37 +0900978 if (cancelled_mic) {
979 int micd_timeout = info->micd_timeout;
980
Mark Browndf9a5ab2013-07-18 22:42:22 +0100981 queue_delayed_work(system_power_efficient_wq,
982 &info->micd_timeout_work,
Chanwoo Choic2275d22013-08-23 10:21:37 +0900983 msecs_to_jiffies(micd_timeout));
984 }
Mark Brown939c5672013-04-01 19:17:34 +0100985
Mark Browna3e20782013-04-01 19:05:27 +0100986 goto out;
987 }
988 info->last_jackdet = val;
989
990 if (info->last_jackdet == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100991 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +0100992 ret = extcon_set_cable_state_(&info->edev,
993 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100994
995 if (ret != 0)
996 dev_err(arizona->dev, "Mechanical report failed: %d\n",
997 ret);
998
Mark Browndd235ee2013-01-11 08:55:51 +0900999 if (!arizona->pdata.hpdet_acc_id) {
1000 info->detecting = true;
1001 info->mic = false;
1002 info->jack_flips = 0;
1003
1004 arizona_start_mic(info);
1005 } else {
Mark Browndf9a5ab2013-07-18 22:42:22 +01001006 queue_delayed_work(system_power_efficient_wq,
1007 &info->hpdet_work,
1008 msecs_to_jiffies(HPDET_DEBOUNCE));
Mark Browndd235ee2013-01-11 08:55:51 +09001009 }
Mark Brown4e616872013-01-15 22:09:20 +09001010
1011 regmap_update_bits(arizona->regmap,
1012 ARIZONA_JACK_DETECT_DEBOUNCE,
1013 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001014 } else {
1015 dev_dbg(arizona->dev, "Detected jack removal\n");
1016
1017 arizona_stop_mic(info);
1018
Mark Browndd235ee2013-01-11 08:55:51 +09001019 info->num_hpdet_res = 0;
1020 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
1021 info->hpdet_res[i] = 0;
1022 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +00001023 info->hpdet_done = false;
Mark Brown9dd5e532013-04-01 19:09:45 +01001024 info->hpdet_retried = false;
Mark Brown92a49872013-01-11 08:55:39 +09001025
Mark Brown6fed4d82013-04-01 22:03:06 +01001026 for (i = 0; i < info->num_micd_ranges; i++)
Mark Brown34efe4d2012-07-20 17:07:29 +01001027 input_report_key(info->input,
Mark Brown6fed4d82013-04-01 22:03:06 +01001028 info->micd_ranges[i].key, 0);
Mark Brown34efe4d2012-07-20 17:07:29 +01001029 input_sync(info->input);
1030
Mark Brownf2c32a82012-06-24 12:09:45 +01001031 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
1032 if (ret != 0)
1033 dev_err(arizona->dev, "Removal report failed: %d\n",
1034 ret);
Mark Brown4e616872013-01-15 22:09:20 +09001035
1036 regmap_update_bits(arizona->regmap,
1037 ARIZONA_JACK_DETECT_DEBOUNCE,
1038 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
1039 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +01001040 }
1041
Mark Brown7abd4e22013-04-01 19:25:55 +01001042 if (arizona->pdata.micd_timeout)
1043 info->micd_timeout = arizona->pdata.micd_timeout;
1044 else
1045 info->micd_timeout = DEFAULT_MICD_TIMEOUT;
1046
Charles Keepax5d9ab702013-02-05 10:13:38 +00001047 /* Clear trig_sts to make sure DCVDD is not forced up */
1048 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
1049 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
1050 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
1051 ARIZONA_JD1_FALL_TRIG_STS |
1052 ARIZONA_JD1_RISE_TRIG_STS);
1053
Mark Browna3e20782013-04-01 19:05:27 +01001054out:
Mark Brownf2c32a82012-06-24 12:09:45 +01001055 mutex_unlock(&info->lock);
1056
1057 pm_runtime_mark_last_busy(info->dev);
1058 pm_runtime_put_autosuspend(info->dev);
1059
1060 return IRQ_HANDLED;
1061}
1062
Mark Brown6fed4d82013-04-01 22:03:06 +01001063/* Map a level onto a slot in the register bank */
1064static void arizona_micd_set_level(struct arizona *arizona, int index,
1065 unsigned int level)
1066{
1067 int reg;
1068 unsigned int mask;
1069
1070 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
1071
1072 if (!(index % 2)) {
1073 mask = 0x3f00;
1074 level <<= 8;
1075 } else {
1076 mask = 0x3f;
1077 }
1078
1079 /* Program the level itself */
1080 regmap_update_bits(arizona->regmap, reg, mask, level);
1081}
1082
Bill Pemberton44f34fd2012-11-19 13:23:21 -05001083static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001084{
1085 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
1086 struct arizona_pdata *pdata;
1087 struct arizona_extcon_info *info;
Mark Browne56a0a52013-04-01 19:03:52 +01001088 unsigned int val;
Mark Brown92a49872013-01-11 08:55:39 +09001089 int jack_irq_fall, jack_irq_rise;
Mark Brown6fed4d82013-04-01 22:03:06 +01001090 int ret, mode, i, j;
Mark Brownf2c32a82012-06-24 12:09:45 +01001091
Mark Brownbbbd46e2013-01-10 19:38:43 +00001092 if (!arizona->dapm || !arizona->dapm->card)
1093 return -EPROBE_DEFER;
1094
Mark Brownf2c32a82012-06-24 12:09:45 +01001095 pdata = dev_get_platdata(arizona->dev);
1096
1097 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1098 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001099 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +01001100 ret = -ENOMEM;
1101 goto err;
1102 }
1103
1104 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
1105 if (IS_ERR(info->micvdd)) {
1106 ret = PTR_ERR(info->micvdd);
1107 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
1108 goto err;
1109 }
1110
1111 mutex_init(&info->lock);
1112 info->arizona = arizona;
1113 info->dev = &pdev->dev;
Mark Browna3e20782013-04-01 19:05:27 +01001114 info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
Mark Brown0e27bd32013-02-05 21:00:15 +00001115 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Browncd59e792013-04-01 19:21:48 +01001116 INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
Mark Brown939c5672013-04-01 19:17:34 +01001117 INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001118 platform_set_drvdata(pdev, info);
1119
1120 switch (arizona->type) {
1121 case WM5102:
1122 switch (arizona->rev) {
1123 case 0:
1124 info->micd_reva = true;
1125 break;
1126 default:
Mark Browndab63eb2013-01-11 08:55:36 +09001127 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +09001128 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +01001129 break;
1130 }
1131 break;
1132 default:
1133 break;
1134 }
1135
1136 info->edev.name = "Headset Jack";
1137 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001138
1139 ret = extcon_dev_register(&info->edev, arizona->dev);
1140 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001141 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001142 ret);
1143 goto err;
1144 }
1145
Mark Brown6fed4d82013-04-01 22:03:06 +01001146 info->input = devm_input_allocate_device(&pdev->dev);
1147 if (!info->input) {
1148 dev_err(arizona->dev, "Can't allocate input dev\n");
1149 ret = -ENOMEM;
1150 goto err_register;
1151 }
1152
1153 info->input->name = "Headset";
1154 info->input->phys = "arizona/extcon";
1155 info->input->dev.parent = &pdev->dev;
1156
Mark Brownf2c32a82012-06-24 12:09:45 +01001157 if (pdata->num_micd_configs) {
1158 info->micd_modes = pdata->micd_configs;
1159 info->micd_num_modes = pdata->num_micd_configs;
1160 } else {
1161 info->micd_modes = micd_default_modes;
1162 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1163 }
1164
1165 if (arizona->pdata.micd_pol_gpio > 0) {
1166 if (info->micd_modes[0].gpio)
1167 mode = GPIOF_OUT_INIT_HIGH;
1168 else
1169 mode = GPIOF_OUT_INIT_LOW;
1170
1171 ret = devm_gpio_request_one(&pdev->dev,
1172 arizona->pdata.micd_pol_gpio,
1173 mode,
1174 "MICD polarity");
1175 if (ret != 0) {
1176 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1177 arizona->pdata.micd_pol_gpio, ret);
1178 goto err_register;
1179 }
1180 }
1181
Mark Brown1eda6aa2013-01-11 08:55:54 +09001182 if (arizona->pdata.hpdet_id_gpio > 0) {
1183 ret = devm_gpio_request_one(&pdev->dev,
1184 arizona->pdata.hpdet_id_gpio,
1185 GPIOF_OUT_INIT_LOW,
1186 "HPDET");
1187 if (ret != 0) {
1188 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1189 arizona->pdata.hpdet_id_gpio, ret);
1190 goto err_register;
1191 }
1192 }
1193
Mark Brownb17e5462013-01-11 08:55:24 +09001194 if (arizona->pdata.micd_bias_start_time)
1195 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1196 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1197 arizona->pdata.micd_bias_start_time
1198 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1199
Mark Brown2e033db2013-01-21 17:36:33 +09001200 if (arizona->pdata.micd_rate)
1201 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1202 ARIZONA_MICD_RATE_MASK,
1203 arizona->pdata.micd_rate
1204 << ARIZONA_MICD_RATE_SHIFT);
1205
1206 if (arizona->pdata.micd_dbtime)
1207 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1208 ARIZONA_MICD_DBTIME_MASK,
1209 arizona->pdata.micd_dbtime
1210 << ARIZONA_MICD_DBTIME_SHIFT);
1211
Mark Brown6fed4d82013-04-01 22:03:06 +01001212 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1213
1214 if (arizona->pdata.num_micd_ranges) {
1215 info->micd_ranges = pdata->micd_ranges;
1216 info->num_micd_ranges = pdata->num_micd_ranges;
1217 } else {
1218 info->micd_ranges = micd_default_ranges;
1219 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1220 }
1221
1222 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1223 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1224 arizona->pdata.num_micd_ranges);
1225 }
1226
1227 if (info->num_micd_ranges > 1) {
1228 for (i = 1; i < info->num_micd_ranges; i++) {
1229 if (info->micd_ranges[i - 1].max >
1230 info->micd_ranges[i].max) {
1231 dev_err(arizona->dev,
1232 "MICD ranges must be sorted\n");
1233 ret = -EINVAL;
1234 goto err_input;
1235 }
1236 }
1237 }
1238
1239 /* Disable all buttons by default */
1240 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1241 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1242
1243 /* Set up all the buttons the user specified */
1244 for (i = 0; i < info->num_micd_ranges; i++) {
1245 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1246 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1247 break;
1248
1249 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1250 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1251 info->micd_ranges[i].max);
1252 ret = -EINVAL;
1253 goto err_input;
1254 }
1255
1256 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1257 arizona_micd_levels[j], i);
1258
1259 arizona_micd_set_level(arizona, i, j);
1260 input_set_capability(info->input, EV_KEY,
1261 info->micd_ranges[i].key);
1262
1263 /* Enable reporting of that range */
1264 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1265 1 << i, 1 << i);
1266 }
1267
1268 /* Set all the remaining keys to a maximum */
1269 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1270 arizona_micd_set_level(arizona, i, 0x3f);
1271
Mark Browndab63eb2013-01-11 08:55:36 +09001272 /*
Mark Brown92a49872013-01-11 08:55:39 +09001273 * If we have a clamp use it, activating in conjunction with
1274 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001275 */
1276 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001277 if (arizona->pdata.jd_gpio5) {
Mark Browne56a0a52013-04-01 19:03:52 +01001278 /* Put the GPIO into input mode with optional pull */
1279 val = 0xc101;
1280 if (arizona->pdata.jd_gpio5_nopull)
1281 val &= ~ARIZONA_GPN_PU;
1282
Mark Brown92a49872013-01-11 08:55:39 +09001283 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
Mark Browne56a0a52013-04-01 19:03:52 +01001284 val);
Mark Brown92a49872013-01-11 08:55:39 +09001285
1286 regmap_update_bits(arizona->regmap,
1287 ARIZONA_MICD_CLAMP_CONTROL,
1288 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1289 } else {
1290 regmap_update_bits(arizona->regmap,
1291 ARIZONA_MICD_CLAMP_CONTROL,
1292 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1293 }
1294
Mark Browndab63eb2013-01-11 08:55:36 +09001295 regmap_update_bits(arizona->regmap,
1296 ARIZONA_JACK_DETECT_DEBOUNCE,
1297 ARIZONA_MICD_CLAMP_DB,
1298 ARIZONA_MICD_CLAMP_DB);
1299 }
1300
Mark Brownf2c32a82012-06-24 12:09:45 +01001301 arizona_extcon_set_mode(info, 0);
1302
1303 pm_runtime_enable(&pdev->dev);
1304 pm_runtime_idle(&pdev->dev);
1305 pm_runtime_get_sync(&pdev->dev);
1306
Mark Brown92a49872013-01-11 08:55:39 +09001307 if (arizona->pdata.jd_gpio5) {
1308 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1309 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1310 } else {
1311 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1312 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1313 }
1314
1315 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001316 "JACKDET rise", arizona_jackdet, info);
1317 if (ret != 0) {
1318 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1319 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001320 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001321 }
1322
Mark Brown92a49872013-01-11 08:55:39 +09001323 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001324 if (ret != 0) {
1325 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1326 ret);
1327 goto err_rise;
1328 }
1329
Mark Brown92a49872013-01-11 08:55:39 +09001330 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001331 "JACKDET fall", arizona_jackdet, info);
1332 if (ret != 0) {
1333 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1334 goto err_rise_wake;
1335 }
1336
Mark Brown92a49872013-01-11 08:55:39 +09001337 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001338 if (ret != 0) {
1339 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1340 ret);
1341 goto err_fall;
1342 }
1343
1344 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1345 "MICDET", arizona_micdet, info);
1346 if (ret != 0) {
1347 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1348 goto err_fall_wake;
1349 }
1350
Mark Brown4f340332013-01-11 08:55:43 +09001351 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1352 "HPDET", arizona_hpdet_irq, info);
1353 if (ret != 0) {
1354 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1355 goto err_micdet;
1356 }
1357
Mark Brownf2c32a82012-06-24 12:09:45 +01001358 arizona_clk32k_enable(arizona);
1359 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1360 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1361 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1362 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1363
Mark Brownb8575a12012-09-07 17:01:15 +08001364 ret = regulator_allow_bypass(info->micvdd, true);
1365 if (ret != 0)
1366 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1367 ret);
1368
Mark Brownf2c32a82012-06-24 12:09:45 +01001369 pm_runtime_put(&pdev->dev);
1370
Mark Brown34efe4d2012-07-20 17:07:29 +01001371 ret = input_register_device(info->input);
1372 if (ret) {
1373 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001374 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001375 }
1376
Mark Brownf2c32a82012-06-24 12:09:45 +01001377 return 0;
1378
Mark Brown4f340332013-01-11 08:55:43 +09001379err_hpdet:
1380 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001381err_micdet:
1382 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001383err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001384 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001385err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001386 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001387err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001388 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001389err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001390 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001391err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001392err_register:
1393 pm_runtime_disable(&pdev->dev);
1394 extcon_dev_unregister(&info->edev);
1395err:
1396 return ret;
1397}
1398
Bill Pemberton93ed0322012-11-19 13:25:49 -05001399static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001400{
1401 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1402 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001403 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001404
1405 pm_runtime_disable(&pdev->dev);
1406
Mark Browndab63eb2013-01-11 08:55:36 +09001407 regmap_update_bits(arizona->regmap,
1408 ARIZONA_MICD_CLAMP_CONTROL,
1409 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1410
Mark Brown92a49872013-01-11 08:55:39 +09001411 if (arizona->pdata.jd_gpio5) {
1412 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1413 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1414 } else {
1415 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1416 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1417 }
1418
1419 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1420 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1421 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001422 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001423 arizona_free_irq(arizona, jack_irq_rise, info);
1424 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001425 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001426 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1427 ARIZONA_JD1_ENA, 0);
1428 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001429 extcon_dev_unregister(&info->edev);
1430
1431 return 0;
1432}
1433
1434static struct platform_driver arizona_extcon_driver = {
1435 .driver = {
1436 .name = "arizona-extcon",
1437 .owner = THIS_MODULE,
1438 },
1439 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001440 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001441};
1442
1443module_platform_driver(arizona_extcon_driver);
1444
1445MODULE_DESCRIPTION("Arizona Extcon driver");
1446MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1447MODULE_LICENSE("GPL");
1448MODULE_ALIAS("platform:extcon-arizona");