diff options
author | Amitkumar Karwar <akarwar@marvell.com> | 2012-04-25 14:43:54 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo@padovan.org> | 2012-05-09 00:40:51 -0400 |
commit | ba54a16ffacfc7121b6a799de1d08254cb0254b9 (patch) | |
tree | 3919a7c8fc86315d3aebacf1787e68d8c0355de2 | |
parent | 6ff9b5ef5e4e3f474689737640d0c01a96d0696d (diff) |
Bluetooth: btmrvl: add support for SDIO suspend/resume callbacks
Host sleep is activated using already configured host sleep
parameters in suspend handler and it is cancelled in resume
handler.
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo Padovan <gustavo@padovan.org>
-rw-r--r-- | drivers/bluetooth/btmrvl_drv.h | 2 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_main.c | 3 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_sdio.c | 100 |
3 files changed, 104 insertions, 1 deletions
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 2c79e76b1ba6..94f2d65131c4 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h | |||
@@ -67,6 +67,7 @@ struct btmrvl_adapter { | |||
67 | u8 wakeup_tries; | 67 | u8 wakeup_tries; |
68 | wait_queue_head_t cmd_wait_q; | 68 | wait_queue_head_t cmd_wait_q; |
69 | u8 cmd_complete; | 69 | u8 cmd_complete; |
70 | bool is_suspended; | ||
70 | }; | 71 | }; |
71 | 72 | ||
72 | struct btmrvl_private { | 73 | struct btmrvl_private { |
@@ -142,6 +143,7 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd); | |||
142 | int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv); | 143 | int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv); |
143 | int btmrvl_enable_ps(struct btmrvl_private *priv); | 144 | int btmrvl_enable_ps(struct btmrvl_private *priv); |
144 | int btmrvl_prepare_command(struct btmrvl_private *priv); | 145 | int btmrvl_prepare_command(struct btmrvl_private *priv); |
146 | int btmrvl_enable_hs(struct btmrvl_private *priv); | ||
145 | 147 | ||
146 | #ifdef CONFIG_DEBUG_FS | 148 | #ifdef CONFIG_DEBUG_FS |
147 | void btmrvl_debugfs_init(struct hci_dev *hdev); | 149 | void btmrvl_debugfs_init(struct hci_dev *hdev); |
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index a880537ff8c5..681ca9d18e12 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c | |||
@@ -262,7 +262,7 @@ int btmrvl_enable_ps(struct btmrvl_private *priv) | |||
262 | } | 262 | } |
263 | EXPORT_SYMBOL_GPL(btmrvl_enable_ps); | 263 | EXPORT_SYMBOL_GPL(btmrvl_enable_ps); |
264 | 264 | ||
265 | static int btmrvl_enable_hs(struct btmrvl_private *priv) | 265 | int btmrvl_enable_hs(struct btmrvl_private *priv) |
266 | { | 266 | { |
267 | struct sk_buff *skb; | 267 | struct sk_buff *skb; |
268 | struct btmrvl_cmd *cmd; | 268 | struct btmrvl_cmd *cmd; |
@@ -298,6 +298,7 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) | |||
298 | 298 | ||
299 | return ret; | 299 | return ret; |
300 | } | 300 | } |
301 | EXPORT_SYMBOL_GPL(btmrvl_enable_hs); | ||
301 | 302 | ||
302 | int btmrvl_prepare_command(struct btmrvl_private *priv) | 303 | int btmrvl_prepare_command(struct btmrvl_private *priv) |
303 | { | 304 | { |
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index d7d8f83d1c02..a853244e7fd7 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c | |||
@@ -1046,11 +1046,111 @@ static void btmrvl_sdio_remove(struct sdio_func *func) | |||
1046 | } | 1046 | } |
1047 | } | 1047 | } |
1048 | 1048 | ||
1049 | static int btmrvl_sdio_suspend(struct device *dev) | ||
1050 | { | ||
1051 | struct sdio_func *func = dev_to_sdio_func(dev); | ||
1052 | struct btmrvl_sdio_card *card; | ||
1053 | struct btmrvl_private *priv; | ||
1054 | mmc_pm_flag_t pm_flags; | ||
1055 | struct hci_dev *hcidev; | ||
1056 | |||
1057 | if (func) { | ||
1058 | pm_flags = sdio_get_host_pm_caps(func); | ||
1059 | BT_DBG("%s: suspend: PM flags = 0x%x", sdio_func_id(func), | ||
1060 | pm_flags); | ||
1061 | if (!(pm_flags & MMC_PM_KEEP_POWER)) { | ||
1062 | BT_ERR("%s: cannot remain alive while suspended", | ||
1063 | sdio_func_id(func)); | ||
1064 | return -ENOSYS; | ||
1065 | } | ||
1066 | card = sdio_get_drvdata(func); | ||
1067 | if (!card || !card->priv) { | ||
1068 | BT_ERR("card or priv structure is not valid"); | ||
1069 | return 0; | ||
1070 | } | ||
1071 | } else { | ||
1072 | BT_ERR("sdio_func is not specified"); | ||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | priv = card->priv; | ||
1077 | |||
1078 | if (priv->adapter->hs_state != HS_ACTIVATED) { | ||
1079 | if (btmrvl_enable_hs(priv)) { | ||
1080 | BT_ERR("HS not actived, suspend failed!"); | ||
1081 | return -EBUSY; | ||
1082 | } | ||
1083 | } | ||
1084 | hcidev = priv->btmrvl_dev.hcidev; | ||
1085 | BT_DBG("%s: SDIO suspend", hcidev->name); | ||
1086 | hci_suspend_dev(hcidev); | ||
1087 | skb_queue_purge(&priv->adapter->tx_queue); | ||
1088 | |||
1089 | priv->adapter->is_suspended = true; | ||
1090 | |||
1091 | /* We will keep the power when hs enabled successfully */ | ||
1092 | if (priv->adapter->hs_state == HS_ACTIVATED) { | ||
1093 | BT_DBG("suspend with MMC_PM_KEEP_POWER"); | ||
1094 | return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); | ||
1095 | } else { | ||
1096 | BT_DBG("suspend without MMC_PM_KEEP_POWER"); | ||
1097 | return 0; | ||
1098 | } | ||
1099 | } | ||
1100 | |||
1101 | static int btmrvl_sdio_resume(struct device *dev) | ||
1102 | { | ||
1103 | struct sdio_func *func = dev_to_sdio_func(dev); | ||
1104 | struct btmrvl_sdio_card *card; | ||
1105 | struct btmrvl_private *priv; | ||
1106 | mmc_pm_flag_t pm_flags; | ||
1107 | struct hci_dev *hcidev; | ||
1108 | |||
1109 | if (func) { | ||
1110 | pm_flags = sdio_get_host_pm_caps(func); | ||
1111 | BT_DBG("%s: resume: PM flags = 0x%x", sdio_func_id(func), | ||
1112 | pm_flags); | ||
1113 | card = sdio_get_drvdata(func); | ||
1114 | if (!card || !card->priv) { | ||
1115 | BT_ERR("card or priv structure is not valid"); | ||
1116 | return 0; | ||
1117 | } | ||
1118 | } else { | ||
1119 | BT_ERR("sdio_func is not specified"); | ||
1120 | return 0; | ||
1121 | } | ||
1122 | priv = card->priv; | ||
1123 | |||
1124 | if (!priv->adapter->is_suspended) { | ||
1125 | BT_DBG("device already resumed"); | ||
1126 | return 0; | ||
1127 | } | ||
1128 | |||
1129 | priv->adapter->is_suspended = false; | ||
1130 | hcidev = priv->btmrvl_dev.hcidev; | ||
1131 | BT_DBG("%s: SDIO resume", hcidev->name); | ||
1132 | hci_resume_dev(hcidev); | ||
1133 | priv->hw_wakeup_firmware(priv); | ||
1134 | priv->adapter->hs_state = HS_DEACTIVATED; | ||
1135 | BT_DBG("%s: HS DEACTIVATED in resume!", hcidev->name); | ||
1136 | |||
1137 | return 0; | ||
1138 | } | ||
1139 | |||
1140 | static const struct dev_pm_ops btmrvl_sdio_pm_ops = { | ||
1141 | .suspend = btmrvl_sdio_suspend, | ||
1142 | .resume = btmrvl_sdio_resume, | ||
1143 | }; | ||
1144 | |||
1049 | static struct sdio_driver bt_mrvl_sdio = { | 1145 | static struct sdio_driver bt_mrvl_sdio = { |
1050 | .name = "btmrvl_sdio", | 1146 | .name = "btmrvl_sdio", |
1051 | .id_table = btmrvl_sdio_ids, | 1147 | .id_table = btmrvl_sdio_ids, |
1052 | .probe = btmrvl_sdio_probe, | 1148 | .probe = btmrvl_sdio_probe, |
1053 | .remove = btmrvl_sdio_remove, | 1149 | .remove = btmrvl_sdio_remove, |
1150 | .drv = { | ||
1151 | .owner = THIS_MODULE, | ||
1152 | .pm = &btmrvl_sdio_pm_ops, | ||
1153 | } | ||
1054 | }; | 1154 | }; |
1055 | 1155 | ||
1056 | static int __init btmrvl_sdio_init_module(void) | 1156 | static int __init btmrvl_sdio_init_module(void) |