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