Commit | Line | Data |
---|---|---|
f2c32a88 MB |
1 | /* |
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> | |
34efe4dc | 24 | #include <linux/input.h> |
f2c32a88 MB |
25 | #include <linux/platform_device.h> |
26 | #include <linux/pm_runtime.h> | |
27 | #include <linux/regulator/consumer.h> | |
28 | #include <linux/extcon.h> | |
29 | ||
30 | #include <linux/mfd/arizona/core.h> | |
31 | #include <linux/mfd/arizona/pdata.h> | |
32 | #include <linux/mfd/arizona/registers.h> | |
33 | ||
34efe4dc MB |
34 | #define ARIZONA_NUM_BUTTONS 6 |
35 | ||
f2c32a88 MB |
36 | struct arizona_extcon_info { |
37 | struct device *dev; | |
38 | struct arizona *arizona; | |
39 | struct mutex lock; | |
40 | struct regulator *micvdd; | |
34efe4dc | 41 | struct input_dev *input; |
f2c32a88 MB |
42 | |
43 | int micd_mode; | |
44 | const struct arizona_micd_config *micd_modes; | |
45 | int micd_num_modes; | |
46 | ||
47 | bool micd_reva; | |
dab63eb2 | 48 | bool micd_clamp; |
f2c32a88 MB |
49 | |
50 | bool mic; | |
51 | bool detecting; | |
52 | int jack_flips; | |
53 | ||
54 | struct extcon_dev edev; | |
55 | }; | |
56 | ||
57 | static const struct arizona_micd_config micd_default_modes[] = { | |
58 | { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 }, | |
59 | { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 }, | |
60 | }; | |
61 | ||
34efe4dc MB |
62 | static struct { |
63 | u16 status; | |
64 | int report; | |
65 | } arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = { | |
66 | { 0x1, BTN_0 }, | |
67 | { 0x2, BTN_1 }, | |
68 | { 0x4, BTN_2 }, | |
69 | { 0x8, BTN_3 }, | |
70 | { 0x10, BTN_4 }, | |
71 | { 0x20, BTN_5 }, | |
72 | }; | |
73 | ||
325c6423 MB |
74 | #define ARIZONA_CABLE_MECHANICAL 0 |
75 | #define ARIZONA_CABLE_MICROPHONE 1 | |
76 | #define ARIZONA_CABLE_HEADPHONE 2 | |
f2c32a88 MB |
77 | |
78 | static const char *arizona_cable[] = { | |
325c6423 MB |
79 | "Mechanical", |
80 | "Microphone", | |
81 | "Headphone", | |
f2c32a88 MB |
82 | NULL, |
83 | }; | |
84 | ||
f2c32a88 MB |
85 | static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) |
86 | { | |
87 | struct arizona *arizona = info->arizona; | |
88 | ||
cd74f7b3 MB |
89 | if (arizona->pdata.micd_pol_gpio > 0) |
90 | gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio, | |
91 | info->micd_modes[mode].gpio); | |
f2c32a88 MB |
92 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, |
93 | ARIZONA_MICD_BIAS_SRC_MASK, | |
94 | info->micd_modes[mode].bias); | |
95 | regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, | |
96 | ARIZONA_ACCDET_SRC, info->micd_modes[mode].src); | |
97 | ||
98 | info->micd_mode = mode; | |
99 | ||
100 | dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode); | |
101 | } | |
102 | ||
103 | static void arizona_start_mic(struct arizona_extcon_info *info) | |
104 | { | |
105 | struct arizona *arizona = info->arizona; | |
106 | bool change; | |
107 | int ret; | |
108 | ||
109 | info->detecting = true; | |
110 | info->mic = false; | |
111 | info->jack_flips = 0; | |
112 | ||
113 | /* Microphone detection can't use idle mode */ | |
114 | pm_runtime_get(info->dev); | |
115 | ||
116 | ret = regulator_enable(info->micvdd); | |
117 | if (ret != 0) { | |
118 | dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", | |
119 | ret); | |
120 | } | |
121 | ||
122 | if (info->micd_reva) { | |
123 | regmap_write(arizona->regmap, 0x80, 0x3); | |
124 | regmap_write(arizona->regmap, 0x294, 0); | |
125 | regmap_write(arizona->regmap, 0x80, 0x0); | |
126 | } | |
127 | ||
128 | regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, | |
129 | ARIZONA_MICD_ENA, ARIZONA_MICD_ENA, | |
130 | &change); | |
131 | if (!change) { | |
132 | regulator_disable(info->micvdd); | |
133 | pm_runtime_put_autosuspend(info->dev); | |
134 | } | |
135 | } | |
136 | ||
137 | static void arizona_stop_mic(struct arizona_extcon_info *info) | |
138 | { | |
139 | struct arizona *arizona = info->arizona; | |
140 | bool change; | |
141 | ||
142 | regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, | |
143 | ARIZONA_MICD_ENA, 0, | |
144 | &change); | |
145 | ||
146 | if (info->micd_reva) { | |
147 | regmap_write(arizona->regmap, 0x80, 0x3); | |
148 | regmap_write(arizona->regmap, 0x294, 2); | |
149 | regmap_write(arizona->regmap, 0x80, 0x0); | |
150 | } | |
151 | ||
152 | if (change) { | |
153 | regulator_disable(info->micvdd); | |
34efe4dc | 154 | pm_runtime_mark_last_busy(info->dev); |
f2c32a88 MB |
155 | pm_runtime_put_autosuspend(info->dev); |
156 | } | |
157 | } | |
158 | ||
159 | static irqreturn_t arizona_micdet(int irq, void *data) | |
160 | { | |
161 | struct arizona_extcon_info *info = data; | |
162 | struct arizona *arizona = info->arizona; | |
34efe4dc MB |
163 | unsigned int val, lvl; |
164 | int ret, i; | |
f2c32a88 MB |
165 | |
166 | mutex_lock(&info->lock); | |
167 | ||
168 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); | |
169 | if (ret != 0) { | |
170 | dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); | |
be31cc0b | 171 | mutex_unlock(&info->lock); |
f2c32a88 MB |
172 | return IRQ_NONE; |
173 | } | |
174 | ||
175 | dev_dbg(arizona->dev, "MICDET: %x\n", val); | |
176 | ||
177 | if (!(val & ARIZONA_MICD_VALID)) { | |
178 | dev_warn(arizona->dev, "Microphone detection state invalid\n"); | |
179 | mutex_unlock(&info->lock); | |
180 | return IRQ_NONE; | |
181 | } | |
182 | ||
183 | /* Due to jack detect this should never happen */ | |
184 | if (!(val & ARIZONA_MICD_STS)) { | |
185 | dev_warn(arizona->dev, "Detected open circuit\n"); | |
186 | info->detecting = false; | |
187 | goto handled; | |
188 | } | |
189 | ||
190 | /* If we got a high impedence we should have a headset, report it. */ | |
191 | if (info->detecting && (val & 0x400)) { | |
325c6423 MB |
192 | ret = extcon_update_state(&info->edev, |
193 | 1 << ARIZONA_CABLE_MICROPHONE | | |
194 | 1 << ARIZONA_CABLE_HEADPHONE, | |
195 | 1 << ARIZONA_CABLE_MICROPHONE | | |
196 | 1 << ARIZONA_CABLE_HEADPHONE); | |
f2c32a88 MB |
197 | |
198 | if (ret != 0) | |
199 | dev_err(arizona->dev, "Headset report failed: %d\n", | |
200 | ret); | |
201 | ||
202 | info->mic = true; | |
203 | info->detecting = false; | |
204 | goto handled; | |
205 | } | |
206 | ||
207 | /* If we detected a lower impedence during initial startup | |
208 | * then we probably have the wrong polarity, flip it. Don't | |
209 | * do this for the lowest impedences to speed up detection of | |
210 | * plain headphones. If both polarities report a low | |
211 | * impedence then give up and report headphones. | |
212 | */ | |
213 | if (info->detecting && (val & 0x3f8)) { | |
214 | info->jack_flips++; | |
215 | ||
216 | if (info->jack_flips >= info->micd_num_modes) { | |
217 | dev_dbg(arizona->dev, "Detected headphone\n"); | |
218 | info->detecting = false; | |
9ef2224d MB |
219 | arizona_stop_mic(info); |
220 | ||
325c6423 MB |
221 | ret = extcon_set_cable_state_(&info->edev, |
222 | ARIZONA_CABLE_HEADPHONE, | |
223 | true); | |
f2c32a88 MB |
224 | if (ret != 0) |
225 | dev_err(arizona->dev, | |
226 | "Headphone report failed: %d\n", | |
227 | ret); | |
228 | } else { | |
229 | info->micd_mode++; | |
230 | if (info->micd_mode == info->micd_num_modes) | |
231 | info->micd_mode = 0; | |
232 | arizona_extcon_set_mode(info, info->micd_mode); | |
233 | ||
234 | info->jack_flips++; | |
235 | } | |
236 | ||
237 | goto handled; | |
238 | } | |
239 | ||
240 | /* | |
241 | * If we're still detecting and we detect a short then we've | |
34efe4dc | 242 | * got a headphone. Otherwise it's a button press. |
f2c32a88 MB |
243 | */ |
244 | if (val & 0x3fc) { | |
245 | if (info->mic) { | |
246 | dev_dbg(arizona->dev, "Mic button detected\n"); | |
247 | ||
34efe4dc MB |
248 | lvl = val & ARIZONA_MICD_LVL_MASK; |
249 | lvl >>= ARIZONA_MICD_LVL_SHIFT; | |
250 | ||
251 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) | |
252 | if (lvl & arizona_lvl_to_key[i].status) | |
253 | input_report_key(info->input, | |
254 | arizona_lvl_to_key[i].report, | |
255 | 1); | |
256 | input_sync(info->input); | |
257 | ||
f2c32a88 MB |
258 | } else if (info->detecting) { |
259 | dev_dbg(arizona->dev, "Headphone detected\n"); | |
260 | info->detecting = false; | |
261 | arizona_stop_mic(info); | |
262 | ||
325c6423 MB |
263 | ret = extcon_set_cable_state_(&info->edev, |
264 | ARIZONA_CABLE_HEADPHONE, | |
265 | true); | |
f2c32a88 MB |
266 | if (ret != 0) |
267 | dev_err(arizona->dev, | |
268 | "Headphone report failed: %d\n", | |
269 | ret); | |
270 | } else { | |
271 | dev_warn(arizona->dev, "Button with no mic: %x\n", | |
272 | val); | |
273 | } | |
274 | } else { | |
275 | dev_dbg(arizona->dev, "Mic button released\n"); | |
34efe4dc MB |
276 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) |
277 | input_report_key(info->input, | |
278 | arizona_lvl_to_key[i].report, 0); | |
279 | input_sync(info->input); | |
f2c32a88 MB |
280 | } |
281 | ||
282 | handled: | |
283 | pm_runtime_mark_last_busy(info->dev); | |
284 | mutex_unlock(&info->lock); | |
285 | ||
286 | return IRQ_HANDLED; | |
287 | } | |
288 | ||
289 | static irqreturn_t arizona_jackdet(int irq, void *data) | |
290 | { | |
291 | struct arizona_extcon_info *info = data; | |
292 | struct arizona *arizona = info->arizona; | |
92a49871 | 293 | unsigned int val, present, mask; |
34efe4dc | 294 | int ret, i; |
f2c32a88 MB |
295 | |
296 | pm_runtime_get_sync(info->dev); | |
297 | ||
298 | mutex_lock(&info->lock); | |
299 | ||
92a49871 MB |
300 | if (arizona->pdata.jd_gpio5) { |
301 | mask = ARIZONA_MICD_CLAMP_STS; | |
302 | present = 0; | |
303 | } else { | |
304 | mask = ARIZONA_JD1_STS; | |
305 | present = ARIZONA_JD1_STS; | |
306 | } | |
307 | ||
f2c32a88 MB |
308 | ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val); |
309 | if (ret != 0) { | |
310 | dev_err(arizona->dev, "Failed to read jackdet status: %d\n", | |
311 | ret); | |
312 | mutex_unlock(&info->lock); | |
313 | pm_runtime_put_autosuspend(info->dev); | |
314 | return IRQ_NONE; | |
315 | } | |
316 | ||
92a49871 | 317 | if ((val & mask) == present) { |
f2c32a88 | 318 | dev_dbg(arizona->dev, "Detected jack\n"); |
325c6423 MB |
319 | ret = extcon_set_cable_state_(&info->edev, |
320 | ARIZONA_CABLE_MECHANICAL, true); | |
f2c32a88 MB |
321 | |
322 | if (ret != 0) | |
323 | dev_err(arizona->dev, "Mechanical report failed: %d\n", | |
324 | ret); | |
325 | ||
326 | arizona_start_mic(info); | |
327 | } else { | |
328 | dev_dbg(arizona->dev, "Detected jack removal\n"); | |
329 | ||
330 | arizona_stop_mic(info); | |
331 | ||
92a49871 | 332 | |
34efe4dc MB |
333 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) |
334 | input_report_key(info->input, | |
335 | arizona_lvl_to_key[i].report, 0); | |
336 | input_sync(info->input); | |
337 | ||
f2c32a88 MB |
338 | ret = extcon_update_state(&info->edev, 0xffffffff, 0); |
339 | if (ret != 0) | |
340 | dev_err(arizona->dev, "Removal report failed: %d\n", | |
341 | ret); | |
342 | } | |
343 | ||
344 | mutex_unlock(&info->lock); | |
345 | ||
346 | pm_runtime_mark_last_busy(info->dev); | |
347 | pm_runtime_put_autosuspend(info->dev); | |
348 | ||
349 | return IRQ_HANDLED; | |
350 | } | |
351 | ||
44f34fd4 | 352 | static int arizona_extcon_probe(struct platform_device *pdev) |
f2c32a88 MB |
353 | { |
354 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); | |
355 | struct arizona_pdata *pdata; | |
356 | struct arizona_extcon_info *info; | |
92a49871 | 357 | int jack_irq_fall, jack_irq_rise; |
34efe4dc | 358 | int ret, mode, i; |
f2c32a88 MB |
359 | |
360 | pdata = dev_get_platdata(arizona->dev); | |
361 | ||
362 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); | |
363 | if (!info) { | |
8e5f5018 | 364 | dev_err(&pdev->dev, "Failed to allocate memory\n"); |
f2c32a88 MB |
365 | ret = -ENOMEM; |
366 | goto err; | |
367 | } | |
368 | ||
369 | info->micvdd = devm_regulator_get(arizona->dev, "MICVDD"); | |
370 | if (IS_ERR(info->micvdd)) { | |
371 | ret = PTR_ERR(info->micvdd); | |
372 | dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret); | |
373 | goto err; | |
374 | } | |
375 | ||
376 | mutex_init(&info->lock); | |
377 | info->arizona = arizona; | |
378 | info->dev = &pdev->dev; | |
379 | info->detecting = true; | |
380 | platform_set_drvdata(pdev, info); | |
381 | ||
382 | switch (arizona->type) { | |
383 | case WM5102: | |
384 | switch (arizona->rev) { | |
385 | case 0: | |
386 | info->micd_reva = true; | |
387 | break; | |
388 | default: | |
dab63eb2 | 389 | info->micd_clamp = true; |
f2c32a88 MB |
390 | break; |
391 | } | |
392 | break; | |
393 | default: | |
394 | break; | |
395 | } | |
396 | ||
397 | info->edev.name = "Headset Jack"; | |
398 | info->edev.supported_cable = arizona_cable; | |
f2c32a88 MB |
399 | |
400 | ret = extcon_dev_register(&info->edev, arizona->dev); | |
401 | if (ret < 0) { | |
8e5f5018 | 402 | dev_err(arizona->dev, "extcon_dev_register() failed: %d\n", |
f2c32a88 MB |
403 | ret); |
404 | goto err; | |
405 | } | |
406 | ||
407 | if (pdata->num_micd_configs) { | |
408 | info->micd_modes = pdata->micd_configs; | |
409 | info->micd_num_modes = pdata->num_micd_configs; | |
410 | } else { | |
411 | info->micd_modes = micd_default_modes; | |
412 | info->micd_num_modes = ARRAY_SIZE(micd_default_modes); | |
413 | } | |
414 | ||
415 | if (arizona->pdata.micd_pol_gpio > 0) { | |
416 | if (info->micd_modes[0].gpio) | |
417 | mode = GPIOF_OUT_INIT_HIGH; | |
418 | else | |
419 | mode = GPIOF_OUT_INIT_LOW; | |
420 | ||
421 | ret = devm_gpio_request_one(&pdev->dev, | |
422 | arizona->pdata.micd_pol_gpio, | |
423 | mode, | |
424 | "MICD polarity"); | |
425 | if (ret != 0) { | |
426 | dev_err(arizona->dev, "Failed to request GPIO%d: %d\n", | |
427 | arizona->pdata.micd_pol_gpio, ret); | |
428 | goto err_register; | |
429 | } | |
430 | } | |
431 | ||
b17e5462 MB |
432 | if (arizona->pdata.micd_bias_start_time) |
433 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, | |
434 | ARIZONA_MICD_BIAS_STARTTIME_MASK, | |
435 | arizona->pdata.micd_bias_start_time | |
436 | << ARIZONA_MICD_BIAS_STARTTIME_SHIFT); | |
437 | ||
dab63eb2 | 438 | /* |
92a49871 MB |
439 | * If we have a clamp use it, activating in conjunction with |
440 | * GPIO5 if that is connected for jack detect operation. | |
dab63eb2 MB |
441 | */ |
442 | if (info->micd_clamp) { | |
92a49871 MB |
443 | if (arizona->pdata.jd_gpio5) { |
444 | /* Put the GPIO into input mode */ | |
445 | regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL, | |
446 | 0xc101); | |
447 | ||
448 | regmap_update_bits(arizona->regmap, | |
449 | ARIZONA_MICD_CLAMP_CONTROL, | |
450 | ARIZONA_MICD_CLAMP_MODE_MASK, 0x9); | |
451 | } else { | |
452 | regmap_update_bits(arizona->regmap, | |
453 | ARIZONA_MICD_CLAMP_CONTROL, | |
454 | ARIZONA_MICD_CLAMP_MODE_MASK, 0x4); | |
455 | } | |
456 | ||
dab63eb2 MB |
457 | regmap_update_bits(arizona->regmap, |
458 | ARIZONA_JACK_DETECT_DEBOUNCE, | |
459 | ARIZONA_MICD_CLAMP_DB, | |
460 | ARIZONA_MICD_CLAMP_DB); | |
461 | } | |
462 | ||
f2c32a88 MB |
463 | arizona_extcon_set_mode(info, 0); |
464 | ||
3d44ea1c | 465 | info->input = devm_input_allocate_device(&pdev->dev); |
34efe4dc MB |
466 | if (!info->input) { |
467 | dev_err(arizona->dev, "Can't allocate input dev\n"); | |
468 | ret = -ENOMEM; | |
469 | goto err_register; | |
470 | } | |
471 | ||
472 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) | |
473 | input_set_capability(info->input, EV_KEY, | |
474 | arizona_lvl_to_key[i].report); | |
475 | info->input->name = "Headset"; | |
476 | info->input->phys = "arizona/extcon"; | |
477 | info->input->dev.parent = &pdev->dev; | |
478 | ||
f2c32a88 MB |
479 | pm_runtime_enable(&pdev->dev); |
480 | pm_runtime_idle(&pdev->dev); | |
481 | pm_runtime_get_sync(&pdev->dev); | |
482 | ||
92a49871 MB |
483 | if (arizona->pdata.jd_gpio5) { |
484 | jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; | |
485 | jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL; | |
486 | } else { | |
487 | jack_irq_rise = ARIZONA_IRQ_JD_RISE; | |
488 | jack_irq_fall = ARIZONA_IRQ_JD_FALL; | |
489 | } | |
490 | ||
491 | ret = arizona_request_irq(arizona, jack_irq_rise, | |
f2c32a88 MB |
492 | "JACKDET rise", arizona_jackdet, info); |
493 | if (ret != 0) { | |
494 | dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n", | |
495 | ret); | |
34efe4dc | 496 | goto err_input; |
f2c32a88 MB |
497 | } |
498 | ||
92a49871 | 499 | ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1); |
f2c32a88 MB |
500 | if (ret != 0) { |
501 | dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n", | |
502 | ret); | |
503 | goto err_rise; | |
504 | } | |
505 | ||
92a49871 | 506 | ret = arizona_request_irq(arizona, jack_irq_fall, |
f2c32a88 MB |
507 | "JACKDET fall", arizona_jackdet, info); |
508 | if (ret != 0) { | |
509 | dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret); | |
510 | goto err_rise_wake; | |
511 | } | |
512 | ||
92a49871 | 513 | ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1); |
f2c32a88 MB |
514 | if (ret != 0) { |
515 | dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n", | |
516 | ret); | |
517 | goto err_fall; | |
518 | } | |
519 | ||
520 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET, | |
521 | "MICDET", arizona_micdet, info); | |
522 | if (ret != 0) { | |
523 | dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret); | |
524 | goto err_fall_wake; | |
525 | } | |
526 | ||
527 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, | |
f2c32a88 | 528 | ARIZONA_MICD_RATE_MASK, |
f2c32a88 MB |
529 | 8 << ARIZONA_MICD_RATE_SHIFT); |
530 | ||
531 | arizona_clk32k_enable(arizona); | |
532 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE, | |
533 | ARIZONA_JD1_DB, ARIZONA_JD1_DB); | |
534 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, | |
535 | ARIZONA_JD1_ENA, ARIZONA_JD1_ENA); | |
536 | ||
b8575a11 MB |
537 | ret = regulator_allow_bypass(info->micvdd, true); |
538 | if (ret != 0) | |
539 | dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", | |
540 | ret); | |
541 | ||
f2c32a88 MB |
542 | pm_runtime_put(&pdev->dev); |
543 | ||
34efe4dc MB |
544 | ret = input_register_device(info->input); |
545 | if (ret) { | |
546 | dev_err(&pdev->dev, "Can't register input device: %d\n", ret); | |
80732cc1 | 547 | goto err_micdet; |
34efe4dc MB |
548 | } |
549 | ||
f2c32a88 MB |
550 | return 0; |
551 | ||
80732cc1 MB |
552 | err_micdet: |
553 | arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info); | |
f2c32a88 | 554 | err_fall_wake: |
92a49871 | 555 | arizona_set_irq_wake(arizona, jack_irq_fall, 0); |
f2c32a88 | 556 | err_fall: |
92a49871 | 557 | arizona_free_irq(arizona, jack_irq_fall, info); |
f2c32a88 | 558 | err_rise_wake: |
92a49871 | 559 | arizona_set_irq_wake(arizona, jack_irq_rise, 0); |
f2c32a88 | 560 | err_rise: |
92a49871 | 561 | arizona_free_irq(arizona, jack_irq_rise, info); |
34efe4dc | 562 | err_input: |
f2c32a88 MB |
563 | err_register: |
564 | pm_runtime_disable(&pdev->dev); | |
565 | extcon_dev_unregister(&info->edev); | |
566 | err: | |
567 | return ret; | |
568 | } | |
569 | ||
93ed0327 | 570 | static int arizona_extcon_remove(struct platform_device *pdev) |
f2c32a88 MB |
571 | { |
572 | struct arizona_extcon_info *info = platform_get_drvdata(pdev); | |
573 | struct arizona *arizona = info->arizona; | |
92a49871 | 574 | int jack_irq_rise, jack_irq_fall; |
f2c32a88 MB |
575 | |
576 | pm_runtime_disable(&pdev->dev); | |
577 | ||
dab63eb2 MB |
578 | regmap_update_bits(arizona->regmap, |
579 | ARIZONA_MICD_CLAMP_CONTROL, | |
580 | ARIZONA_MICD_CLAMP_MODE_MASK, 0); | |
581 | ||
92a49871 MB |
582 | if (arizona->pdata.jd_gpio5) { |
583 | jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; | |
584 | jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL; | |
585 | } else { | |
586 | jack_irq_rise = ARIZONA_IRQ_JD_RISE; | |
587 | jack_irq_fall = ARIZONA_IRQ_JD_FALL; | |
588 | } | |
589 | ||
590 | arizona_set_irq_wake(arizona, jack_irq_rise, 0); | |
591 | arizona_set_irq_wake(arizona, jack_irq_fall, 0); | |
592 | arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info); | |
f2c32a88 | 593 | arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info); |
92a49871 MB |
594 | arizona_free_irq(arizona, jack_irq_rise, info); |
595 | arizona_free_irq(arizona, jack_irq_fall, info); | |
f2c32a88 MB |
596 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, |
597 | ARIZONA_JD1_ENA, 0); | |
598 | arizona_clk32k_disable(arizona); | |
599 | extcon_dev_unregister(&info->edev); | |
600 | ||
601 | return 0; | |
602 | } | |
603 | ||
604 | static struct platform_driver arizona_extcon_driver = { | |
605 | .driver = { | |
606 | .name = "arizona-extcon", | |
607 | .owner = THIS_MODULE, | |
608 | }, | |
609 | .probe = arizona_extcon_probe, | |
5f7e2228 | 610 | .remove = arizona_extcon_remove, |
f2c32a88 MB |
611 | }; |
612 | ||
613 | module_platform_driver(arizona_extcon_driver); | |
614 | ||
615 | MODULE_DESCRIPTION("Arizona Extcon driver"); | |
616 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | |
617 | MODULE_LICENSE("GPL"); | |
618 | MODULE_ALIAS("platform:extcon-arizona"); |