@@ -197,18 +197,35 @@ static bool bcm_device_exists(struct bcm_device *device)
197
197
198
198
static int bcm_gpio_set_power (struct bcm_device * dev , bool powered )
199
199
{
200
- if (powered && !IS_ERR (dev -> clk ) && !dev -> clk_enabled )
201
- clk_prepare_enable (dev -> clk );
200
+ int err ;
202
201
203
- dev -> set_shutdown (dev , powered );
204
- dev -> set_device_wakeup (dev , powered );
202
+ if (powered && !IS_ERR (dev -> clk ) && !dev -> clk_enabled ) {
203
+ err = clk_prepare_enable (dev -> clk );
204
+ if (err )
205
+ return err ;
206
+ }
207
+
208
+ err = dev -> set_shutdown (dev , powered );
209
+ if (err )
210
+ goto err_clk_disable ;
211
+
212
+ err = dev -> set_device_wakeup (dev , powered );
213
+ if (err )
214
+ goto err_revert_shutdown ;
205
215
206
216
if (!powered && !IS_ERR (dev -> clk ) && dev -> clk_enabled )
207
217
clk_disable_unprepare (dev -> clk );
208
218
209
219
dev -> clk_enabled = powered ;
210
220
211
221
return 0 ;
222
+
223
+ err_revert_shutdown :
224
+ dev -> set_shutdown (dev , !powered );
225
+ err_clk_disable :
226
+ if (powered && !IS_ERR (dev -> clk ) && !dev -> clk_enabled )
227
+ clk_disable_unprepare (dev -> clk );
228
+ return err ;
212
229
}
213
230
214
231
#ifdef CONFIG_PM
@@ -331,6 +348,7 @@ static int bcm_open(struct hci_uart *hu)
331
348
{
332
349
struct bcm_data * bcm ;
333
350
struct list_head * p ;
351
+ int err ;
334
352
335
353
bt_dev_dbg (hu -> hdev , "hu %p" , hu );
336
354
@@ -345,7 +363,10 @@ static int bcm_open(struct hci_uart *hu)
345
363
mutex_lock (& bcm_device_lock );
346
364
347
365
if (hu -> serdev ) {
348
- serdev_device_open (hu -> serdev );
366
+ err = serdev_device_open (hu -> serdev );
367
+ if (err )
368
+ goto err_free ;
369
+
349
370
bcm -> dev = serdev_device_get_drvdata (hu -> serdev );
350
371
goto out ;
351
372
}
@@ -373,17 +394,30 @@ static int bcm_open(struct hci_uart *hu)
373
394
if (bcm -> dev ) {
374
395
hu -> init_speed = bcm -> dev -> init_speed ;
375
396
hu -> oper_speed = bcm -> dev -> oper_speed ;
376
- bcm_gpio_set_power (bcm -> dev , true);
397
+ err = bcm_gpio_set_power (bcm -> dev , true);
398
+ if (err )
399
+ goto err_unset_hu ;
377
400
}
378
401
379
402
mutex_unlock (& bcm_device_lock );
380
403
return 0 ;
404
+
405
+ err_unset_hu :
406
+ #ifdef CONFIG_PM
407
+ bcm -> dev -> hu = NULL ;
408
+ #endif
409
+ err_free :
410
+ mutex_unlock (& bcm_device_lock );
411
+ hu -> priv = NULL ;
412
+ kfree (bcm );
413
+ return err ;
381
414
}
382
415
383
416
static int bcm_close (struct hci_uart * hu )
384
417
{
385
418
struct bcm_data * bcm = hu -> priv ;
386
419
struct bcm_device * bdev = NULL ;
420
+ int err ;
387
421
388
422
bt_dev_dbg (hu -> hdev , "hu %p" , hu );
389
423
@@ -407,8 +441,11 @@ static int bcm_close(struct hci_uart *hu)
407
441
pm_runtime_disable (bdev -> dev );
408
442
}
409
443
410
- bcm_gpio_set_power (bdev , false);
411
- pm_runtime_set_suspended (bdev -> dev );
444
+ err = bcm_gpio_set_power (bdev , false);
445
+ if (err )
446
+ bt_dev_err (hu -> hdev , "Failed to power down" );
447
+ else
448
+ pm_runtime_set_suspended (bdev -> dev );
412
449
}
413
450
mutex_unlock (& bcm_device_lock );
414
451
@@ -588,6 +625,7 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
588
625
static int bcm_suspend_device (struct device * dev )
589
626
{
590
627
struct bcm_device * bdev = dev_get_drvdata (dev );
628
+ int err ;
591
629
592
630
bt_dev_dbg (bdev , "" );
593
631
@@ -599,7 +637,15 @@ static int bcm_suspend_device(struct device *dev)
599
637
}
600
638
601
639
/* Suspend the device */
602
- bdev -> set_device_wakeup (bdev , false);
640
+ err = bdev -> set_device_wakeup (bdev , false);
641
+ if (err ) {
642
+ if (bdev -> is_suspended && bdev -> hu ) {
643
+ bdev -> is_suspended = false;
644
+ hci_uart_set_flow_control (bdev -> hu , false);
645
+ }
646
+ return - EBUSY ;
647
+ }
648
+
603
649
bt_dev_dbg (bdev , "suspend, delaying 15 ms" );
604
650
mdelay (15 );
605
651
@@ -609,10 +655,16 @@ static int bcm_suspend_device(struct device *dev)
609
655
static int bcm_resume_device (struct device * dev )
610
656
{
611
657
struct bcm_device * bdev = dev_get_drvdata (dev );
658
+ int err ;
612
659
613
660
bt_dev_dbg (bdev , "" );
614
661
615
- bdev -> set_device_wakeup (bdev , true);
662
+ err = bdev -> set_device_wakeup (bdev , true);
663
+ if (err ) {
664
+ dev_err (dev , "Failed to power up\n" );
665
+ return err ;
666
+ }
667
+
616
668
bt_dev_dbg (bdev , "resume, delaying 15 ms" );
617
669
mdelay (15 );
618
670
@@ -666,6 +718,7 @@ static int bcm_suspend(struct device *dev)
666
718
static int bcm_resume (struct device * dev )
667
719
{
668
720
struct bcm_device * bdev = dev_get_drvdata (dev );
721
+ int err = 0 ;
669
722
670
723
bt_dev_dbg (bdev , "resume: is_suspended %d" , bdev -> is_suspended );
671
724
@@ -685,14 +738,16 @@ static int bcm_resume(struct device *dev)
685
738
bt_dev_dbg (bdev , "BCM irq: disabled" );
686
739
}
687
740
688
- bcm_resume_device (dev );
741
+ err = bcm_resume_device (dev );
689
742
690
743
unlock :
691
744
mutex_unlock (& bcm_device_lock );
692
745
693
- pm_runtime_disable (dev );
694
- pm_runtime_set_active (dev );
695
- pm_runtime_enable (dev );
746
+ if (!err ) {
747
+ pm_runtime_disable (dev );
748
+ pm_runtime_set_active (dev );
749
+ pm_runtime_enable (dev );
750
+ }
696
751
697
752
return 0 ;
698
753
}
@@ -923,7 +978,9 @@ static int bcm_probe(struct platform_device *pdev)
923
978
list_add_tail (& dev -> list , & bcm_device_list );
924
979
mutex_unlock (& bcm_device_lock );
925
980
926
- bcm_gpio_set_power (dev , false);
981
+ ret = bcm_gpio_set_power (dev , false);
982
+ if (ret )
983
+ dev_err (& pdev -> dev , "Failed to power down\n" );
927
984
928
985
return 0 ;
929
986
}
@@ -1025,7 +1082,9 @@ static int bcm_serdev_probe(struct serdev_device *serdev)
1025
1082
if (err )
1026
1083
return err ;
1027
1084
1028
- bcm_gpio_set_power (bcmdev , false);
1085
+ err = bcm_gpio_set_power (bcmdev , false);
1086
+ if (err )
1087
+ dev_err (& serdev -> dev , "Failed to power down\n" );
1029
1088
1030
1089
return hci_uart_register_device (& bcmdev -> serdev_hu , & bcm_proto );
1031
1090
}
0 commit comments