|
@@ -52,6 +52,68 @@ static struct memory_type_mapping mem_type_mapping_tbl[] = {
|
|
|
{"EXTLAST", NULL, 0, 0xFE},
|
|
|
};
|
|
|
|
|
|
+static const struct of_device_id btmrvl_sdio_of_match_table[] = {
|
|
|
+ { .compatible = "marvell,sd8897-bt" },
|
|
|
+ { .compatible = "marvell,sd8997-bt" },
|
|
|
+ { }
|
|
|
+};
|
|
|
+
|
|
|
+static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv)
|
|
|
+{
|
|
|
+ struct btmrvl_plt_wake_cfg *cfg = priv;
|
|
|
+
|
|
|
+ if (cfg->irq_bt >= 0) {
|
|
|
+ pr_info("%s: wake by bt", __func__);
|
|
|
+ cfg->wake_by_bt = true;
|
|
|
+ disable_irq_nosync(irq);
|
|
|
+ }
|
|
|
+
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|
|
|
+/* This function parses device tree node using mmc subnode devicetree API.
|
|
|
+ * The device node is saved in card->plt_of_node.
|
|
|
+ * If the device tree node exists and includes interrupts attributes, this
|
|
|
+ * function will request platform specific wakeup interrupt.
|
|
|
+ */
|
|
|
+static int btmrvl_sdio_probe_of(struct device *dev,
|
|
|
+ struct btmrvl_sdio_card *card)
|
|
|
+{
|
|
|
+ struct btmrvl_plt_wake_cfg *cfg;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (!dev->of_node ||
|
|
|
+ !of_match_node(btmrvl_sdio_of_match_table, dev->of_node)) {
|
|
|
+ pr_err("sdio platform data not available");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ card->plt_of_node = dev->of_node;
|
|
|
+
|
|
|
+ card->plt_wake_cfg = devm_kzalloc(dev, sizeof(*card->plt_wake_cfg),
|
|
|
+ GFP_KERNEL);
|
|
|
+ cfg = card->plt_wake_cfg;
|
|
|
+ if (cfg && card->plt_of_node) {
|
|
|
+ cfg->irq_bt = irq_of_parse_and_map(card->plt_of_node, 0);
|
|
|
+ if (!cfg->irq_bt) {
|
|
|
+ dev_err(dev, "fail to parse irq_bt from device tree");
|
|
|
+ } else {
|
|
|
+ ret = devm_request_irq(dev, cfg->irq_bt,
|
|
|
+ btmrvl_wake_irq_bt,
|
|
|
+ IRQF_TRIGGER_LOW,
|
|
|
+ "bt_wake", cfg);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(dev,
|
|
|
+ "Failed to request irq_bt %d (%d)\n",
|
|
|
+ cfg->irq_bt, ret);
|
|
|
+ }
|
|
|
+ disable_irq(cfg->irq_bt);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* The btmrvl_sdio_remove() callback function is called
|
|
|
* when user removes this module from kernel space or ejects
|
|
|
* the card from the slot. The driver handles these 2 cases
|
|
@@ -1464,6 +1526,9 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
|
|
|
|
|
|
btmrvl_sdio_enable_host_int(card);
|
|
|
|
|
|
+ /* Device tree node parsing and platform specific configuration*/
|
|
|
+ btmrvl_sdio_probe_of(&func->dev, card);
|
|
|
+
|
|
|
priv = btmrvl_add_card(card);
|
|
|
if (!priv) {
|
|
|
BT_ERR("Initializing card failed!");
|
|
@@ -1544,6 +1609,13 @@ static int btmrvl_sdio_suspend(struct device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+ /* Enable platform specific wakeup interrupt */
|
|
|
+ if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0) {
|
|
|
+ card->plt_wake_cfg->wake_by_bt = false;
|
|
|
+ enable_irq(card->plt_wake_cfg->irq_bt);
|
|
|
+ enable_irq_wake(card->plt_wake_cfg->irq_bt);
|
|
|
+ }
|
|
|
+
|
|
|
priv = card->priv;
|
|
|
priv->adapter->is_suspending = true;
|
|
|
hcidev = priv->btmrvl_dev.hcidev;
|
|
@@ -1606,6 +1678,13 @@ static int btmrvl_sdio_resume(struct device *dev)
|
|
|
BT_DBG("%s: SDIO resume", hcidev->name);
|
|
|
hci_resume_dev(hcidev);
|
|
|
|
|
|
+ /* Disable platform specific wakeup interrupt */
|
|
|
+ if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0) {
|
|
|
+ disable_irq_wake(card->plt_wake_cfg->irq_bt);
|
|
|
+ if (!card->plt_wake_cfg->wake_by_bt)
|
|
|
+ disable_irq(card->plt_wake_cfg->irq_bt);
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|