summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-08-29 13:15:03 -0700
committerDavid S. Miller <davem@davemloft.net>2015-08-29 13:15:03 -0700
commitf5004a14fac0a71656340544c48a14c80a3afddf (patch)
treec92b514ef46049e3050ed95e3065ae2190d3d3fc /drivers
parent6d74232410a9f3ed0e1fc0f5e538598f21e93982 (diff)
parent917522aae169ad02010dcee6ae42c16155bcd285 (diff)
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== pull request: bluetooth-next 2015-08-28 One more bunch of Bluetooth patches for 4.3: - Crash fix for hci_bcm driver - Enhancements to hci_intel driver (e.g. baudrate configuration) - Fix for SCO link type after multiple connect attempts - Cleanups & minor fixes in a few other places Please let me know if there are any issues pulling. Thanks. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/btintel.c2
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c3
-rw-r--r--drivers/bluetooth/btusb.c4
-rw-r--r--drivers/bluetooth/hci_bcm.c40
-rw-r--r--drivers/bluetooth/hci_h4.c9
-rw-r--r--drivers/bluetooth/hci_intel.c321
6 files changed, 348 insertions, 31 deletions
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 1ce4ac16c7fa..048423fd83bf 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -173,3 +173,5 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("intel/ibt-11-5.sfi");
+MODULE_FIRMWARE("intel/ibt-11-5.ddc");
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 7c097629e593..b9978a7ba0cc 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -1376,8 +1376,7 @@ done:
/* fw_dump_data will be free in device coredump release function
after 5 min*/
- dev_coredumpv(&priv->btmrvl_dev.hcidev->dev, fw_dump_data,
- fw_dump_len, GFP_KERNEL);
+ dev_coredumpv(&card->func->dev, fw_dump_data, fw_dump_len, GFP_KERNEL);
BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump end");
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index f759dea7d3ba..b6aceaf82aa8 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -1581,7 +1581,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
/* fw_patch_num indicates the version of patch the device currently
* have. If there is no patch data in the device, it is always 0x00.
- * So, if it is other than 0x00, no need to patch the deivce again.
+ * So, if it is other than 0x00, no need to patch the device again.
*/
if (ver->fw_patch_num) {
BT_INFO("%s: Intel device is already patched. patch num: %02x",
@@ -2100,7 +2100,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
frag_len += sizeof(*cmd) + cmd->plen;
- /* The paramter length of the secure send command requires
+ /* The parameter length of the secure send command requires
* a 4 byte alignment. It happens so that the firmware file
* contains proper Intel_NOP commands to align the fragments
* as needed.
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 322302b04710..835bfab88ef5 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -66,7 +66,7 @@ struct bcm_data {
};
/* List of BCM BT UART devices */
-static DEFINE_SPINLOCK(bcm_device_list_lock);
+static DEFINE_SPINLOCK(bcm_device_lock);
static LIST_HEAD(bcm_device_list);
static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed)
@@ -118,7 +118,7 @@ static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed)
return 0;
}
-/* bcm_device_exists should be protected by bcm_device_list_lock */
+/* bcm_device_exists should be protected by bcm_device_lock */
static bool bcm_device_exists(struct bcm_device *device)
{
struct list_head *p;
@@ -138,8 +138,8 @@ static int bcm_gpio_set_power(struct bcm_device *dev, bool powered)
if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled)
clk_enable(dev->clk);
- gpiod_set_value_cansleep(dev->shutdown, powered);
- gpiod_set_value_cansleep(dev->device_wakeup, powered);
+ gpiod_set_value(dev->shutdown, powered);
+ gpiod_set_value(dev->device_wakeup, powered);
if (!powered && !IS_ERR(dev->clk) && dev->clk_enabled)
clk_disable(dev->clk);
@@ -164,7 +164,7 @@ static int bcm_open(struct hci_uart *hu)
hu->priv = bcm;
- spin_lock(&bcm_device_list_lock);
+ spin_lock(&bcm_device_lock);
list_for_each(p, &bcm_device_list) {
struct bcm_device *dev = list_entry(p, struct bcm_device, list);
@@ -185,7 +185,7 @@ static int bcm_open(struct hci_uart *hu)
if (bcm->dev)
bcm_gpio_set_power(bcm->dev, true);
- spin_unlock(&bcm_device_list_lock);
+ spin_unlock(&bcm_device_lock);
return 0;
}
@@ -197,14 +197,14 @@ static int bcm_close(struct hci_uart *hu)
BT_DBG("hu %p", hu);
/* Protect bcm->dev against removal of the device or driver */
- spin_lock(&bcm_device_list_lock);
+ spin_lock(&bcm_device_lock);
if (bcm_device_exists(bcm->dev)) {
bcm_gpio_set_power(bcm->dev, false);
#ifdef CONFIG_PM_SLEEP
bcm->dev->hu = NULL;
#endif
}
- spin_unlock(&bcm_device_list_lock);
+ spin_unlock(&bcm_device_lock);
skb_queue_purge(&bcm->txq);
kfree_skb(bcm->rx_skb);
@@ -338,6 +338,11 @@ static int bcm_suspend(struct device *dev)
BT_DBG("suspend (%p): is_suspended %d", bdev, bdev->is_suspended);
+ spin_lock(&bcm_device_lock);
+
+ if (!bdev->hu)
+ goto unlock;
+
if (!bdev->is_suspended) {
hci_uart_set_flow_control(bdev->hu, true);
@@ -352,6 +357,9 @@ static int bcm_suspend(struct device *dev)
mdelay(15);
}
+unlock:
+ spin_unlock(&bcm_device_lock);
+
return 0;
}
@@ -362,6 +370,11 @@ static int bcm_resume(struct device *dev)
BT_DBG("resume (%p): is_suspended %d", bdev, bdev->is_suspended);
+ spin_lock(&bcm_device_lock);
+
+ if (!bdev->hu)
+ goto unlock;
+
if (bdev->device_wakeup) {
gpiod_set_value(bdev->device_wakeup, true);
BT_DBG("resume, delaying 15 ms");
@@ -375,6 +388,9 @@ static int bcm_resume(struct device *dev)
hci_uart_set_flow_control(bdev->hu, false);
}
+unlock:
+ spin_unlock(&bcm_device_lock);
+
return 0;
}
#endif
@@ -488,9 +504,9 @@ static int bcm_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "%s device registered.\n", dev->name);
/* Place this instance on the device list */
- spin_lock(&bcm_device_list_lock);
+ spin_lock(&bcm_device_lock);
list_add_tail(&dev->list, &bcm_device_list);
- spin_unlock(&bcm_device_list_lock);
+ spin_unlock(&bcm_device_lock);
bcm_gpio_set_power(dev, false);
@@ -501,9 +517,9 @@ static int bcm_remove(struct platform_device *pdev)
{
struct bcm_device *dev = platform_get_drvdata(pdev);
- spin_lock(&bcm_device_list_lock);
+ spin_lock(&bcm_device_lock);
list_del(&dev->list);
- spin_unlock(&bcm_device_list_lock);
+ spin_unlock(&bcm_device_lock);
acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev));
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 57faddc53645..eec3f28e4bb9 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -223,8 +223,7 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
switch ((&pkts[i])->lsize) {
case 0:
/* No variable data length */
- (&pkts[i])->recv(hdev, skb);
- skb = NULL;
+ dlen = 0;
break;
case 1:
/* Single octet variable length */
@@ -252,6 +251,12 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
kfree_skb(skb);
return ERR_PTR(-EILSEQ);
}
+
+ if (!dlen) {
+ /* No more data, complete frame */
+ (&pkts[i])->recv(hdev, skb);
+ skb = NULL;
+ }
} else {
/* Complete frame */
(&pkts[i])->recv(hdev, skb);
diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c
index 21dfa89751df..cf07d1121956 100644
--- a/drivers/bluetooth/hci_intel.c
+++ b/drivers/bluetooth/hci_intel.c
@@ -25,7 +25,12 @@
#include <linux/errno.h>
#include <linux/skbuff.h>
#include <linux/firmware.h>
+#include <linux/module.h>
#include <linux/wait.h>
+#include <linux/tty.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/acpi.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -39,12 +44,108 @@
#define STATE_FIRMWARE_FAILED 3
#define STATE_BOOTING 4
+struct intel_device {
+ struct list_head list;
+ struct platform_device *pdev;
+ struct gpio_desc *reset;
+};
+
+static LIST_HEAD(intel_device_list);
+static DEFINE_SPINLOCK(intel_device_list_lock);
+
struct intel_data {
struct sk_buff *rx_skb;
struct sk_buff_head txq;
unsigned long flags;
};
+static u8 intel_convert_speed(unsigned int speed)
+{
+ switch (speed) {
+ case 9600:
+ return 0x00;
+ case 19200:
+ return 0x01;
+ case 38400:
+ return 0x02;
+ case 57600:
+ return 0x03;
+ case 115200:
+ return 0x04;
+ case 230400:
+ return 0x05;
+ case 460800:
+ return 0x06;
+ case 921600:
+ return 0x07;
+ case 1843200:
+ return 0x08;
+ case 3250000:
+ return 0x09;
+ case 2000000:
+ return 0x0a;
+ case 3000000:
+ return 0x0b;
+ default:
+ return 0xff;
+ }
+}
+
+static int intel_wait_booting(struct hci_uart *hu)
+{
+ struct intel_data *intel = hu->priv;
+ int err;
+
+ err = wait_on_bit_timeout(&intel->flags, STATE_BOOTING,
+ TASK_INTERRUPTIBLE,
+ msecs_to_jiffies(1000));
+
+ if (err == 1) {
+ BT_ERR("%s: Device boot interrupted", hu->hdev->name);
+ return -EINTR;
+ }
+
+ if (err) {
+ BT_ERR("%s: Device boot timeout", hu->hdev->name);
+ return -ETIMEDOUT;
+ }
+
+ return err;
+}
+
+static int intel_set_power(struct hci_uart *hu, bool powered)
+{
+ struct list_head *p;
+ int err = -ENODEV;
+
+ spin_lock(&intel_device_list_lock);
+
+ list_for_each(p, &intel_device_list) {
+ struct intel_device *idev = list_entry(p, struct intel_device,
+ list);
+
+ /* tty device and pdev device should share the same parent
+ * which is the UART port.
+ */
+ if (hu->tty->dev->parent != idev->pdev->dev.parent)
+ continue;
+
+ if (!idev->reset) {
+ err = -ENOTSUPP;
+ break;
+ }
+
+ BT_INFO("hu %p, Switching compatible pm device (%s) to %u",
+ hu, dev_name(&idev->pdev->dev), powered);
+
+ gpiod_set_value(idev->reset, powered);
+ }
+
+ spin_unlock(&intel_device_list_lock);
+
+ return err;
+}
+
static int intel_open(struct hci_uart *hu)
{
struct intel_data *intel;
@@ -58,6 +159,10 @@ static int intel_open(struct hci_uart *hu)
skb_queue_head_init(&intel->txq);
hu->priv = intel;
+
+ if (!intel_set_power(hu, true))
+ set_bit(STATE_BOOTING, &intel->flags);
+
return 0;
}
@@ -67,6 +172,8 @@ static int intel_close(struct hci_uart *hu)
BT_DBG("hu %p", hu);
+ intel_set_power(hu, false);
+
skb_queue_purge(&intel->txq);
kfree_skb(intel->rx_skb);
kfree(intel);
@@ -111,6 +218,68 @@ static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode)
return hci_recv_frame(hdev, skb);
}
+static int intel_set_baudrate(struct hci_uart *hu, unsigned int speed)
+{
+ struct intel_data *intel = hu->priv;
+ struct hci_dev *hdev = hu->hdev;
+ u8 speed_cmd[] = { 0x06, 0xfc, 0x01, 0x00 };
+ struct sk_buff *skb;
+ int err;
+
+ /* This can be the first command sent to the chip, check
+ * that the controller is ready.
+ */
+ err = intel_wait_booting(hu);
+
+ clear_bit(STATE_BOOTING, &intel->flags);
+
+ /* In case of timeout, try to continue anyway */
+ if (err && err != ETIMEDOUT)
+ return err;
+
+ BT_INFO("%s: Change controller speed to %d", hdev->name, speed);
+
+ speed_cmd[3] = intel_convert_speed(speed);
+ if (speed_cmd[3] == 0xff) {
+ BT_ERR("%s: Unsupported speed", hdev->name);
+ return -EINVAL;
+ }
+
+ /* Device will not accept speed change if Intel version has not been
+ * previously requested.
+ */
+ skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Reading Intel version information failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return PTR_ERR(skb);
+ }
+ kfree_skb(skb);
+
+ skb = bt_skb_alloc(sizeof(speed_cmd), GFP_KERNEL);
+ if (!skb) {
+ BT_ERR("%s: Failed to allocate memory for baudrate packet",
+ hdev->name);
+ return -ENOMEM;
+ }
+
+ memcpy(skb_put(skb, sizeof(speed_cmd)), speed_cmd, sizeof(speed_cmd));
+ bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
+
+ hci_uart_set_flow_control(hu, true);
+
+ skb_queue_tail(&intel->txq, skb);
+ hci_uart_tx_wakeup(hu);
+
+ /* wait 100ms to change baudrate on controller side */
+ msleep(100);
+
+ hci_uart_set_baudrate(hu, speed);
+ hci_uart_set_flow_control(hu, false);
+
+ return 0;
+}
+
static int intel_setup(struct hci_uart *hu)
{
static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01,
@@ -126,6 +295,8 @@ static int intel_setup(struct hci_uart *hu)
u32 frag_len;
ktime_t calltime, delta, rettime;
unsigned long long duration;
+ unsigned int init_speed, oper_speed;
+ int speed_change = 0;
int err;
BT_DBG("%s", hdev->name);
@@ -134,6 +305,28 @@ static int intel_setup(struct hci_uart *hu)
calltime = ktime_get();
+ if (hu->init_speed)
+ init_speed = hu->init_speed;
+ else
+ init_speed = hu->proto->init_speed;
+
+ if (hu->oper_speed)
+ oper_speed = hu->oper_speed;
+ else
+ oper_speed = hu->proto->oper_speed;
+
+ if (oper_speed && init_speed && oper_speed != init_speed)
+ speed_change = 1;
+
+ /* Check that the controller is ready */
+ err = intel_wait_booting(hu);
+
+ clear_bit(STATE_BOOTING, &intel->flags);
+
+ /* In case of timeout, try to continue anyway */
+ if (err && err != ETIMEDOUT)
+ return err;
+
set_bit(STATE_BOOTLOADER, &intel->flags);
/* Read the Intel version information to determine if the device
@@ -416,6 +609,13 @@ done:
if (err < 0)
return err;
+ /* We need to restore the default speed before Intel reset */
+ if (speed_change) {
+ err = intel_set_baudrate(hu, init_speed);
+ if (err)
+ return err;
+ }
+
calltime = ktime_get();
set_bit(STATE_BOOTING, &intel->flags);
@@ -436,19 +636,11 @@ done:
*/
BT_INFO("%s: Waiting for device to boot", hdev->name);
- err = wait_on_bit_timeout(&intel->flags, STATE_BOOTING,
- TASK_INTERRUPTIBLE,
- msecs_to_jiffies(1000));
-
- if (err == 1) {
- BT_ERR("%s: Device boot interrupted", hdev->name);
- return -EINTR;
- }
+ err = intel_wait_booting(hu);
+ if (err)
+ return err;
- if (err) {
- BT_ERR("%s: Device boot timeout", hdev->name);
- return -ETIMEDOUT;
- }
+ clear_bit(STATE_BOOTING, &intel->flags);
rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
@@ -456,6 +648,19 @@ done:
BT_INFO("%s: Device booted in %llu usecs", hdev->name, duration);
+ skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_CMD_TIMEOUT);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+ kfree_skb(skb);
+
+ if (speed_change) {
+ err = intel_set_baudrate(hu, oper_speed);
+ if (err)
+ return err;
+ }
+
+ BT_INFO("%s: Setup complete", hdev->name);
+
clear_bit(STATE_BOOTLOADER, &intel->flags);
return 0;
@@ -467,7 +672,8 @@ static int intel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
struct intel_data *intel = hu->priv;
struct hci_event_hdr *hdr;
- if (!test_bit(STATE_BOOTLOADER, &intel->flags))
+ if (!test_bit(STATE_BOOTLOADER, &intel->flags) &&
+ !test_bit(STATE_BOOTING, &intel->flags))
goto recv;
hdr = (void *)skb->data;
@@ -572,21 +778,110 @@ static const struct hci_uart_proto intel_proto = {
.id = HCI_UART_INTEL,
.name = "Intel",
.init_speed = 115200,
+ .oper_speed = 3000000,
.open = intel_open,
.close = intel_close,
.flush = intel_flush,
.setup = intel_setup,
+ .set_baudrate = intel_set_baudrate,
.recv = intel_recv,
.enqueue = intel_enqueue,
.dequeue = intel_dequeue,
};
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id intel_acpi_match[] = {
+ { "INT33E1", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, intel_acpi_match);
+
+static int intel_acpi_probe(struct intel_device *idev)
+{
+ const struct acpi_device_id *id;
+
+ id = acpi_match_device(intel_acpi_match, &idev->pdev->dev);
+ if (!id)
+ return -ENODEV;
+
+ return 0;
+}
+#else
+static int intel_acpi_probe(struct intel_device *idev)
+{
+ return -ENODEV;
+}
+#endif
+
+static int intel_probe(struct platform_device *pdev)
+{
+ struct intel_device *idev;
+
+ idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);
+ if (!idev)
+ return -ENOMEM;
+
+ idev->pdev = pdev;
+
+ if (ACPI_HANDLE(&pdev->dev)) {
+ int err = intel_acpi_probe(idev);
+ if (err)
+ return err;
+ } else {
+ return -ENODEV;
+ }
+
+ idev->reset = devm_gpiod_get_optional(&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);
+ }
+
+ platform_set_drvdata(pdev, idev);
+
+ /* Place this instance on the device list */
+ spin_lock(&intel_device_list_lock);
+ list_add_tail(&idev->list, &intel_device_list);
+ spin_unlock(&intel_device_list_lock);
+
+ dev_info(&pdev->dev, "registered.\n");
+
+ return 0;
+}
+
+static int intel_remove(struct platform_device *pdev)
+{
+ struct intel_device *idev = platform_get_drvdata(pdev);
+
+ spin_lock(&intel_device_list_lock);
+ list_del(&idev->list);
+ spin_unlock(&intel_device_list_lock);
+
+ dev_info(&pdev->dev, "unregistered.\n");
+
+ return 0;
+}
+
+static struct platform_driver intel_driver = {
+ .probe = intel_probe,
+ .remove = intel_remove,
+ .driver = {
+ .name = "hci_intel",
+ .acpi_match_table = ACPI_PTR(intel_acpi_match),
+ },
+};
+
int __init intel_init(void)
{
+ platform_driver_register(&intel_driver);
+
return hci_uart_register_proto(&intel_proto);
}
int __exit intel_deinit(void)
{
+ platform_driver_unregister(&intel_driver);
+
return hci_uart_unregister_proto(&intel_proto);
}