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:
David S. Miller 2016-05-09 00:10:00 -04:00
commit 7c878bb318
8 changed files with 180 additions and 53 deletions

View File

@ -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>;
};

View 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>;
};
};

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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 {

View File

@ -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;

View File

@ -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;