aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon/extcon-arizona.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-07-20 12:07:29 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-16 13:35:52 -0400
commit34efe4dc47227264a38e60c878b4831d5f0d5a33 (patch)
tree68db9434049a5119cc5e0a5d689dbfaa7419f6af /drivers/extcon/extcon-arizona.c
parent689ae231afbac8979f96100b372a5a73458baaa9 (diff)
extcon: arizona: Implement button detection support
As well as identifying accessories the accessory detection hardware on Arizona class devices can also detect a number of buttons which we should report via the input API. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/extcon/extcon-arizona.c')
-rw-r--r--drivers/extcon/extcon-arizona.c72
1 files changed, 65 insertions, 7 deletions
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 427a289f32a5..fa2114f1f9ec 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -21,6 +21,7 @@
21#include <linux/interrupt.h> 21#include <linux/interrupt.h>
22#include <linux/err.h> 22#include <linux/err.h>
23#include <linux/gpio.h> 23#include <linux/gpio.h>
24#include <linux/input.h>
24#include <linux/platform_device.h> 25#include <linux/platform_device.h>
25#include <linux/pm_runtime.h> 26#include <linux/pm_runtime.h>
26#include <linux/regulator/consumer.h> 27#include <linux/regulator/consumer.h>
@@ -30,11 +31,14 @@
30#include <linux/mfd/arizona/pdata.h> 31#include <linux/mfd/arizona/pdata.h>
31#include <linux/mfd/arizona/registers.h> 32#include <linux/mfd/arizona/registers.h>
32 33
34#define ARIZONA_NUM_BUTTONS 6
35
33struct arizona_extcon_info { 36struct arizona_extcon_info {
34 struct device *dev; 37 struct device *dev;
35 struct arizona *arizona; 38 struct arizona *arizona;
36 struct mutex lock; 39 struct mutex lock;
37 struct regulator *micvdd; 40 struct regulator *micvdd;
41 struct input_dev *input;
38 42
39 int micd_mode; 43 int micd_mode;
40 const struct arizona_micd_config *micd_modes; 44 const struct arizona_micd_config *micd_modes;
@@ -54,6 +58,18 @@ static const struct arizona_micd_config micd_default_modes[] = {
54 { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 }, 58 { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
55}; 59};
56 60
61static 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
57#define ARIZONA_CABLE_MECHANICAL 0 73#define ARIZONA_CABLE_MECHANICAL 0
58#define ARIZONA_CABLE_MICROPHONE 1 74#define ARIZONA_CABLE_MICROPHONE 1
59#define ARIZONA_CABLE_HEADPHONE 2 75#define ARIZONA_CABLE_HEADPHONE 2
@@ -133,6 +149,7 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
133 149
134 if (change) { 150 if (change) {
135 regulator_disable(info->micvdd); 151 regulator_disable(info->micvdd);
152 pm_runtime_mark_last_busy(info->dev);
136 pm_runtime_put_autosuspend(info->dev); 153 pm_runtime_put_autosuspend(info->dev);
137 } 154 }
138} 155}
@@ -141,8 +158,8 @@ static irqreturn_t arizona_micdet(int irq, void *data)
141{ 158{
142 struct arizona_extcon_info *info = data; 159 struct arizona_extcon_info *info = data;
143 struct arizona *arizona = info->arizona; 160 struct arizona *arizona = info->arizona;
144 unsigned int val; 161 unsigned int val, lvl;
145 int ret; 162 int ret, i;
146 163
147 mutex_lock(&info->lock); 164 mutex_lock(&info->lock);
148 165
@@ -219,13 +236,22 @@ static irqreturn_t arizona_micdet(int irq, void *data)
219 236
220 /* 237 /*
221 * If we're still detecting and we detect a short then we've 238 * If we're still detecting and we detect a short then we've
222 * got a headphone. Otherwise it's a button press, the 239 * got a headphone. Otherwise it's a button press.
223 * button reporting is stubbed out for now.
224 */ 240 */
225 if (val & 0x3fc) { 241 if (val & 0x3fc) {
226 if (info->mic) { 242 if (info->mic) {
227 dev_dbg(arizona->dev, "Mic button detected\n"); 243 dev_dbg(arizona->dev, "Mic button detected\n");
228 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
229 } else if (info->detecting) { 255 } else if (info->detecting) {
230 dev_dbg(arizona->dev, "Headphone detected\n"); 256 dev_dbg(arizona->dev, "Headphone detected\n");
231 info->detecting = false; 257 info->detecting = false;
@@ -244,6 +270,10 @@ static irqreturn_t arizona_micdet(int irq, void *data)
244 } 270 }
245 } else { 271 } else {
246 dev_dbg(arizona->dev, "Mic button released\n"); 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);
247 } 277 }
248 278
249handled: 279handled:
@@ -258,7 +288,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
258 struct arizona_extcon_info *info = data; 288 struct arizona_extcon_info *info = data;
259 struct arizona *arizona = info->arizona; 289 struct arizona *arizona = info->arizona;
260 unsigned int val; 290 unsigned int val;
261 int ret; 291 int ret, i;
262 292
263 pm_runtime_get_sync(info->dev); 293 pm_runtime_get_sync(info->dev);
264 294
@@ -288,6 +318,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
288 318
289 arizona_stop_mic(info); 319 arizona_stop_mic(info);
290 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
291 ret = extcon_update_state(&info->edev, 0xffffffff, 0); 326 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
292 if (ret != 0) 327 if (ret != 0)
293 dev_err(arizona->dev, "Removal report failed: %d\n", 328 dev_err(arizona->dev, "Removal report failed: %d\n",
@@ -307,7 +342,7 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
307 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); 342 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
308 struct arizona_pdata *pdata; 343 struct arizona_pdata *pdata;
309 struct arizona_extcon_info *info; 344 struct arizona_extcon_info *info;
310 int ret, mode; 345 int ret, mode, i;
311 346
312 pdata = dev_get_platdata(arizona->dev); 347 pdata = dev_get_platdata(arizona->dev);
313 348
@@ -382,6 +417,20 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
382 417
383 arizona_extcon_set_mode(info, 0); 418 arizona_extcon_set_mode(info, 0);
384 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
385 pm_runtime_enable(&pdev->dev); 434 pm_runtime_enable(&pdev->dev);
386 pm_runtime_idle(&pdev->dev); 435 pm_runtime_idle(&pdev->dev);
387 pm_runtime_get_sync(&pdev->dev); 436 pm_runtime_get_sync(&pdev->dev);
@@ -391,7 +440,7 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
391 if (ret != 0) { 440 if (ret != 0) {
392 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n", 441 dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
393 ret); 442 ret);
394 goto err_register; 443 goto err_input;
395 } 444 }
396 445
397 ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 1); 446 ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 1);
@@ -436,6 +485,12 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
436 485
437 pm_runtime_put(&pdev->dev); 486 pm_runtime_put(&pdev->dev);
438 487
488 ret = input_register_device(info->input);
489 if (ret) {
490 dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
491 goto err_fall_wake;
492 }
493
439 return 0; 494 return 0;
440 495
441err_fall_wake: 496err_fall_wake:
@@ -446,6 +501,8 @@ err_rise_wake:
446 arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0); 501 arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0);
447err_rise: 502err_rise:
448 arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info); 503 arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info);
504err_input:
505 input_free_device(info->input);
449err_register: 506err_register:
450 pm_runtime_disable(&pdev->dev); 507 pm_runtime_disable(&pdev->dev);
451 extcon_dev_unregister(&info->edev); 508 extcon_dev_unregister(&info->edev);
@@ -468,6 +525,7 @@ static int __devexit arizona_extcon_remove(struct platform_device *pdev)
468 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, 525 regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
469 ARIZONA_JD1_ENA, 0); 526 ARIZONA_JD1_ENA, 0);
470 arizona_clk32k_disable(arizona); 527 arizona_clk32k_disable(arizona);
528 input_unregister_device(info->input);
471 extcon_dev_unregister(&info->edev); 529 extcon_dev_unregister(&info->edev);
472 530
473 return 0; 531 return 0;