Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
extcon-arizona.c
Go to the documentation of this file.
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>
28 #include <linux/extcon.h>
29 
30 #include <linux/mfd/arizona/core.h>
33 
34 #define ARIZONA_NUM_BUTTONS 6
35 
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;
46 
47  bool micd_reva;
48 
49  bool mic;
50  bool detecting;
52 
53  struct extcon_dev edev;
54 };
55 
56 static const struct arizona_micd_config micd_default_modes[] = {
58  { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
59 };
60 
61 static struct {
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 
73 #define ARIZONA_CABLE_MECHANICAL 0
74 #define ARIZONA_CABLE_MICROPHONE 1
75 #define ARIZONA_CABLE_HEADPHONE 2
76 
77 static const char *arizona_cable[] = {
78  "Mechanical",
79  "Microphone",
80  "Headphone",
81  NULL,
82 };
83 
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);
92  info->micd_modes[mode].bias);
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 
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 
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);
152  pm_runtime_mark_last_busy(info->dev);
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;
161  unsigned int val, lvl;
162  int ret, i;
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)) {
189  ret = extcon_update_state(&info->edev,
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;
216  arizona_stop_mic(info);
217 
218  ret = extcon_set_cable_state_(&info->edev,
220  true);
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
239  * got a headphone. Otherwise it's a button press.
240  */
241  if (val & 0x3fc) {
242  if (info->mic) {
243  dev_dbg(arizona->dev, "Mic button detected\n");
244 
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 
255  } else if (info->detecting) {
256  dev_dbg(arizona->dev, "Headphone detected\n");
257  info->detecting = false;
258  arizona_stop_mic(info);
259 
260  ret = extcon_set_cable_state_(&info->edev,
262  true);
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");
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);
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;
291  int ret, i;
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");
308  ret = extcon_set_cable_state_(&info->edev,
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 
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 
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 
340 static int __devinit arizona_extcon_probe(struct platform_device *pdev)
341 {
342  struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
343  struct arizona_pdata *pdata;
344  struct arizona_extcon_info *info;
345  int ret, mode, i;
346 
347  pdata = dev_get_platdata(arizona->dev);
348 
349  info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
350  if (!info) {
351  dev_err(&pdev->dev, "Failed to allocate memory\n");
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;
385 
386  ret = extcon_dev_register(&info->edev, arizona->dev);
387  if (ret < 0) {
388  dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
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 
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 
434  pm_runtime_enable(&pdev->dev);
435  pm_runtime_idle(&pdev->dev);
436  pm_runtime_get_sync(&pdev->dev);
437 
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);
443  goto err_input;
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 
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 
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 
479 
480  arizona_clk32k_enable(arizona);
485 
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 
491  pm_runtime_put(&pdev->dev);
492 
493  ret = input_register_device(info->input);
494  if (ret) {
495  dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
496  goto err_micdet;
497  }
498 
499  return 0;
500 
501 err_micdet:
502  arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
503 err_fall_wake:
505 err_fall:
506  arizona_free_irq(arizona, ARIZONA_IRQ_JD_FALL, info);
507 err_rise_wake:
509 err_rise:
510  arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info);
511 err_input:
512  input_free_device(info->input);
513 err_register:
514  pm_runtime_disable(&pdev->dev);
515  extcon_dev_unregister(&info->edev);
516 err:
517  return ret;
518 }
519 
520 static int __devexit arizona_extcon_remove(struct platform_device *pdev)
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 
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);
533  ARIZONA_JD1_ENA, 0);
534  arizona_clk32k_disable(arizona);
535  input_unregister_device(info->input);
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 <[email protected]>");
554 MODULE_LICENSE("GPL");
555 MODULE_ALIAS("platform:extcon-arizona");