blob: 4bb0e9ae405ddd1e74a72435d9181906f142b7bf [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 Brown34efe4d2012-07-20 17:07:29 +010036#define ARIZONA_NUM_BUTTONS 6
37
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 Brownf2c32a82012-06-24 12:09:45 +010042struct arizona_extcon_info {
43 struct device *dev;
44 struct arizona *arizona;
45 struct mutex lock;
46 struct regulator *micvdd;
Mark Brown34efe4d2012-07-20 17:07:29 +010047 struct input_dev *input;
Mark Brownf2c32a82012-06-24 12:09:45 +010048
49 int micd_mode;
50 const struct arizona_micd_config *micd_modes;
51 int micd_num_modes;
52
53 bool micd_reva;
Mark Browndab63eb2013-01-11 08:55:36 +090054 bool micd_clamp;
Mark Brownf2c32a82012-06-24 12:09:45 +010055
Mark Brown0e27bd32013-02-05 21:00:15 +000056 struct delayed_work hpdet_work;
57
Mark Brown4f340332013-01-11 08:55:43 +090058 bool hpdet_active;
Mark Brownbf14ee52013-02-05 20:20:17 +000059 bool hpdet_done;
Mark Brown4f340332013-01-11 08:55:43 +090060
Mark Browndd235ee2013-01-11 08:55:51 +090061 int num_hpdet_res;
Mark Brown1eda6aa2013-01-11 08:55:54 +090062 unsigned int hpdet_res[3];
Mark Browndd235ee2013-01-11 08:55:51 +090063
Mark Brownf2c32a82012-06-24 12:09:45 +010064 bool mic;
65 bool detecting;
66 int jack_flips;
67
Mark Brown4f340332013-01-11 08:55:43 +090068 int hpdet_ip;
69
Mark Brownf2c32a82012-06-24 12:09:45 +010070 struct extcon_dev edev;
71};
72
73static const struct arizona_micd_config micd_default_modes[] = {
Mark Brownf2c32a82012-06-24 12:09:45 +010074 { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
Mark Browndd235ee2013-01-11 08:55:51 +090075 { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
Mark Brownf2c32a82012-06-24 12:09:45 +010076};
77
Mark Brown34efe4d2012-07-20 17:07:29 +010078static struct {
79 u16 status;
80 int report;
81} arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = {
82 { 0x1, BTN_0 },
83 { 0x2, BTN_1 },
84 { 0x4, BTN_2 },
85 { 0x8, BTN_3 },
86 { 0x10, BTN_4 },
87 { 0x20, BTN_5 },
88};
89
Mark Brown325c6422012-06-28 13:08:30 +010090#define ARIZONA_CABLE_MECHANICAL 0
91#define ARIZONA_CABLE_MICROPHONE 1
92#define ARIZONA_CABLE_HEADPHONE 2
Mark Brown4f340332013-01-11 08:55:43 +090093#define ARIZONA_CABLE_LINEOUT 3
Mark Brownf2c32a82012-06-24 12:09:45 +010094
95static const char *arizona_cable[] = {
Mark Brown325c6422012-06-28 13:08:30 +010096 "Mechanical",
97 "Microphone",
98 "Headphone",
Mark Brown4f340332013-01-11 08:55:43 +090099 "Line-out",
Mark Brownf2c32a82012-06-24 12:09:45 +0100100 NULL,
101};
102
Mark Brown03409072013-02-12 13:00:31 +0000103static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
104 unsigned int magic)
105{
106 struct arizona *arizona = info->arizona;
Mark Brown03409072013-02-12 13:00:31 +0000107 int ret;
108
109 mutex_lock(&arizona->dapm->card->dapm_mutex);
110
Mark Browndf8c3db2013-02-22 18:38:03 +0000111 arizona->hpdet_magic = magic;
112
113 /* Keep the HP output stages disabled while doing the magic */
114 if (magic) {
115 ret = regmap_update_bits(arizona->regmap,
116 ARIZONA_OUTPUT_ENABLES_1,
117 ARIZONA_OUT1L_ENA |
118 ARIZONA_OUT1R_ENA, 0);
119 if (ret != 0)
120 dev_warn(arizona->dev,
121 "Failed to disable headphone outputs: %d\n",
122 ret);
Mark Brown03409072013-02-12 13:00:31 +0000123 }
124
Mark Browndf8c3db2013-02-22 18:38:03 +0000125 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
126 magic);
127 if (ret != 0)
128 dev_warn(arizona->dev, "Failed to do magic: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000129 ret);
130
Mark Browndf8c3db2013-02-22 18:38:03 +0000131 ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
132 magic);
133 if (ret != 0)
134 dev_warn(arizona->dev, "Failed to do magic: %d\n",
135 ret);
136
137 /* Restore the desired state while not doing the magic */
138 if (!magic) {
139 ret = regmap_update_bits(arizona->regmap,
140 ARIZONA_OUTPUT_ENABLES_1,
141 ARIZONA_OUT1L_ENA |
142 ARIZONA_OUT1R_ENA, arizona->hp_ena);
Mark Brown03409072013-02-12 13:00:31 +0000143 if (ret != 0)
Mark Browndf8c3db2013-02-22 18:38:03 +0000144 dev_warn(arizona->dev,
145 "Failed to restore headphone outputs: %d\n",
Mark Brown03409072013-02-12 13:00:31 +0000146 ret);
147 }
148
149 mutex_unlock(&arizona->dapm->card->dapm_mutex);
150}
151
Mark Brownf2c32a82012-06-24 12:09:45 +0100152static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
153{
154 struct arizona *arizona = info->arizona;
155
Mark Brown84eaa132013-01-25 20:14:44 +0800156 mode %= info->num_micd_modes;
157
Mark Browncd74f7b2012-11-27 16:14:26 +0900158 if (arizona->pdata.micd_pol_gpio > 0)
159 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
160 info->micd_modes[mode].gpio);
Mark Brownf2c32a82012-06-24 12:09:45 +0100161 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
162 ARIZONA_MICD_BIAS_SRC_MASK,
163 info->micd_modes[mode].bias);
164 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
165 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
166
167 info->micd_mode = mode;
168
169 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
170}
171
Mark Brownbbbd46e2013-01-10 19:38:43 +0000172static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
173{
174 switch (info->micd_modes[0].bias >> ARIZONA_MICD_BIAS_SRC_SHIFT) {
175 case 1:
176 return "MICBIAS1";
177 case 2:
178 return "MICBIAS2";
179 case 3:
180 return "MICBIAS3";
181 default:
182 return "MICVDD";
183 }
184}
185
186static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
187{
188 struct arizona *arizona = info->arizona;
189 const char *widget = arizona_extcon_get_micbias(info);
190 struct snd_soc_dapm_context *dapm = arizona->dapm;
191 int ret;
192
193 mutex_lock(&dapm->card->dapm_mutex);
194
195 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
196 if (ret != 0)
197 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
198 widget, ret);
199
200 mutex_unlock(&dapm->card->dapm_mutex);
201
202 snd_soc_dapm_sync(dapm);
203
204 if (!arizona->pdata.micd_force_micbias) {
205 mutex_lock(&dapm->card->dapm_mutex);
206
207 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
208 if (ret != 0)
209 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
210 widget, ret);
211
212 mutex_unlock(&dapm->card->dapm_mutex);
213
214 snd_soc_dapm_sync(dapm);
215 }
216}
217
Mark Brown9b1270c2013-01-11 08:55:46 +0900218static void arizona_start_mic(struct arizona_extcon_info *info)
219{
220 struct arizona *arizona = info->arizona;
221 bool change;
222 int ret;
223
Mark Brown9b1270c2013-01-11 08:55:46 +0900224 /* Microphone detection can't use idle mode */
225 pm_runtime_get(info->dev);
226
Mark Brownbbbd46e2013-01-10 19:38:43 +0000227 if (info->detecting) {
228 ret = regulator_allow_bypass(info->micvdd, false);
229 if (ret != 0) {
230 dev_err(arizona->dev,
231 "Failed to regulate MICVDD: %d\n",
232 ret);
233 }
234 }
235
Mark Brown9b1270c2013-01-11 08:55:46 +0900236 ret = regulator_enable(info->micvdd);
237 if (ret != 0) {
238 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
239 ret);
240 }
241
242 if (info->micd_reva) {
243 regmap_write(arizona->regmap, 0x80, 0x3);
244 regmap_write(arizona->regmap, 0x294, 0);
245 regmap_write(arizona->regmap, 0x80, 0x0);
246 }
247
248 regmap_update_bits(arizona->regmap,
249 ARIZONA_ACCESSORY_DETECT_MODE_1,
250 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
251
Mark Brownbbbd46e2013-01-10 19:38:43 +0000252 arizona_extcon_pulse_micbias(info);
253
Mark Brown9b1270c2013-01-11 08:55:46 +0900254 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
255 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
256 &change);
257 if (!change) {
258 regulator_disable(info->micvdd);
259 pm_runtime_put_autosuspend(info->dev);
260 }
261}
262
263static void arizona_stop_mic(struct arizona_extcon_info *info)
264{
265 struct arizona *arizona = info->arizona;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000266 const char *widget = arizona_extcon_get_micbias(info);
267 struct snd_soc_dapm_context *dapm = arizona->dapm;
Mark Brown9b1270c2013-01-11 08:55:46 +0900268 bool change;
Mark Brownbbbd46e2013-01-10 19:38:43 +0000269 int ret;
Mark Brown9b1270c2013-01-11 08:55:46 +0900270
271 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
272 ARIZONA_MICD_ENA, 0,
273 &change);
274
Mark Brownbbbd46e2013-01-10 19:38:43 +0000275 mutex_lock(&dapm->card->dapm_mutex);
276
277 ret = snd_soc_dapm_disable_pin(dapm, widget);
278 if (ret != 0)
279 dev_warn(arizona->dev,
280 "Failed to disable %s: %d\n",
281 widget, ret);
282
283 mutex_unlock(&dapm->card->dapm_mutex);
284
285 snd_soc_dapm_sync(dapm);
286
Mark Brown9b1270c2013-01-11 08:55:46 +0900287 if (info->micd_reva) {
288 regmap_write(arizona->regmap, 0x80, 0x3);
289 regmap_write(arizona->regmap, 0x294, 2);
290 regmap_write(arizona->regmap, 0x80, 0x0);
291 }
292
Mark Brownbbbd46e2013-01-10 19:38:43 +0000293 ret = regulator_allow_bypass(info->micvdd, true);
294 if (ret != 0) {
295 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
296 ret);
297 }
298
Mark Brown9b1270c2013-01-11 08:55:46 +0900299 if (change) {
300 regulator_disable(info->micvdd);
301 pm_runtime_mark_last_busy(info->dev);
302 pm_runtime_put_autosuspend(info->dev);
303 }
304}
305
Mark Brown4f340332013-01-11 08:55:43 +0900306static struct {
307 unsigned int factor_a;
308 unsigned int factor_b;
309} arizona_hpdet_b_ranges[] = {
310 { 5528, 362464 },
311 { 11084, 6186851 },
312 { 11065, 65460395 },
313};
314
315static struct {
316 int min;
317 int max;
318} arizona_hpdet_c_ranges[] = {
319 { 0, 30 },
320 { 8, 100 },
321 { 100, 1000 },
322 { 1000, 10000 },
323};
324
325static int arizona_hpdet_read(struct arizona_extcon_info *info)
326{
327 struct arizona *arizona = info->arizona;
328 unsigned int val, range;
329 int ret;
330
331 ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
332 if (ret != 0) {
333 dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
334 ret);
335 return ret;
336 }
337
338 switch (info->hpdet_ip) {
339 case 0:
340 if (!(val & ARIZONA_HP_DONE)) {
341 dev_err(arizona->dev, "HPDET did not complete: %x\n",
342 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900343 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900344 }
345
346 val &= ARIZONA_HP_LVL_MASK;
347 break;
348
349 case 1:
350 if (!(val & ARIZONA_HP_DONE_B)) {
351 dev_err(arizona->dev, "HPDET did not complete: %x\n",
352 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900353 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900354 }
355
356 ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
357 if (ret != 0) {
358 dev_err(arizona->dev, "Failed to read HP value: %d\n",
359 ret);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900360 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900361 }
362
363 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
364 &range);
365 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
366 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
367
368 if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
369 (val < 100 || val > 0x3fb)) {
370 range++;
371 dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
372 range);
373 regmap_update_bits(arizona->regmap,
374 ARIZONA_HEADPHONE_DETECT_1,
375 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
376 range <<
377 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
378 return -EAGAIN;
379 }
380
381 /* If we go out of range report top of range */
382 if (val < 100 || val > 0x3fb) {
383 dev_dbg(arizona->dev, "Measurement out of range\n");
384 return 10000;
385 }
386
387 dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
388 val, range);
389
390 val = arizona_hpdet_b_ranges[range].factor_b
391 / ((val * 100) -
392 arizona_hpdet_b_ranges[range].factor_a);
393 break;
394
395 default:
396 dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
397 info->hpdet_ip);
398 case 2:
399 if (!(val & ARIZONA_HP_DONE_B)) {
400 dev_err(arizona->dev, "HPDET did not complete: %x\n",
401 val);
Mark Browne6dd8cf2013-01-21 17:30:02 +0900402 return -EAGAIN;
Mark Brown4f340332013-01-11 08:55:43 +0900403 }
404
405 val &= ARIZONA_HP_LVL_B_MASK;
406
407 regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
408 &range);
409 range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
410 >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
411
412 /* Skip up or down a range? */
413 if (range && (val < arizona_hpdet_c_ranges[range].min)) {
414 range--;
415 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
416 arizona_hpdet_c_ranges[range].min,
417 arizona_hpdet_c_ranges[range].max);
418 regmap_update_bits(arizona->regmap,
419 ARIZONA_HEADPHONE_DETECT_1,
420 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
421 range <<
422 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
423 return -EAGAIN;
424 }
425
426 if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
427 (val >= arizona_hpdet_c_ranges[range].max)) {
428 range++;
429 dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
430 arizona_hpdet_c_ranges[range].min,
431 arizona_hpdet_c_ranges[range].max);
432 regmap_update_bits(arizona->regmap,
433 ARIZONA_HEADPHONE_DETECT_1,
434 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
435 range <<
436 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
437 return -EAGAIN;
438 }
439 }
440
441 dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
442 return val;
443}
444
Mark Browndd235ee2013-01-11 08:55:51 +0900445static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
446{
447 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900448 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Browndd235ee2013-01-11 08:55:51 +0900449
450 /*
451 * If we're using HPDET for accessory identification we need
452 * to take multiple measurements, step through them in sequence.
453 */
454 if (arizona->pdata.hpdet_acc_id) {
455 info->hpdet_res[info->num_hpdet_res++] = *reading;
456
457 /*
458 * If the impedence is too high don't measure the
459 * second ground.
460 */
461 if (info->num_hpdet_res == 1 && *reading >= 45) {
462 dev_dbg(arizona->dev, "Skipping ground flip\n");
463 info->hpdet_res[info->num_hpdet_res++] = *reading;
464 }
465
466 if (info->num_hpdet_res == 1) {
467 dev_dbg(arizona->dev, "Flipping ground\n");
468
469 regmap_update_bits(arizona->regmap,
470 ARIZONA_ACCESSORY_DETECT_MODE_1,
471 ARIZONA_ACCDET_SRC,
472 ~info->micd_modes[0].src);
Mark Brown1eda6aa2013-01-11 08:55:54 +0900473
Mark Browndd235ee2013-01-11 08:55:51 +0900474 regmap_update_bits(arizona->regmap,
475 ARIZONA_HEADPHONE_DETECT_1,
Mark Brown1eda6aa2013-01-11 08:55:54 +0900476 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
477 return -EAGAIN;
478 }
479
480 /* Only check the mic directly if we didn't already ID it */
481 if (id_gpio && info->num_hpdet_res == 2 &&
482 !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) {
483 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 Brown1eda6aa2013-01-11 08:55:54 +0900501 dev_dbg(arizona->dev, "HPDET measured %d %d %d\n",
502 info->hpdet_res[0], info->hpdet_res[1],
503 info->hpdet_res[2]);
Mark Browndd235ee2013-01-11 08:55:51 +0900504
Mark Brownc37b3872013-02-05 17:48:49 +0000505
506 /* Take the headphone impedance for the main report */
507 *reading = info->hpdet_res[0];
508
Mark Brown1eda6aa2013-01-11 08:55:54 +0900509 /*
510 * Either the two grounds measure differently or we
511 * measure the mic as high impedance.
512 */
513 if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) ||
514 (id_gpio && info->hpdet_res[2] > 10)) {
Mark Browndd235ee2013-01-11 08:55:51 +0900515 dev_dbg(arizona->dev, "Detected mic\n");
516 info->mic = true;
Mark Brownbf14ee52013-02-05 20:20:17 +0000517 info->detecting = true;
Mark Browndd235ee2013-01-11 08:55:51 +0900518 } else {
519 dev_dbg(arizona->dev, "Detected headphone\n");
520 }
521
522 /* Make sure everything is reset back to the real polarity */
523 regmap_update_bits(arizona->regmap,
524 ARIZONA_ACCESSORY_DETECT_MODE_1,
525 ARIZONA_ACCDET_SRC,
526 info->micd_modes[0].src);
527 }
528
529 return 0;
530}
531
Mark Brown4f340332013-01-11 08:55:43 +0900532static irqreturn_t arizona_hpdet_irq(int irq, void *data)
533{
534 struct arizona_extcon_info *info = data;
535 struct arizona *arizona = info->arizona;
Mark Brown1eda6aa2013-01-11 08:55:54 +0900536 int id_gpio = arizona->pdata.hpdet_id_gpio;
Mark Brown4f340332013-01-11 08:55:43 +0900537 int report = ARIZONA_CABLE_HEADPHONE;
Mark Browndd235ee2013-01-11 08:55:51 +0900538 int ret, reading;
Mark Brown4f340332013-01-11 08:55:43 +0900539
540 mutex_lock(&info->lock);
541
542 /* If we got a spurious IRQ for some reason then ignore it */
543 if (!info->hpdet_active) {
544 dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
545 mutex_unlock(&info->lock);
546 return IRQ_NONE;
547 }
548
549 /* If the cable was removed while measuring ignore the result */
550 ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
551 if (ret < 0) {
552 dev_err(arizona->dev, "Failed to check cable state: %d\n",
553 ret);
554 goto out;
555 } else if (!ret) {
556 dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
557 goto done;
558 }
559
560 ret = arizona_hpdet_read(info);
561 if (ret == -EAGAIN) {
562 goto out;
563 } else if (ret < 0) {
564 goto done;
565 }
Mark Browndd235ee2013-01-11 08:55:51 +0900566 reading = ret;
Mark Brown4f340332013-01-11 08:55:43 +0900567
568 /* Reset back to starting range */
569 regmap_update_bits(arizona->regmap,
570 ARIZONA_HEADPHONE_DETECT_1,
Mark Browndd235ee2013-01-11 08:55:51 +0900571 ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
572 0);
573
574 ret = arizona_hpdet_do_id(info, &reading);
575 if (ret == -EAGAIN) {
576 goto out;
577 } else if (ret < 0) {
578 goto done;
579 }
Mark Brown4f340332013-01-11 08:55:43 +0900580
581 /* Report high impedence cables as line outputs */
Mark Browndd235ee2013-01-11 08:55:51 +0900582 if (reading >= 5000)
Mark Brown4f340332013-01-11 08:55:43 +0900583 report = ARIZONA_CABLE_LINEOUT;
584 else
585 report = ARIZONA_CABLE_HEADPHONE;
586
587 ret = extcon_set_cable_state_(&info->edev, report, true);
588 if (ret != 0)
589 dev_err(arizona->dev, "Failed to report HP/line: %d\n",
590 ret);
591
Mark Brown03409072013-02-12 13:00:31 +0000592 arizona_extcon_do_magic(info, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900593
594done:
Mark Brown1eda6aa2013-01-11 08:55:54 +0900595 if (id_gpio)
596 gpio_set_value_cansleep(id_gpio, 0);
Mark Brown4f340332013-01-11 08:55:43 +0900597
598 /* Revert back to MICDET mode */
599 regmap_update_bits(arizona->regmap,
600 ARIZONA_ACCESSORY_DETECT_MODE_1,
601 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
602
603 /* If we have a mic then reenable MICDET */
604 if (info->mic)
605 arizona_start_mic(info);
606
607 if (info->hpdet_active) {
608 pm_runtime_put_autosuspend(info->dev);
609 info->hpdet_active = false;
610 }
611
Mark Brownbf14ee52013-02-05 20:20:17 +0000612 info->hpdet_done = true;
613
Mark Brown4f340332013-01-11 08:55:43 +0900614out:
615 mutex_unlock(&info->lock);
616
617 return IRQ_HANDLED;
618}
619
620static void arizona_identify_headphone(struct arizona_extcon_info *info)
621{
622 struct arizona *arizona = info->arizona;
623 int ret;
624
Mark Brownbf14ee52013-02-05 20:20:17 +0000625 if (info->hpdet_done)
626 return;
627
Mark Brown4f340332013-01-11 08:55:43 +0900628 dev_dbg(arizona->dev, "Starting HPDET\n");
629
630 /* Make sure we keep the device enabled during the measurement */
631 pm_runtime_get(info->dev);
632
633 info->hpdet_active = true;
634
635 if (info->mic)
636 arizona_stop_mic(info);
637
Mark Brown03409072013-02-12 13:00:31 +0000638 arizona_extcon_do_magic(info, 0x4000);
Mark Brown4f340332013-01-11 08:55:43 +0900639
640 ret = regmap_update_bits(arizona->regmap,
641 ARIZONA_ACCESSORY_DETECT_MODE_1,
642 ARIZONA_ACCDET_MODE_MASK,
643 ARIZONA_ACCDET_MODE_HPL);
644 if (ret != 0) {
645 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
646 goto err;
647 }
648
649 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
650 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
651 if (ret != 0) {
652 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
653 ret);
654 goto err;
655 }
656
657 return;
658
659err:
660 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
661 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
662
663 /* Just report headphone */
664 ret = extcon_update_state(&info->edev,
665 1 << ARIZONA_CABLE_HEADPHONE,
666 1 << ARIZONA_CABLE_HEADPHONE);
667 if (ret != 0)
668 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
669
670 if (info->mic)
671 arizona_start_mic(info);
672
673 info->hpdet_active = false;
674}
Mark Browndd235ee2013-01-11 08:55:51 +0900675
676static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
677{
678 struct arizona *arizona = info->arizona;
679 int ret;
680
681 dev_dbg(arizona->dev, "Starting identification via HPDET\n");
682
683 /* Make sure we keep the device enabled during the measurement */
Mark Brown0e27bd32013-02-05 21:00:15 +0000684 pm_runtime_get_sync(info->dev);
Mark Browndd235ee2013-01-11 08:55:51 +0900685
686 info->hpdet_active = true;
687
Mark Brownbbbd46e2013-01-10 19:38:43 +0000688 arizona_extcon_pulse_micbias(info);
689
Mark Brown03409072013-02-12 13:00:31 +0000690 arizona_extcon_do_magic(info, 0x4000);
Mark Browndd235ee2013-01-11 08:55:51 +0900691
692 ret = regmap_update_bits(arizona->regmap,
693 ARIZONA_ACCESSORY_DETECT_MODE_1,
694 ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
695 info->micd_modes[0].src |
696 ARIZONA_ACCDET_MODE_HPL);
697 if (ret != 0) {
698 dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
699 goto err;
Mark Brown4f340332013-01-11 08:55:43 +0900700 }
701
Mark Browndd235ee2013-01-11 08:55:51 +0900702 ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
703 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
704 if (ret != 0) {
705 dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
706 ret);
707 goto err;
708 }
709
710 return;
711
712err:
713 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
714 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
715
716 /* Just report headphone */
717 ret = extcon_update_state(&info->edev,
718 1 << ARIZONA_CABLE_HEADPHONE,
719 1 << ARIZONA_CABLE_HEADPHONE);
720 if (ret != 0)
721 dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
722
Mark Brown4f340332013-01-11 08:55:43 +0900723 info->hpdet_active = false;
724}
725
Mark Brownf2c32a82012-06-24 12:09:45 +0100726static irqreturn_t arizona_micdet(int irq, void *data)
727{
728 struct arizona_extcon_info *info = data;
729 struct arizona *arizona = info->arizona;
Mark Brown34efe4d2012-07-20 17:07:29 +0100730 unsigned int val, lvl;
731 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100732
733 mutex_lock(&info->lock);
734
735 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
736 if (ret != 0) {
737 dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
Alexey Khoroshilovbe31cc02012-11-05 17:11:41 +0900738 mutex_unlock(&info->lock);
Mark Brownf2c32a82012-06-24 12:09:45 +0100739 return IRQ_NONE;
740 }
741
742 dev_dbg(arizona->dev, "MICDET: %x\n", val);
743
744 if (!(val & ARIZONA_MICD_VALID)) {
745 dev_warn(arizona->dev, "Microphone detection state invalid\n");
746 mutex_unlock(&info->lock);
747 return IRQ_NONE;
748 }
749
750 /* Due to jack detect this should never happen */
751 if (!(val & ARIZONA_MICD_STS)) {
752 dev_warn(arizona->dev, "Detected open circuit\n");
753 info->detecting = false;
754 goto handled;
755 }
756
757 /* If we got a high impedence we should have a headset, report it. */
758 if (info->detecting && (val & 0x400)) {
Mark Brown4f340332013-01-11 08:55:43 +0900759 arizona_identify_headphone(info);
760
Mark Brown325c6422012-06-28 13:08:30 +0100761 ret = extcon_update_state(&info->edev,
Mark Brown4f340332013-01-11 08:55:43 +0900762 1 << ARIZONA_CABLE_MICROPHONE,
763 1 << ARIZONA_CABLE_MICROPHONE);
Mark Brownf2c32a82012-06-24 12:09:45 +0100764
765 if (ret != 0)
766 dev_err(arizona->dev, "Headset report failed: %d\n",
767 ret);
768
Mark Brownbbbd46e2013-01-10 19:38:43 +0000769 /* Don't need to regulate for button detection */
770 ret = regulator_allow_bypass(info->micvdd, false);
771 if (ret != 0) {
772 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
773 ret);
774 }
775
Mark Brownf2c32a82012-06-24 12:09:45 +0100776 info->mic = true;
777 info->detecting = false;
778 goto handled;
779 }
780
781 /* If we detected a lower impedence during initial startup
782 * then we probably have the wrong polarity, flip it. Don't
783 * do this for the lowest impedences to speed up detection of
784 * plain headphones. If both polarities report a low
785 * impedence then give up and report headphones.
786 */
787 if (info->detecting && (val & 0x3f8)) {
Mark Brown84eaa132013-01-25 20:14:44 +0800788 if (info->jack_flips >= info->micd_num_modes * 10) {
Mark Brown4f340332013-01-11 08:55:43 +0900789 dev_dbg(arizona->dev, "Detected HP/line\n");
790 arizona_identify_headphone(info);
Mark Brown9ef2224d2012-06-28 13:08:31 +0100791
Mark Brown4f340332013-01-11 08:55:43 +0900792 info->detecting = false;
793
794 arizona_stop_mic(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100795 } else {
796 info->micd_mode++;
797 if (info->micd_mode == info->micd_num_modes)
798 info->micd_mode = 0;
799 arizona_extcon_set_mode(info, info->micd_mode);
800
801 info->jack_flips++;
802 }
803
804 goto handled;
805 }
806
807 /*
808 * If we're still detecting and we detect a short then we've
Mark Brown34efe4d2012-07-20 17:07:29 +0100809 * got a headphone. Otherwise it's a button press.
Mark Brownf2c32a82012-06-24 12:09:45 +0100810 */
811 if (val & 0x3fc) {
812 if (info->mic) {
813 dev_dbg(arizona->dev, "Mic button detected\n");
814
Mark Brown34efe4d2012-07-20 17:07:29 +0100815 lvl = val & ARIZONA_MICD_LVL_MASK;
816 lvl >>= ARIZONA_MICD_LVL_SHIFT;
817
818 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
819 if (lvl & arizona_lvl_to_key[i].status)
820 input_report_key(info->input,
821 arizona_lvl_to_key[i].report,
822 1);
823 input_sync(info->input);
824
Mark Brownf2c32a82012-06-24 12:09:45 +0100825 } else if (info->detecting) {
826 dev_dbg(arizona->dev, "Headphone detected\n");
827 info->detecting = false;
828 arizona_stop_mic(info);
829
Mark Brown4f340332013-01-11 08:55:43 +0900830 arizona_identify_headphone(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100831 } else {
832 dev_warn(arizona->dev, "Button with no mic: %x\n",
833 val);
834 }
835 } else {
836 dev_dbg(arizona->dev, "Mic button released\n");
Mark Brown34efe4d2012-07-20 17:07:29 +0100837 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
838 input_report_key(info->input,
839 arizona_lvl_to_key[i].report, 0);
840 input_sync(info->input);
Mark Brownbbbd46e2013-01-10 19:38:43 +0000841 arizona_extcon_pulse_micbias(info);
Mark Brownf2c32a82012-06-24 12:09:45 +0100842 }
843
844handled:
845 pm_runtime_mark_last_busy(info->dev);
846 mutex_unlock(&info->lock);
847
848 return IRQ_HANDLED;
849}
850
Mark Brown0e27bd32013-02-05 21:00:15 +0000851static void arizona_hpdet_work(struct work_struct *work)
852{
853 struct arizona_extcon_info *info = container_of(work,
854 struct arizona_extcon_info,
855 hpdet_work.work);
856
857 mutex_lock(&info->lock);
858 arizona_start_hpdet_acc_id(info);
859 mutex_unlock(&info->lock);
860}
861
Mark Brownf2c32a82012-06-24 12:09:45 +0100862static irqreturn_t arizona_jackdet(int irq, void *data)
863{
864 struct arizona_extcon_info *info = data;
865 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +0900866 unsigned int val, present, mask;
Mark Brown34efe4d2012-07-20 17:07:29 +0100867 int ret, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100868
869 pm_runtime_get_sync(info->dev);
870
Mark Brown0e27bd32013-02-05 21:00:15 +0000871 cancel_delayed_work_sync(&info->hpdet_work);
872
Mark Brownf2c32a82012-06-24 12:09:45 +0100873 mutex_lock(&info->lock);
874
Mark Brown92a49872013-01-11 08:55:39 +0900875 if (arizona->pdata.jd_gpio5) {
876 mask = ARIZONA_MICD_CLAMP_STS;
877 present = 0;
878 } else {
879 mask = ARIZONA_JD1_STS;
880 present = ARIZONA_JD1_STS;
881 }
882
Mark Brownf2c32a82012-06-24 12:09:45 +0100883 ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
884 if (ret != 0) {
885 dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
886 ret);
887 mutex_unlock(&info->lock);
888 pm_runtime_put_autosuspend(info->dev);
889 return IRQ_NONE;
890 }
891
Mark Brown92a49872013-01-11 08:55:39 +0900892 if ((val & mask) == present) {
Mark Brownf2c32a82012-06-24 12:09:45 +0100893 dev_dbg(arizona->dev, "Detected jack\n");
Mark Brown325c6422012-06-28 13:08:30 +0100894 ret = extcon_set_cable_state_(&info->edev,
895 ARIZONA_CABLE_MECHANICAL, true);
Mark Brownf2c32a82012-06-24 12:09:45 +0100896
897 if (ret != 0)
898 dev_err(arizona->dev, "Mechanical report failed: %d\n",
899 ret);
900
Mark Browndd235ee2013-01-11 08:55:51 +0900901 if (!arizona->pdata.hpdet_acc_id) {
902 info->detecting = true;
903 info->mic = false;
904 info->jack_flips = 0;
905
906 arizona_start_mic(info);
907 } else {
Mark Brown0e27bd32013-02-05 21:00:15 +0000908 schedule_delayed_work(&info->hpdet_work,
909 msecs_to_jiffies(250));
Mark Browndd235ee2013-01-11 08:55:51 +0900910 }
Mark Brown4e616872013-01-15 22:09:20 +0900911
912 regmap_update_bits(arizona->regmap,
913 ARIZONA_JACK_DETECT_DEBOUNCE,
914 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +0100915 } else {
916 dev_dbg(arizona->dev, "Detected jack removal\n");
917
918 arizona_stop_mic(info);
919
Mark Browndd235ee2013-01-11 08:55:51 +0900920 info->num_hpdet_res = 0;
921 for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
922 info->hpdet_res[i] = 0;
923 info->mic = false;
Mark Brownbf14ee52013-02-05 20:20:17 +0000924 info->hpdet_done = false;
Mark Brown92a49872013-01-11 08:55:39 +0900925
Mark Brown34efe4d2012-07-20 17:07:29 +0100926 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
927 input_report_key(info->input,
928 arizona_lvl_to_key[i].report, 0);
929 input_sync(info->input);
930
Mark Brownf2c32a82012-06-24 12:09:45 +0100931 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
932 if (ret != 0)
933 dev_err(arizona->dev, "Removal report failed: %d\n",
934 ret);
Mark Brown4e616872013-01-15 22:09:20 +0900935
936 regmap_update_bits(arizona->regmap,
937 ARIZONA_JACK_DETECT_DEBOUNCE,
938 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
939 ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
Mark Brownf2c32a82012-06-24 12:09:45 +0100940 }
941
Charles Keepax5d9ab702013-02-05 10:13:38 +0000942 /* Clear trig_sts to make sure DCVDD is not forced up */
943 regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
944 ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
945 ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
946 ARIZONA_JD1_FALL_TRIG_STS |
947 ARIZONA_JD1_RISE_TRIG_STS);
948
Mark Brownf2c32a82012-06-24 12:09:45 +0100949 mutex_unlock(&info->lock);
950
951 pm_runtime_mark_last_busy(info->dev);
952 pm_runtime_put_autosuspend(info->dev);
953
954 return IRQ_HANDLED;
955}
956
Bill Pemberton44f34fd2012-11-19 13:23:21 -0500957static int arizona_extcon_probe(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +0100958{
959 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
960 struct arizona_pdata *pdata;
961 struct arizona_extcon_info *info;
Mark Brown92a49872013-01-11 08:55:39 +0900962 int jack_irq_fall, jack_irq_rise;
Mark Brown34efe4d2012-07-20 17:07:29 +0100963 int ret, mode, i;
Mark Brownf2c32a82012-06-24 12:09:45 +0100964
Mark Brownbbbd46e2013-01-10 19:38:43 +0000965 if (!arizona->dapm || !arizona->dapm->card)
966 return -EPROBE_DEFER;
967
Mark Brownf2c32a82012-06-24 12:09:45 +0100968 pdata = dev_get_platdata(arizona->dev);
969
970 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
971 if (!info) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +0900972 dev_err(&pdev->dev, "Failed to allocate memory\n");
Mark Brownf2c32a82012-06-24 12:09:45 +0100973 ret = -ENOMEM;
974 goto err;
975 }
976
977 info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
978 if (IS_ERR(info->micvdd)) {
979 ret = PTR_ERR(info->micvdd);
980 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
981 goto err;
982 }
983
984 mutex_init(&info->lock);
985 info->arizona = arizona;
986 info->dev = &pdev->dev;
Mark Brown0e27bd32013-02-05 21:00:15 +0000987 INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +0100988 platform_set_drvdata(pdev, info);
989
990 switch (arizona->type) {
991 case WM5102:
992 switch (arizona->rev) {
993 case 0:
994 info->micd_reva = true;
995 break;
996 default:
Mark Browndab63eb2013-01-11 08:55:36 +0900997 info->micd_clamp = true;
Mark Brown4f340332013-01-11 08:55:43 +0900998 info->hpdet_ip = 1;
Mark Brownf2c32a82012-06-24 12:09:45 +0100999 break;
1000 }
1001 break;
1002 default:
1003 break;
1004 }
1005
1006 info->edev.name = "Headset Jack";
1007 info->edev.supported_cable = arizona_cable;
Mark Brownf2c32a82012-06-24 12:09:45 +01001008
1009 ret = extcon_dev_register(&info->edev, arizona->dev);
1010 if (ret < 0) {
Peter Meerwald8e5f5012012-08-23 09:11:50 +09001011 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
Mark Brownf2c32a82012-06-24 12:09:45 +01001012 ret);
1013 goto err;
1014 }
1015
1016 if (pdata->num_micd_configs) {
1017 info->micd_modes = pdata->micd_configs;
1018 info->micd_num_modes = pdata->num_micd_configs;
1019 } else {
1020 info->micd_modes = micd_default_modes;
1021 info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
1022 }
1023
1024 if (arizona->pdata.micd_pol_gpio > 0) {
1025 if (info->micd_modes[0].gpio)
1026 mode = GPIOF_OUT_INIT_HIGH;
1027 else
1028 mode = GPIOF_OUT_INIT_LOW;
1029
1030 ret = devm_gpio_request_one(&pdev->dev,
1031 arizona->pdata.micd_pol_gpio,
1032 mode,
1033 "MICD polarity");
1034 if (ret != 0) {
1035 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1036 arizona->pdata.micd_pol_gpio, ret);
1037 goto err_register;
1038 }
1039 }
1040
Mark Brown1eda6aa2013-01-11 08:55:54 +09001041 if (arizona->pdata.hpdet_id_gpio > 0) {
1042 ret = devm_gpio_request_one(&pdev->dev,
1043 arizona->pdata.hpdet_id_gpio,
1044 GPIOF_OUT_INIT_LOW,
1045 "HPDET");
1046 if (ret != 0) {
1047 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
1048 arizona->pdata.hpdet_id_gpio, ret);
1049 goto err_register;
1050 }
1051 }
1052
Mark Brownb17e5462013-01-11 08:55:24 +09001053 if (arizona->pdata.micd_bias_start_time)
1054 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1055 ARIZONA_MICD_BIAS_STARTTIME_MASK,
1056 arizona->pdata.micd_bias_start_time
1057 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
1058
Mark Brown2e033db2013-01-21 17:36:33 +09001059 if (arizona->pdata.micd_rate)
1060 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1061 ARIZONA_MICD_RATE_MASK,
1062 arizona->pdata.micd_rate
1063 << ARIZONA_MICD_RATE_SHIFT);
1064
1065 if (arizona->pdata.micd_dbtime)
1066 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
1067 ARIZONA_MICD_DBTIME_MASK,
1068 arizona->pdata.micd_dbtime
1069 << ARIZONA_MICD_DBTIME_SHIFT);
1070
Mark Browndab63eb2013-01-11 08:55:36 +09001071 /*
Mark Brown92a49872013-01-11 08:55:39 +09001072 * If we have a clamp use it, activating in conjunction with
1073 * GPIO5 if that is connected for jack detect operation.
Mark Browndab63eb2013-01-11 08:55:36 +09001074 */
1075 if (info->micd_clamp) {
Mark Brown92a49872013-01-11 08:55:39 +09001076 if (arizona->pdata.jd_gpio5) {
1077 /* Put the GPIO into input mode */
1078 regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
1079 0xc101);
1080
1081 regmap_update_bits(arizona->regmap,
1082 ARIZONA_MICD_CLAMP_CONTROL,
1083 ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
1084 } else {
1085 regmap_update_bits(arizona->regmap,
1086 ARIZONA_MICD_CLAMP_CONTROL,
1087 ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
1088 }
1089
Mark Browndab63eb2013-01-11 08:55:36 +09001090 regmap_update_bits(arizona->regmap,
1091 ARIZONA_JACK_DETECT_DEBOUNCE,
1092 ARIZONA_MICD_CLAMP_DB,
1093 ARIZONA_MICD_CLAMP_DB);
1094 }
1095
Mark Brownf2c32a82012-06-24 12:09:45 +01001096 arizona_extcon_set_mode(info, 0);
1097
Mark Brown3d44ea12013-01-11 08:51:13 +09001098 info->input = devm_input_allocate_device(&pdev->dev);
Mark Brown34efe4d2012-07-20 17:07:29 +01001099 if (!info->input) {
1100 dev_err(arizona->dev, "Can't allocate input dev\n");
1101 ret = -ENOMEM;
1102 goto err_register;
1103 }
1104
1105 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
1106 input_set_capability(info->input, EV_KEY,
1107 arizona_lvl_to_key[i].report);
1108 info->input->name = "Headset";
1109 info->input->phys = "arizona/extcon";
1110 info->input->dev.parent = &pdev->dev;
1111
Mark Brownf2c32a82012-06-24 12:09:45 +01001112 pm_runtime_enable(&pdev->dev);
1113 pm_runtime_idle(&pdev->dev);
1114 pm_runtime_get_sync(&pdev->dev);
1115
Mark Brown92a49872013-01-11 08:55:39 +09001116 if (arizona->pdata.jd_gpio5) {
1117 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1118 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1119 } else {
1120 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1121 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1122 }
1123
1124 ret = arizona_request_irq(arizona, jack_irq_rise,
Mark Brownf2c32a82012-06-24 12:09:45 +01001125 "JACKDET rise", arizona_jackdet, info);
1126 if (ret != 0) {
1127 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
1128 ret);
Mark Brown34efe4d2012-07-20 17:07:29 +01001129 goto err_input;
Mark Brownf2c32a82012-06-24 12:09:45 +01001130 }
1131
Mark Brown92a49872013-01-11 08:55:39 +09001132 ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001133 if (ret != 0) {
1134 dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
1135 ret);
1136 goto err_rise;
1137 }
1138
Mark Brown92a49872013-01-11 08:55:39 +09001139 ret = arizona_request_irq(arizona, jack_irq_fall,
Mark Brownf2c32a82012-06-24 12:09:45 +01001140 "JACKDET fall", arizona_jackdet, info);
1141 if (ret != 0) {
1142 dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
1143 goto err_rise_wake;
1144 }
1145
Mark Brown92a49872013-01-11 08:55:39 +09001146 ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
Mark Brownf2c32a82012-06-24 12:09:45 +01001147 if (ret != 0) {
1148 dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
1149 ret);
1150 goto err_fall;
1151 }
1152
1153 ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
1154 "MICDET", arizona_micdet, info);
1155 if (ret != 0) {
1156 dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
1157 goto err_fall_wake;
1158 }
1159
Mark Brown4f340332013-01-11 08:55:43 +09001160 ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
1161 "HPDET", arizona_hpdet_irq, info);
1162 if (ret != 0) {
1163 dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
1164 goto err_micdet;
1165 }
1166
Mark Brownf2c32a82012-06-24 12:09:45 +01001167 arizona_clk32k_enable(arizona);
1168 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
1169 ARIZONA_JD1_DB, ARIZONA_JD1_DB);
1170 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1171 ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
1172
Mark Brownb8575a12012-09-07 17:01:15 +08001173 ret = regulator_allow_bypass(info->micvdd, true);
1174 if (ret != 0)
1175 dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
1176 ret);
1177
Mark Brownf2c32a82012-06-24 12:09:45 +01001178 pm_runtime_put(&pdev->dev);
1179
Mark Brown34efe4d2012-07-20 17:07:29 +01001180 ret = input_register_device(info->input);
1181 if (ret) {
1182 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
Mark Brown4f340332013-01-11 08:55:43 +09001183 goto err_hpdet;
Mark Brown34efe4d2012-07-20 17:07:29 +01001184 }
1185
Mark Brownf2c32a82012-06-24 12:09:45 +01001186 return 0;
1187
Mark Brown4f340332013-01-11 08:55:43 +09001188err_hpdet:
1189 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brown80732cc2012-08-26 13:58:20 -07001190err_micdet:
1191 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001192err_fall_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001193 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001194err_fall:
Mark Brown92a49872013-01-11 08:55:39 +09001195 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001196err_rise_wake:
Mark Brown92a49872013-01-11 08:55:39 +09001197 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
Mark Brownf2c32a82012-06-24 12:09:45 +01001198err_rise:
Mark Brown92a49872013-01-11 08:55:39 +09001199 arizona_free_irq(arizona, jack_irq_rise, info);
Mark Brown34efe4d2012-07-20 17:07:29 +01001200err_input:
Mark Brownf2c32a82012-06-24 12:09:45 +01001201err_register:
1202 pm_runtime_disable(&pdev->dev);
1203 extcon_dev_unregister(&info->edev);
1204err:
1205 return ret;
1206}
1207
Bill Pemberton93ed0322012-11-19 13:25:49 -05001208static int arizona_extcon_remove(struct platform_device *pdev)
Mark Brownf2c32a82012-06-24 12:09:45 +01001209{
1210 struct arizona_extcon_info *info = platform_get_drvdata(pdev);
1211 struct arizona *arizona = info->arizona;
Mark Brown92a49872013-01-11 08:55:39 +09001212 int jack_irq_rise, jack_irq_fall;
Mark Brownf2c32a82012-06-24 12:09:45 +01001213
1214 pm_runtime_disable(&pdev->dev);
1215
Mark Browndab63eb2013-01-11 08:55:36 +09001216 regmap_update_bits(arizona->regmap,
1217 ARIZONA_MICD_CLAMP_CONTROL,
1218 ARIZONA_MICD_CLAMP_MODE_MASK, 0);
1219
Mark Brown92a49872013-01-11 08:55:39 +09001220 if (arizona->pdata.jd_gpio5) {
1221 jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
1222 jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
1223 } else {
1224 jack_irq_rise = ARIZONA_IRQ_JD_RISE;
1225 jack_irq_fall = ARIZONA_IRQ_JD_FALL;
1226 }
1227
1228 arizona_set_irq_wake(arizona, jack_irq_rise, 0);
1229 arizona_set_irq_wake(arizona, jack_irq_fall, 0);
1230 arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
Mark Brownf2c32a82012-06-24 12:09:45 +01001231 arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
Mark Brown92a49872013-01-11 08:55:39 +09001232 arizona_free_irq(arizona, jack_irq_rise, info);
1233 arizona_free_irq(arizona, jack_irq_fall, info);
Mark Brown0e27bd32013-02-05 21:00:15 +00001234 cancel_delayed_work_sync(&info->hpdet_work);
Mark Brownf2c32a82012-06-24 12:09:45 +01001235 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
1236 ARIZONA_JD1_ENA, 0);
1237 arizona_clk32k_disable(arizona);
Mark Brownf2c32a82012-06-24 12:09:45 +01001238 extcon_dev_unregister(&info->edev);
1239
1240 return 0;
1241}
1242
1243static struct platform_driver arizona_extcon_driver = {
1244 .driver = {
1245 .name = "arizona-extcon",
1246 .owner = THIS_MODULE,
1247 },
1248 .probe = arizona_extcon_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -05001249 .remove = arizona_extcon_remove,
Mark Brownf2c32a82012-06-24 12:09:45 +01001250};
1251
1252module_platform_driver(arizona_extcon_driver);
1253
1254MODULE_DESCRIPTION("Arizona Extcon driver");
1255MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1256MODULE_LICENSE("GPL");
1257MODULE_ALIAS("platform:extcon-arizona");