Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== pull request: bluetooth-next 2016-05-07 Here are a few more Bluetooth patches for the 4.7 kernel: - NULL pointer fix in hci_intel driver - New Intel Bluetooth controller id in btusb driver - Added device tree binding documentation for Marvel's bt-sd8xxx - Platform specific wakeup interrupt support for btmrvl driver Please let me know if there are any issues pulling. Thanks. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
7c878bb318
@ -1,29 +0,0 @@
|
||||
btmrvl
|
||||
------
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : must be "btmrvl,cfgdata"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- btmrvl,cal-data : Calibration data downloaded to the device during
|
||||
initialization. This is an array of 28 values(u8).
|
||||
|
||||
- btmrvl,gpio-gap : gpio and gap (in msecs) combination to be
|
||||
configured.
|
||||
|
||||
Example:
|
||||
|
||||
GPIO pin 13 is configured as a wakeup source and GAP is set to 100 msecs
|
||||
in below example.
|
||||
|
||||
btmrvl {
|
||||
compatible = "btmrvl,cfgdata";
|
||||
|
||||
btmrvl,cal-data = /bits/ 8 <
|
||||
0x37 0x01 0x1c 0x00 0xff 0xff 0xff 0xff 0x01 0x7f 0x04 0x02
|
||||
0x00 0x00 0xba 0xce 0xc0 0xc6 0x2d 0x00 0x00 0x00 0x00 0x00
|
||||
0x00 0x00 0xf0 0x00>;
|
||||
btmrvl,gpio-gap = <0x0d64>;
|
||||
};
|
56
Documentation/devicetree/bindings/net/marvell-bt-sd8xxx.txt
Normal file
56
Documentation/devicetree/bindings/net/marvell-bt-sd8xxx.txt
Normal file
@ -0,0 +1,56 @@
|
||||
Marvell 8897/8997 (sd8897/sd8997) bluetooth SDIO devices
|
||||
------
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be one of the following:
|
||||
* "marvell,sd8897-bt"
|
||||
* "marvell,sd8997-bt"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- marvell,cal-data: Calibration data downloaded to the device during
|
||||
initialization. This is an array of 28 values(u8).
|
||||
|
||||
- marvell,wakeup-pin: It represents wakeup pin number of the bluetooth chip.
|
||||
firmware will use the pin to wakeup host system.
|
||||
- marvell,wakeup-gap-ms: wakeup gap represents wakeup latency of the host
|
||||
platform. The value will be configured to firmware. This
|
||||
is needed to work chip's sleep feature as expected.
|
||||
- interrupt-parent: phandle of the parent interrupt controller
|
||||
- interrupts : interrupt pin number to the cpu. Driver will request an irq based
|
||||
on this interrupt number. During system suspend, the irq will be
|
||||
enabled so that the bluetooth chip can wakeup host platform under
|
||||
certain condition. During system resume, the irq will be disabled
|
||||
to make sure unnecessary interrupt is not received.
|
||||
|
||||
Example:
|
||||
|
||||
IRQ pin 119 is used as system wakeup source interrupt.
|
||||
wakeup pin 13 and gap 100ms are configured so that firmware can wakeup host
|
||||
using this device side pin and wakeup latency.
|
||||
calibration data is also available in below example.
|
||||
|
||||
&mmc3 {
|
||||
status = "okay";
|
||||
vmmc-supply = <&wlan_en_reg>;
|
||||
bus-width = <4>;
|
||||
cap-power-off-card;
|
||||
keep-power-in-suspend;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
btmrvl: bluetooth@2 {
|
||||
compatible = "marvell,sd8897-bt";
|
||||
reg = <2>;
|
||||
interrupt-parent = <&pio>;
|
||||
interrupts = <119 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
marvell,cal-data = /bits/ 8 <
|
||||
0x37 0x01 0x1c 0x00 0xff 0xff 0xff 0xff 0x01 0x7f 0x04 0x02
|
||||
0x00 0x00 0xba 0xce 0xc0 0xc6 0x2d 0x00 0x00 0x00 0x00 0x00
|
||||
0x00 0x00 0xf0 0x00>;
|
||||
marvell,wakeup-pin = <0x0d>;
|
||||
marvell,wakeup-gap-ms = <0x64>;
|
||||
};
|
||||
};
|
@ -23,6 +23,17 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#define BTM_HEADER_LEN 4
|
||||
#define BTM_UPLD_SIZE 2312
|
||||
|
@ -510,34 +510,39 @@ static int btmrvl_download_cal_data(struct btmrvl_private *priv,
|
||||
static int btmrvl_check_device_tree(struct btmrvl_private *priv)
|
||||
{
|
||||
struct device_node *dt_node;
|
||||
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
|
||||
u8 cal_data[BT_CAL_HDR_LEN + BT_CAL_DATA_SIZE];
|
||||
int ret;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
u16 gpio, gap;
|
||||
|
||||
for_each_compatible_node(dt_node, NULL, "btmrvl,cfgdata") {
|
||||
ret = of_property_read_u32(dt_node, "btmrvl,gpio-gap", &val);
|
||||
if (!ret)
|
||||
priv->btmrvl_dev.gpio_gap = val;
|
||||
if (card->plt_of_node) {
|
||||
dt_node = card->plt_of_node;
|
||||
ret = of_property_read_u16(dt_node, "marvell,wakeup-pin",
|
||||
&gpio);
|
||||
if (ret)
|
||||
gpio = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
|
||||
|
||||
ret = of_property_read_u8_array(dt_node, "btmrvl,cal-data",
|
||||
ret = of_property_read_u16(dt_node, "marvell,wakeup-gap-ms",
|
||||
&gap);
|
||||
if (ret)
|
||||
gap = (u8)(priv->btmrvl_dev.gpio_gap & 0x00ff);
|
||||
|
||||
priv->btmrvl_dev.gpio_gap = (gpio << 8) + gap;
|
||||
|
||||
ret = of_property_read_u8_array(dt_node, "marvell,cal-data",
|
||||
cal_data + BT_CAL_HDR_LEN,
|
||||
BT_CAL_DATA_SIZE);
|
||||
if (ret) {
|
||||
of_node_put(dt_node);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
BT_DBG("Use cal data from device tree");
|
||||
ret = btmrvl_download_cal_data(priv, cal_data,
|
||||
BT_CAL_DATA_SIZE);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
BT_ERR("Fail to download calibrate data");
|
||||
of_node_put(dt_node);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btmrvl_setup(struct hci_dev *hdev)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,10 @@
|
||||
|
||||
#define FIRMWARE_READY 0xfedc
|
||||
|
||||
struct btmrvl_plt_wake_cfg {
|
||||
int irq_bt;
|
||||
bool wake_by_bt;
|
||||
};
|
||||
|
||||
struct btmrvl_sdio_card_reg {
|
||||
u8 cfg;
|
||||
@ -97,6 +101,8 @@ struct btmrvl_sdio_card {
|
||||
u16 sd_blksz_fw_dl;
|
||||
u8 rx_unit;
|
||||
struct btmrvl_private *priv;
|
||||
struct device_node *plt_of_node;
|
||||
struct btmrvl_plt_wake_cfg *plt_wake_cfg;
|
||||
};
|
||||
|
||||
struct btmrvl_sdio_device {
|
||||
|
@ -2001,12 +2001,13 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* At the moment only the hardware variant iBT 3.0 (LnP/SfP) is
|
||||
* supported by this firmware loading method. This check has been
|
||||
* put in place to ensure correct forward compatibility options
|
||||
* when newer hardware variants come along.
|
||||
/* At the moment the iBT 3.0 hardware variants 0x0b (LnP/SfP)
|
||||
* and 0x0c (WsP) are supported by this firmware loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
if (ver.hw_variant != 0x0b) {
|
||||
if (ver.hw_variant != 0x0b && ver.hw_variant != 0x0c) {
|
||||
BT_ERR("%s: Unsupported Intel hardware variant (%u)",
|
||||
hdev->name, ver.hw_variant);
|
||||
return -EINVAL;
|
||||
|
@ -1210,8 +1210,7 @@ static int intel_probe(struct platform_device *pdev)
|
||||
|
||||
idev->pdev = pdev;
|
||||
|
||||
idev->reset = devm_gpiod_get_optional(&pdev->dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
idev->reset = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(idev->reset)) {
|
||||
dev_err(&pdev->dev, "Unable to retrieve gpio\n");
|
||||
return PTR_ERR(idev->reset);
|
||||
@ -1223,8 +1222,7 @@ static int intel_probe(struct platform_device *pdev)
|
||||
|
||||
dev_err(&pdev->dev, "No IRQ, falling back to gpio-irq\n");
|
||||
|
||||
host_wake = devm_gpiod_get_optional(&pdev->dev, "host-wake",
|
||||
GPIOD_IN);
|
||||
host_wake = devm_gpiod_get(&pdev->dev, "host-wake", GPIOD_IN);
|
||||
if (IS_ERR(host_wake)) {
|
||||
dev_err(&pdev->dev, "Unable to retrieve IRQ\n");
|
||||
goto no_irq;
|
||||
|
Loading…
Reference in New Issue
Block a user