]> Pileus Git - ~andy/linux/blob - drivers/extcon/extcon-arizona.c
extcon: arizona: Support use of GPIO5 as an input to jack detection
[~andy/linux] / drivers / extcon / extcon-arizona.c
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>
24 #include <linux/input.h>
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
34 #define ARIZONA_NUM_BUTTONS 6
35
36 struct arizona_extcon_info {
37         struct device *dev;
38         struct arizona *arizona;
39         struct mutex lock;
40         struct regulator *micvdd;
41         struct input_dev *input;
42
43         int micd_mode;
44         const struct arizona_micd_config *micd_modes;
45         int micd_num_modes;
46
47         bool micd_reva;
48         bool micd_clamp;
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
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
74 #define ARIZONA_CABLE_MECHANICAL 0
75 #define ARIZONA_CABLE_MICROPHONE 1
76 #define ARIZONA_CABLE_HEADPHONE  2
77
78 static const char *arizona_cable[] = {
79         "Mechanical",
80         "Microphone",
81         "Headphone",
82         NULL,
83 };
84
85 static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
86 {
87         struct arizona *arizona = info->arizona;
88
89         if (arizona->pdata.micd_pol_gpio > 0)
90                 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
91                                         info->micd_modes[mode].gpio);
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);
154                 pm_runtime_mark_last_busy(info->dev);
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;
163         unsigned int val, lvl;
164         int ret, i;
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);
171                 mutex_unlock(&info->lock);
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)) {
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);
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;
219                         arizona_stop_mic(info);
220
221                         ret = extcon_set_cable_state_(&info->edev,
222                                                       ARIZONA_CABLE_HEADPHONE,
223                                                       true);
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
242          * got a headphone.  Otherwise it's a button press.
243          */
244         if (val & 0x3fc) {
245                 if (info->mic) {
246                         dev_dbg(arizona->dev, "Mic button detected\n");
247
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
258                 } else if (info->detecting) {
259                         dev_dbg(arizona->dev, "Headphone detected\n");
260                         info->detecting = false;
261                         arizona_stop_mic(info);
262
263                         ret = extcon_set_cable_state_(&info->edev,
264                                                       ARIZONA_CABLE_HEADPHONE,
265                                                       true);
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");
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);
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;
293         unsigned int val, present, mask;
294         int ret, i;
295
296         pm_runtime_get_sync(info->dev);
297
298         mutex_lock(&info->lock);
299
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
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
317         if ((val & mask) == present) {
318                 dev_dbg(arizona->dev, "Detected jack\n");
319                 ret = extcon_set_cable_state_(&info->edev,
320                                               ARIZONA_CABLE_MECHANICAL, true);
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
332
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
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
352 static int arizona_extcon_probe(struct platform_device *pdev)
353 {
354         struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
355         struct arizona_pdata *pdata;
356         struct arizona_extcon_info *info;
357         int jack_irq_fall, jack_irq_rise;
358         int ret, mode, i;
359
360         pdata = dev_get_platdata(arizona->dev);
361
362         info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
363         if (!info) {
364                 dev_err(&pdev->dev, "Failed to allocate memory\n");
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:
389                         info->micd_clamp = true;
390                         break;
391                 }
392                 break;
393         default:
394                 break;
395         }
396
397         info->edev.name = "Headset Jack";
398         info->edev.supported_cable = arizona_cable;
399
400         ret = extcon_dev_register(&info->edev, arizona->dev);
401         if (ret < 0) {
402                 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
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
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
438         /*
439          * If we have a clamp use it, activating in conjunction with
440          * GPIO5 if that is connected for jack detect operation.
441          */
442         if (info->micd_clamp) {
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
457                 regmap_update_bits(arizona->regmap,
458                                    ARIZONA_JACK_DETECT_DEBOUNCE,
459                                    ARIZONA_MICD_CLAMP_DB,
460                                    ARIZONA_MICD_CLAMP_DB);
461         }
462
463         arizona_extcon_set_mode(info, 0);
464
465         info->input = devm_input_allocate_device(&pdev->dev);
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
479         pm_runtime_enable(&pdev->dev);
480         pm_runtime_idle(&pdev->dev);
481         pm_runtime_get_sync(&pdev->dev);
482
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,
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);
496                 goto err_input;
497         }
498
499         ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
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
506         ret = arizona_request_irq(arizona, jack_irq_fall,
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
513         ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
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,
528                            ARIZONA_MICD_RATE_MASK,
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
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
542         pm_runtime_put(&pdev->dev);
543
544         ret = input_register_device(info->input);
545         if (ret) {
546                 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
547                 goto err_micdet;
548         }
549
550         return 0;
551
552 err_micdet:
553         arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
554 err_fall_wake:
555         arizona_set_irq_wake(arizona, jack_irq_fall, 0);
556 err_fall:
557         arizona_free_irq(arizona, jack_irq_fall, info);
558 err_rise_wake:
559         arizona_set_irq_wake(arizona, jack_irq_rise, 0);
560 err_rise:
561         arizona_free_irq(arizona, jack_irq_rise, info);
562 err_input:
563 err_register:
564         pm_runtime_disable(&pdev->dev);
565         extcon_dev_unregister(&info->edev);
566 err:
567         return ret;
568 }
569
570 static int arizona_extcon_remove(struct platform_device *pdev)
571 {
572         struct arizona_extcon_info *info = platform_get_drvdata(pdev);
573         struct arizona *arizona = info->arizona;
574         int jack_irq_rise, jack_irq_fall;
575
576         pm_runtime_disable(&pdev->dev);
577
578         regmap_update_bits(arizona->regmap,
579                            ARIZONA_MICD_CLAMP_CONTROL,
580                            ARIZONA_MICD_CLAMP_MODE_MASK, 0);
581
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);
593         arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
594         arizona_free_irq(arizona, jack_irq_rise, info);
595         arizona_free_irq(arizona, jack_irq_fall, info);
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,
610         .remove         = arizona_extcon_remove,
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");