diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 15:10:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 15:10:44 -0400 |
commit | 06d2fe153b9b35e57221e35831a26918f462db68 (patch) | |
tree | f77cb72dfba7f2a47ceb93e120abd9399a24a1b9 /drivers/extcon/extcon-arizona.c | |
parent | 3aebd34b1200a902a8662da8845824a02f00772e (diff) | |
parent | e0f21e6d52cc245e7d4f7e02ca4b7b6571660ec2 (diff) |
Merge tag 'driver-core-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core merge from Greg Kroah-Hartman:
"Here is the big driver core update for 3.7-rc1.
A number of firmware_class.c updates (as you saw a month or so ago),
and some hyper-v updates and some printk fixes as well. All patches
that are outside of the drivers/base area have been acked by the
respective maintainers, and have all been in the linux-next tree for a
while.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"
* tag 'driver-core-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (95 commits)
memory: tegra{20,30}-mc: Fix reading incorrect register in mc_readl()
device.h: Add missing inline to #ifndef CONFIG_PRINTK dev_vprintk_emit
memory: emif: Add ifdef CONFIG_DEBUG_FS guard for emif_debugfs_[init|exit]
Documentation: Fixes some translation error in Documentation/zh_CN/gpio.txt
Documentation: Remove 3 byte redundant code at the head of the Documentation/zh_CN/arm/booting
Documentation: Chinese translation of Documentation/video4linux/omap3isp.txt
device and dynamic_debug: Use dev_vprintk_emit and dev_printk_emit
dev: Add dev_vprintk_emit and dev_printk_emit
netdev_printk/netif_printk: Remove a superfluous logging colon
netdev_printk/dynamic_netdev_dbg: Directly call printk_emit
dev_dbg/dynamic_debug: Update to use printk_emit, optimize stack
driver-core: Shut up dev_dbg_reatelimited() without DEBUG
tools/hv: Parse /etc/os-release
tools/hv: Check for read/write errors
tools/hv: Fix exit() error code
tools/hv: Fix file handle leak
Tools: hv: Implement the KVP verb - KVP_OP_GET_IP_INFO
Tools: hv: Rename the function kvp_get_ip_address()
Tools: hv: Implement the KVP verb - KVP_OP_SET_IP_INFO
Tools: hv: Add an example script to configure an interface
...
Diffstat (limited to 'drivers/extcon/extcon-arizona.c')
-rw-r--r-- | drivers/extcon/extcon-arizona.c | 78 |
1 files changed, 69 insertions, 9 deletions
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 6c19833ed2d..cdab9e59829 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 | |||
33 | struct arizona_extcon_info { | 36 | struct 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 | ||
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 | |||
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 | ||
249 | handled: | 279 | handled: |
@@ -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,13 +342,13 @@ 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 | ||
314 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); | 349 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); |
315 | if (!info) { | 350 | if (!info) { |
316 | dev_err(&pdev->dev, "failed to allocate memory\n"); | 351 | dev_err(&pdev->dev, "Failed to allocate memory\n"); |
317 | ret = -ENOMEM; | 352 | ret = -ENOMEM; |
318 | goto err; | 353 | goto err; |
319 | } | 354 | } |
@@ -350,7 +385,7 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev) | |||
350 | 385 | ||
351 | ret = extcon_dev_register(&info->edev, arizona->dev); | 386 | ret = extcon_dev_register(&info->edev, arizona->dev); |
352 | if (ret < 0) { | 387 | if (ret < 0) { |
353 | dev_err(arizona->dev, "extcon_dev_regster() failed: %d\n", | 388 | dev_err(arizona->dev, "extcon_dev_register() failed: %d\n", |
354 | ret); | 389 | ret); |
355 | goto err; | 390 | goto err; |
356 | } | 391 | } |
@@ -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); |
@@ -441,8 +490,16 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev) | |||
441 | 490 | ||
442 | pm_runtime_put(&pdev->dev); | 491 | pm_runtime_put(&pdev->dev); |
443 | 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 | |||
444 | return 0; | 499 | return 0; |
445 | 500 | ||
501 | err_micdet: | ||
502 | arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info); | ||
446 | err_fall_wake: | 503 | err_fall_wake: |
447 | arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 0); | 504 | arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 0); |
448 | err_fall: | 505 | err_fall: |
@@ -451,6 +508,8 @@ err_rise_wake: | |||
451 | arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0); | 508 | arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0); |
452 | err_rise: | 509 | err_rise: |
453 | arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info); | 510 | arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info); |
511 | err_input: | ||
512 | input_free_device(info->input); | ||
454 | err_register: | 513 | err_register: |
455 | pm_runtime_disable(&pdev->dev); | 514 | pm_runtime_disable(&pdev->dev); |
456 | extcon_dev_unregister(&info->edev); | 515 | extcon_dev_unregister(&info->edev); |
@@ -473,6 +532,7 @@ static int __devexit arizona_extcon_remove(struct platform_device *pdev) | |||
473 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, | 532 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, |
474 | ARIZONA_JD1_ENA, 0); | 533 | ARIZONA_JD1_ENA, 0); |
475 | arizona_clk32k_disable(arizona); | 534 | arizona_clk32k_disable(arizona); |
535 | input_unregister_device(info->input); | ||
476 | extcon_dev_unregister(&info->edev); | 536 | extcon_dev_unregister(&info->edev); |
477 | 537 | ||
478 | return 0; | 538 | return 0; |