@@ -51,6 +51,11 @@ struct bcm_device {
51
51
bool clk_enabled ;
52
52
53
53
u32 init_speed ;
54
+
55
+ #ifdef CONFIG_PM_SLEEP
56
+ struct hci_uart * hu ;
57
+ bool is_suspended ; /* suspend/resume flag */
58
+ #endif
54
59
};
55
60
56
61
struct bcm_data {
@@ -170,6 +175,9 @@ static int bcm_open(struct hci_uart *hu)
170
175
if (hu -> tty -> dev -> parent == dev -> pdev -> dev .parent ) {
171
176
bcm -> dev = dev ;
172
177
hu -> init_speed = dev -> init_speed ;
178
+ #ifdef CONFIG_PM_SLEEP
179
+ dev -> hu = hu ;
180
+ #endif
173
181
break ;
174
182
}
175
183
}
@@ -190,8 +198,12 @@ static int bcm_close(struct hci_uart *hu)
190
198
191
199
/* Protect bcm->dev against removal of the device or driver */
192
200
spin_lock (& bcm_device_list_lock );
193
- if (bcm_device_exists (bcm -> dev ))
201
+ if (bcm_device_exists (bcm -> dev )) {
194
202
bcm_gpio_set_power (bcm -> dev , false);
203
+ #ifdef CONFIG_PM_SLEEP
204
+ bcm -> dev -> hu = NULL ;
205
+ #endif
206
+ }
195
207
spin_unlock (& bcm_device_list_lock );
196
208
197
209
skb_queue_purge (& bcm -> txq );
@@ -318,6 +330,55 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
318
330
return skb_dequeue (& bcm -> txq );
319
331
}
320
332
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
+
321
382
static const struct acpi_gpio_params device_wakeup_gpios = { 0 , 0 , false };
322
383
static const struct acpi_gpio_params shutdown_gpios = { 1 , 0 , false };
323
384
@@ -474,12 +535,16 @@ static const struct acpi_device_id bcm_acpi_match[] = {
474
535
MODULE_DEVICE_TABLE (acpi , bcm_acpi_match );
475
536
#endif
476
537
538
+ /* Platform suspend and resume callbacks */
539
+ static SIMPLE_DEV_PM_OPS (bcm_pm_ops , bcm_suspend , bcm_resume ) ;
540
+
477
541
static struct platform_driver bcm_driver = {
478
542
.probe = bcm_probe ,
479
543
.remove = bcm_remove ,
480
544
.driver = {
481
545
.name = "hci_bcm" ,
482
546
.acpi_match_table = ACPI_PTR (bcm_acpi_match ),
547
+ .pm = & bcm_pm_ops ,
483
548
},
484
549
};
485
550
0 commit comments