Skip to content

Commit 118612f

Browse files
Frederic Danisholtmann
authored andcommitted
Bluetooth: hci_bcm: Add suspend/resume PM functions
Add reference to hci_uart structure to bcm_device. This allows suspend/resume callbacks to manage UART flow control. Signed-off-by: Frederic Danis <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent ae05690 commit 118612f

File tree

1 file changed

+66
-1
lines changed

1 file changed

+66
-1
lines changed

drivers/bluetooth/hci_bcm.c

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ struct bcm_device {
5151
bool clk_enabled;
5252

5353
u32 init_speed;
54+
55+
#ifdef CONFIG_PM_SLEEP
56+
struct hci_uart *hu;
57+
bool is_suspended; /* suspend/resume flag */
58+
#endif
5459
};
5560

5661
struct bcm_data {
@@ -170,6 +175,9 @@ static int bcm_open(struct hci_uart *hu)
170175
if (hu->tty->dev->parent == dev->pdev->dev.parent) {
171176
bcm->dev = dev;
172177
hu->init_speed = dev->init_speed;
178+
#ifdef CONFIG_PM_SLEEP
179+
dev->hu = hu;
180+
#endif
173181
break;
174182
}
175183
}
@@ -190,8 +198,12 @@ static int bcm_close(struct hci_uart *hu)
190198

191199
/* Protect bcm->dev against removal of the device or driver */
192200
spin_lock(&bcm_device_list_lock);
193-
if (bcm_device_exists(bcm->dev))
201+
if (bcm_device_exists(bcm->dev)) {
194202
bcm_gpio_set_power(bcm->dev, false);
203+
#ifdef CONFIG_PM_SLEEP
204+
bcm->dev->hu = NULL;
205+
#endif
206+
}
195207
spin_unlock(&bcm_device_list_lock);
196208

197209
skb_queue_purge(&bcm->txq);
@@ -318,6 +330,55 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
318330
return skb_dequeue(&bcm->txq);
319331
}
320332

333+
#ifdef CONFIG_PM_SLEEP
334+
/* Platform suspend callback */
335+
static int bcm_suspend(struct device *dev)
336+
{
337+
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
338+
339+
BT_DBG("suspend (%p): is_suspended %d", bdev, bdev->is_suspended);
340+
341+
if (!bdev->is_suspended) {
342+
hci_uart_set_flow_control(bdev->hu, true);
343+
344+
/* Once this callback returns, driver suspends BT via GPIO */
345+
bdev->is_suspended = true;
346+
}
347+
348+
/* Suspend the device */
349+
if (bdev->device_wakeup) {
350+
gpiod_set_value(bdev->device_wakeup, false);
351+
BT_DBG("suspend, delaying 15 ms");
352+
mdelay(15);
353+
}
354+
355+
return 0;
356+
}
357+
358+
/* Platform resume callback */
359+
static int bcm_resume(struct device *dev)
360+
{
361+
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
362+
363+
BT_DBG("resume (%p): is_suspended %d", bdev, bdev->is_suspended);
364+
365+
if (bdev->device_wakeup) {
366+
gpiod_set_value(bdev->device_wakeup, true);
367+
BT_DBG("resume, delaying 15 ms");
368+
mdelay(15);
369+
}
370+
371+
/* When this callback executes, the device has woken up already */
372+
if (bdev->is_suspended) {
373+
bdev->is_suspended = false;
374+
375+
hci_uart_set_flow_control(bdev->hu, false);
376+
}
377+
378+
return 0;
379+
}
380+
#endif
381+
321382
static const struct acpi_gpio_params device_wakeup_gpios = { 0, 0, false };
322383
static const struct acpi_gpio_params shutdown_gpios = { 1, 0, false };
323384

@@ -474,12 +535,16 @@ static const struct acpi_device_id bcm_acpi_match[] = {
474535
MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
475536
#endif
476537

538+
/* Platform suspend and resume callbacks */
539+
static SIMPLE_DEV_PM_OPS(bcm_pm_ops, bcm_suspend, bcm_resume);
540+
477541
static struct platform_driver bcm_driver = {
478542
.probe = bcm_probe,
479543
.remove = bcm_remove,
480544
.driver = {
481545
.name = "hci_bcm",
482546
.acpi_match_table = ACPI_PTR(bcm_acpi_match),
547+
.pm = &bcm_pm_ops,
483548
},
484549
};
485550

0 commit comments

Comments
 (0)