aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2012-04-25 14:43:54 -0400
committerGustavo Padovan <gustavo@padovan.org>2012-05-09 00:40:51 -0400
commitba54a16ffacfc7121b6a799de1d08254cb0254b9 (patch)
tree3919a7c8fc86315d3aebacf1787e68d8c0355de2
parent6ff9b5ef5e4e3f474689737640d0c01a96d0696d (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.h2
-rw-r--r--drivers/bluetooth/btmrvl_main.c3
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c100
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
72struct btmrvl_private { 73struct btmrvl_private {
@@ -142,6 +143,7 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
142int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv); 143int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv);
143int btmrvl_enable_ps(struct btmrvl_private *priv); 144int btmrvl_enable_ps(struct btmrvl_private *priv);
144int btmrvl_prepare_command(struct btmrvl_private *priv); 145int btmrvl_prepare_command(struct btmrvl_private *priv);
146int btmrvl_enable_hs(struct btmrvl_private *priv);
145 147
146#ifdef CONFIG_DEBUG_FS 148#ifdef CONFIG_DEBUG_FS
147void btmrvl_debugfs_init(struct hci_dev *hdev); 149void 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}
263EXPORT_SYMBOL_GPL(btmrvl_enable_ps); 263EXPORT_SYMBOL_GPL(btmrvl_enable_ps);
264 264
265static int btmrvl_enable_hs(struct btmrvl_private *priv) 265int 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}
301EXPORT_SYMBOL_GPL(btmrvl_enable_hs);
301 302
302int btmrvl_prepare_command(struct btmrvl_private *priv) 303int 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
1049static 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
1101static 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
1140static const struct dev_pm_ops btmrvl_sdio_pm_ops = {
1141 .suspend = btmrvl_sdio_suspend,
1142 .resume = btmrvl_sdio_resume,
1143};
1144
1049static struct sdio_driver bt_mrvl_sdio = { 1145static 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
1056static int __init btmrvl_sdio_init_module(void) 1156static int __init btmrvl_sdio_init_module(void)