diff options
author | Frederic Danis <frederic.danis@linux.intel.com> | 2015-09-23 12:18:09 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-09-24 10:25:44 -0400 |
commit | b7a622a249736b36c0bf4c3f986ed431281d5e98 (patch) | |
tree | b53ecfd0bb4942abc7ecfaddb338390acb38f1e2 /drivers/bluetooth | |
parent | 5cebdfea32b89911d4540440c1c2854a1a3d591e (diff) |
Bluetooth: hci_bcm: Prepare PM runtime support
Change some CONFIG_PM_SLEEP to CONFIG_PM as hu and is_suspended parameters
will be used during PM runtime callbacks.
Add bcm_suspend_device() and bcm_resume_device() which performs link
management for PM callbacks.
These functions will be used for runtime management.
Signed-off-by: Frederic Danis <frederic.danis@linux.intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/hci_bcm.c | 88 |
1 files changed, 60 insertions, 28 deletions
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 2cb50898d667..fc5ca950d37a 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c | |||
@@ -56,7 +56,7 @@ struct bcm_device { | |||
56 | int irq; | 56 | int irq; |
57 | u8 irq_polarity; | 57 | u8 irq_polarity; |
58 | 58 | ||
59 | #ifdef CONFIG_PM_SLEEP | 59 | #ifdef CONFIG_PM |
60 | struct hci_uart *hu; | 60 | struct hci_uart *hu; |
61 | bool is_suspended; /* suspend/resume flag */ | 61 | bool is_suspended; /* suspend/resume flag */ |
62 | #endif | 62 | #endif |
@@ -153,7 +153,7 @@ static int bcm_gpio_set_power(struct bcm_device *dev, bool powered) | |||
153 | return 0; | 153 | return 0; |
154 | } | 154 | } |
155 | 155 | ||
156 | #ifdef CONFIG_PM_SLEEP | 156 | #ifdef CONFIG_PM |
157 | static irqreturn_t bcm_host_wake(int irq, void *data) | 157 | static irqreturn_t bcm_host_wake(int irq, void *data) |
158 | { | 158 | { |
159 | struct bcm_device *bdev = data; | 159 | struct bcm_device *bdev = data; |
@@ -259,7 +259,7 @@ static int bcm_open(struct hci_uart *hu) | |||
259 | if (hu->tty->dev->parent == dev->pdev->dev.parent) { | 259 | if (hu->tty->dev->parent == dev->pdev->dev.parent) { |
260 | bcm->dev = dev; | 260 | bcm->dev = dev; |
261 | hu->init_speed = dev->init_speed; | 261 | hu->init_speed = dev->init_speed; |
262 | #ifdef CONFIG_PM_SLEEP | 262 | #ifdef CONFIG_PM |
263 | dev->hu = hu; | 263 | dev->hu = hu; |
264 | #endif | 264 | #endif |
265 | bcm_gpio_set_power(bcm->dev, true); | 265 | bcm_gpio_set_power(bcm->dev, true); |
@@ -283,7 +283,7 @@ static int bcm_close(struct hci_uart *hu) | |||
283 | mutex_lock(&bcm_device_lock); | 283 | mutex_lock(&bcm_device_lock); |
284 | if (bcm_device_exists(bdev)) { | 284 | if (bcm_device_exists(bdev)) { |
285 | bcm_gpio_set_power(bdev, false); | 285 | bcm_gpio_set_power(bdev, false); |
286 | #ifdef CONFIG_PM_SLEEP | 286 | #ifdef CONFIG_PM |
287 | if (device_can_wakeup(&bdev->pdev->dev)) { | 287 | if (device_can_wakeup(&bdev->pdev->dev)) { |
288 | devm_free_irq(&bdev->pdev->dev, bdev->irq, bdev); | 288 | devm_free_irq(&bdev->pdev->dev, bdev->irq, bdev); |
289 | device_init_wakeup(&bdev->pdev->dev, false); | 289 | device_init_wakeup(&bdev->pdev->dev, false); |
@@ -425,24 +425,17 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu) | |||
425 | return skb_dequeue(&bcm->txq); | 425 | return skb_dequeue(&bcm->txq); |
426 | } | 426 | } |
427 | 427 | ||
428 | #ifdef CONFIG_PM_SLEEP | 428 | #ifdef CONFIG_PM |
429 | /* Platform suspend callback */ | 429 | static int bcm_suspend_device(struct device *dev) |
430 | static int bcm_suspend(struct device *dev) | ||
431 | { | 430 | { |
432 | struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev)); | 431 | struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev)); |
433 | int error; | ||
434 | 432 | ||
435 | bt_dev_dbg(bdev, "suspend: is_suspended %d", bdev->is_suspended); | 433 | bt_dev_dbg(bdev, ""); |
436 | |||
437 | mutex_lock(&bcm_device_lock); | ||
438 | |||
439 | if (!bdev->hu) | ||
440 | goto unlock; | ||
441 | 434 | ||
442 | if (!bdev->is_suspended) { | 435 | if (!bdev->is_suspended && bdev->hu) { |
443 | hci_uart_set_flow_control(bdev->hu, true); | 436 | hci_uart_set_flow_control(bdev->hu, true); |
444 | 437 | ||
445 | /* Once this callback returns, driver suspends BT via GPIO */ | 438 | /* Once this returns, driver suspends BT via GPIO */ |
446 | bdev->is_suspended = true; | 439 | bdev->is_suspended = true; |
447 | } | 440 | } |
448 | 441 | ||
@@ -453,6 +446,52 @@ static int bcm_suspend(struct device *dev) | |||
453 | mdelay(15); | 446 | mdelay(15); |
454 | } | 447 | } |
455 | 448 | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int bcm_resume_device(struct device *dev) | ||
453 | { | ||
454 | struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev)); | ||
455 | |||
456 | bt_dev_dbg(bdev, ""); | ||
457 | |||
458 | if (bdev->device_wakeup) { | ||
459 | gpiod_set_value(bdev->device_wakeup, true); | ||
460 | bt_dev_dbg(bdev, "resume, delaying 15 ms"); | ||
461 | mdelay(15); | ||
462 | } | ||
463 | |||
464 | /* When this executes, the device has woken up already */ | ||
465 | if (bdev->is_suspended && bdev->hu) { | ||
466 | bdev->is_suspended = false; | ||
467 | |||
468 | hci_uart_set_flow_control(bdev->hu, false); | ||
469 | } | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | #endif | ||
474 | |||
475 | #ifdef CONFIG_PM_SLEEP | ||
476 | /* Platform suspend callback */ | ||
477 | static int bcm_suspend(struct device *dev) | ||
478 | { | ||
479 | struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev)); | ||
480 | int error; | ||
481 | |||
482 | bt_dev_dbg(bdev, "suspend: is_suspended %d", bdev->is_suspended); | ||
483 | |||
484 | /* bcm_suspend can be called at any time as long as platform device is | ||
485 | * bound, so it should use bcm_device_lock to protect access to hci_uart | ||
486 | * and device_wake-up GPIO. | ||
487 | */ | ||
488 | mutex_lock(&bcm_device_lock); | ||
489 | |||
490 | if (!bdev->hu) | ||
491 | goto unlock; | ||
492 | |||
493 | bcm_suspend_device(dev); | ||
494 | |||
456 | if (device_may_wakeup(&bdev->pdev->dev)) { | 495 | if (device_may_wakeup(&bdev->pdev->dev)) { |
457 | error = enable_irq_wake(bdev->irq); | 496 | error = enable_irq_wake(bdev->irq); |
458 | if (!error) | 497 | if (!error) |
@@ -472,6 +511,10 @@ static int bcm_resume(struct device *dev) | |||
472 | 511 | ||
473 | bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended); | 512 | bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended); |
474 | 513 | ||
514 | /* bcm_resume can be called at any time as long as platform device is | ||
515 | * bound, so it should use bcm_device_lock to protect access to hci_uart | ||
516 | * and device_wake-up GPIO. | ||
517 | */ | ||
475 | mutex_lock(&bcm_device_lock); | 518 | mutex_lock(&bcm_device_lock); |
476 | 519 | ||
477 | if (!bdev->hu) | 520 | if (!bdev->hu) |
@@ -482,18 +525,7 @@ static int bcm_resume(struct device *dev) | |||
482 | bt_dev_dbg(bdev, "BCM irq: disabled"); | 525 | bt_dev_dbg(bdev, "BCM irq: disabled"); |
483 | } | 526 | } |
484 | 527 | ||
485 | if (bdev->device_wakeup) { | 528 | bcm_resume_device(dev); |
486 | gpiod_set_value(bdev->device_wakeup, true); | ||
487 | bt_dev_dbg(bdev, "resume, delaying 15 ms"); | ||
488 | mdelay(15); | ||
489 | } | ||
490 | |||
491 | /* When this callback executes, the device has woken up already */ | ||
492 | if (bdev->is_suspended) { | ||
493 | bdev->is_suspended = false; | ||
494 | |||
495 | hci_uart_set_flow_control(bdev->hu, false); | ||
496 | } | ||
497 | 529 | ||
498 | unlock: | 530 | unlock: |
499 | mutex_unlock(&bcm_device_lock); | 531 | mutex_unlock(&bcm_device_lock); |