aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXinming Hu <huxm@marvell.com>2016-04-26 09:57:27 -0400
committerMarcel Holtmann <marcel@holtmann.org>2016-05-02 13:26:15 -0400
commitbb7f4f0bcee6844632d7366d6abff4b9996ad454 (patch)
tree7a3bf4a02c6b4a2a4ef6e79f940c7edf1ffdf15e
parent0065d1c5acdb60ee2c0e54585a29243718465bb7 (diff)
btmrvl: add platform specific wakeup interrupt support
On some arm-based platforms, we need to configure platform specific parameters by device tree node and also define our node as a child node of parent SDIO host controller. This patch parses these parameters from device tree. It includes calibration data download to firmware, wakeup pin configured to firmware, and soc specific wake up gpio, which will be set as wakeup interrupt pin. Signed-off-by: Xinming Hu <huxm@marvell.com> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--drivers/bluetooth/btmrvl_drv.h11
-rw-r--r--drivers/bluetooth/btmrvl_main.c35
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c79
-rw-r--r--drivers/bluetooth/btmrvl_sdio.h6
4 files changed, 116 insertions, 15 deletions
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index 05904732e6f1..f742384b53f7 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -23,6 +23,17 @@
23#include <linux/bitops.h> 23#include <linux/bitops.h>
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <net/bluetooth/bluetooth.h> 25#include <net/bluetooth/bluetooth.h>
26#include <linux/err.h>
27#include <linux/gpio.h>
28#include <linux/gfp.h>
29#include <linux/interrupt.h>
30#include <linux/io.h>
31#include <linux/of_gpio.h>
32#include <linux/of_platform.h>
33#include <linux/platform_device.h>
34#include <linux/pm_runtime.h>
35#include <linux/slab.h>
36#include <linux/of_irq.h>
26 37
27#define BTM_HEADER_LEN 4 38#define BTM_HEADER_LEN 4
28#define BTM_UPLD_SIZE 2312 39#define BTM_UPLD_SIZE 2312
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index f25a825a693f..7ad8d61c0c61 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -510,34 +510,39 @@ static int btmrvl_download_cal_data(struct btmrvl_private *priv,
510static int btmrvl_check_device_tree(struct btmrvl_private *priv) 510static int btmrvl_check_device_tree(struct btmrvl_private *priv)
511{ 511{
512 struct device_node *dt_node; 512 struct device_node *dt_node;
513 struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
513 u8 cal_data[BT_CAL_HDR_LEN + BT_CAL_DATA_SIZE]; 514 u8 cal_data[BT_CAL_HDR_LEN + BT_CAL_DATA_SIZE];
514 int ret; 515 int ret = 0;
515 u32 val; 516 u16 gpio, gap;
517
518 if (card->plt_of_node) {
519 dt_node = card->plt_of_node;
520 ret = of_property_read_u16(dt_node, "marvell,wakeup-pin",
521 &gpio);
522 if (ret)
523 gpio = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
524
525 ret = of_property_read_u16(dt_node, "marvell,wakeup-gap-ms",
526 &gap);
527 if (ret)
528 gap = (u8)(priv->btmrvl_dev.gpio_gap & 0x00ff);
516 529
517 for_each_compatible_node(dt_node, NULL, "btmrvl,cfgdata") { 530 priv->btmrvl_dev.gpio_gap = (gpio << 8) + gap;
518 ret = of_property_read_u32(dt_node, "btmrvl,gpio-gap", &val);
519 if (!ret)
520 priv->btmrvl_dev.gpio_gap = val;
521 531
522 ret = of_property_read_u8_array(dt_node, "btmrvl,cal-data", 532 ret = of_property_read_u8_array(dt_node, "marvell,cal-data",
523 cal_data + BT_CAL_HDR_LEN, 533 cal_data + BT_CAL_HDR_LEN,
524 BT_CAL_DATA_SIZE); 534 BT_CAL_DATA_SIZE);
525 if (ret) { 535 if (ret)
526 of_node_put(dt_node);
527 return ret; 536 return ret;
528 }
529 537
530 BT_DBG("Use cal data from device tree"); 538 BT_DBG("Use cal data from device tree");
531 ret = btmrvl_download_cal_data(priv, cal_data, 539 ret = btmrvl_download_cal_data(priv, cal_data,
532 BT_CAL_DATA_SIZE); 540 BT_CAL_DATA_SIZE);
533 if (ret) { 541 if (ret)
534 BT_ERR("Fail to download calibrate data"); 542 BT_ERR("Fail to download calibrate data");
535 of_node_put(dt_node);
536 return ret;
537 }
538 } 543 }
539 544
540 return 0; 545 return ret;
541} 546}
542 547
543static int btmrvl_setup(struct hci_dev *hdev) 548static int btmrvl_setup(struct hci_dev *hdev)
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index c6ef248de5e4..f425ddf91a24 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -52,6 +52,68 @@ static struct memory_type_mapping mem_type_mapping_tbl[] = {
52 {"EXTLAST", NULL, 0, 0xFE}, 52 {"EXTLAST", NULL, 0, 0xFE},
53}; 53};
54 54
55static const struct of_device_id btmrvl_sdio_of_match_table[] = {
56 { .compatible = "marvell,sd8897-bt" },
57 { .compatible = "marvell,sd8997-bt" },
58 { }
59};
60
61static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv)
62{
63 struct btmrvl_plt_wake_cfg *cfg = priv;
64
65 if (cfg->irq_bt >= 0) {
66 pr_info("%s: wake by bt", __func__);
67 cfg->wake_by_bt = true;
68 disable_irq_nosync(irq);
69 }
70
71 return IRQ_HANDLED;
72}
73
74/* This function parses device tree node using mmc subnode devicetree API.
75 * The device node is saved in card->plt_of_node.
76 * If the device tree node exists and includes interrupts attributes, this
77 * function will request platform specific wakeup interrupt.
78 */
79static int btmrvl_sdio_probe_of(struct device *dev,
80 struct btmrvl_sdio_card *card)
81{
82 struct btmrvl_plt_wake_cfg *cfg;
83 int ret;
84
85 if (!dev->of_node ||
86 !of_match_node(btmrvl_sdio_of_match_table, dev->of_node)) {
87 pr_err("sdio platform data not available");
88 return -1;
89 }
90
91 card->plt_of_node = dev->of_node;
92
93 card->plt_wake_cfg = devm_kzalloc(dev, sizeof(*card->plt_wake_cfg),
94 GFP_KERNEL);
95 cfg = card->plt_wake_cfg;
96 if (cfg && card->plt_of_node) {
97 cfg->irq_bt = irq_of_parse_and_map(card->plt_of_node, 0);
98 if (!cfg->irq_bt) {
99 dev_err(dev, "fail to parse irq_bt from device tree");
100 } else {
101 ret = devm_request_irq(dev, cfg->irq_bt,
102 btmrvl_wake_irq_bt,
103 IRQF_TRIGGER_LOW,
104 "bt_wake", cfg);
105 if (ret) {
106 dev_err(dev,
107 "Failed to request irq_bt %d (%d)\n",
108 cfg->irq_bt, ret);
109 }
110 disable_irq(cfg->irq_bt);
111 }
112 }
113
114 return 0;
115}
116
55/* The btmrvl_sdio_remove() callback function is called 117/* The btmrvl_sdio_remove() callback function is called
56 * when user removes this module from kernel space or ejects 118 * when user removes this module from kernel space or ejects
57 * the card from the slot. The driver handles these 2 cases 119 * the card from the slot. The driver handles these 2 cases
@@ -1464,6 +1526,9 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
1464 1526
1465 btmrvl_sdio_enable_host_int(card); 1527 btmrvl_sdio_enable_host_int(card);
1466 1528
1529 /* Device tree node parsing and platform specific configuration*/
1530 btmrvl_sdio_probe_of(&func->dev, card);
1531
1467 priv = btmrvl_add_card(card); 1532 priv = btmrvl_add_card(card);
1468 if (!priv) { 1533 if (!priv) {
1469 BT_ERR("Initializing card failed!"); 1534 BT_ERR("Initializing card failed!");
@@ -1544,6 +1609,13 @@ static int btmrvl_sdio_suspend(struct device *dev)
1544 return 0; 1609 return 0;
1545 } 1610 }
1546 1611
1612 /* Enable platform specific wakeup interrupt */
1613 if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0) {
1614 card->plt_wake_cfg->wake_by_bt = false;
1615 enable_irq(card->plt_wake_cfg->irq_bt);
1616 enable_irq_wake(card->plt_wake_cfg->irq_bt);
1617 }
1618
1547 priv = card->priv; 1619 priv = card->priv;
1548 priv->adapter->is_suspending = true; 1620 priv->adapter->is_suspending = true;
1549 hcidev = priv->btmrvl_dev.hcidev; 1621 hcidev = priv->btmrvl_dev.hcidev;
@@ -1606,6 +1678,13 @@ static int btmrvl_sdio_resume(struct device *dev)
1606 BT_DBG("%s: SDIO resume", hcidev->name); 1678 BT_DBG("%s: SDIO resume", hcidev->name);
1607 hci_resume_dev(hcidev); 1679 hci_resume_dev(hcidev);
1608 1680
1681 /* Disable platform specific wakeup interrupt */
1682 if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0) {
1683 disable_irq_wake(card->plt_wake_cfg->irq_bt);
1684 if (!card->plt_wake_cfg->wake_by_bt)
1685 disable_irq(card->plt_wake_cfg->irq_bt);
1686 }
1687
1609 return 0; 1688 return 0;
1610} 1689}
1611 1690
diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h
index 1a3bd064c442..3a522d23ee6e 100644
--- a/drivers/bluetooth/btmrvl_sdio.h
+++ b/drivers/bluetooth/btmrvl_sdio.h
@@ -62,6 +62,10 @@
62 62
63#define FIRMWARE_READY 0xfedc 63#define FIRMWARE_READY 0xfedc
64 64
65struct btmrvl_plt_wake_cfg {
66 int irq_bt;
67 bool wake_by_bt;
68};
65 69
66struct btmrvl_sdio_card_reg { 70struct btmrvl_sdio_card_reg {
67 u8 cfg; 71 u8 cfg;
@@ -97,6 +101,8 @@ struct btmrvl_sdio_card {
97 u16 sd_blksz_fw_dl; 101 u16 sd_blksz_fw_dl;
98 u8 rx_unit; 102 u8 rx_unit;
99 struct btmrvl_private *priv; 103 struct btmrvl_private *priv;
104 struct device_node *plt_of_node;
105 struct btmrvl_plt_wake_cfg *plt_wake_cfg;
100}; 106};
101 107
102struct btmrvl_sdio_device { 108struct btmrvl_sdio_device {