From patchwork Thu Apr 13 15:03:50 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Rob Herring \(Arm\)" X-Patchwork-Id: 97375 Delivered-To: patch@linaro.org Received: by 10.182.246.10 with SMTP id xs10csp787000obc; Thu, 13 Apr 2017 08:04:09 -0700 (PDT) X-Received: by 10.98.23.23 with SMTP id 23mr3830867pfx.30.1492095849657; Thu, 13 Apr 2017 08:04:09 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 74si9093443pga.211.2017.04.13.08.04.09; Thu, 13 Apr 2017 08:04:09 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754623AbdDMPEH (ORCPT + 6 others); Thu, 13 Apr 2017 11:04:07 -0400 Received: from mail-oi0-f65.google.com ([209.85.218.65]:33648 "EHLO mail-oi0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754511AbdDMPEE (ORCPT ); Thu, 13 Apr 2017 11:04:04 -0400 Received: by mail-oi0-f65.google.com with SMTP id t63so12468031oih.0; Thu, 13 Apr 2017 08:04:03 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=+ZE4rd0zSwH0QOZciamipR+7Y053NmFEl8HJbyagSaU=; b=ClxfOkyqtuR6fECYB2LB+kETes9YajbH+jkGUp6pqqNx92i+6tY3aJPcgnZdZM9sl7 x/3eT5y4903rToT91BjsXwnhkDmDr3JT7Os4+UgQ+0zTIowlFC2C8weLdJqy0lcKhH/R VtxeIe0Minh17BlEN48F62+VAgOQcXTnbf3nZDfVcEmfT37Tfa7W2kR5igSyHqvLzpCl EjcjOHkrzqyWPL0iBzGwXlVw6npRALVEKCNufLQ0vQFLi51Sp0b82Nz1rmMAM8gtwwmO D0NkrP8S3HQjKAPKZXj7qlJRyXJ5MbxkWu7juKicQx4sNKx84tbi6xrFORVSuXg01hxi gtxQ== X-Gm-Message-State: AN3rC/5YKSJlOfBybqoq8dghxTZDn8rGd1eFBpE2faH19clVaBMo8JYx KdGPTU4DwIIlrQOuX44= X-Received: by 10.202.182.194 with SMTP id g185mr1546931oif.60.1492095843352; Thu, 13 Apr 2017 08:04:03 -0700 (PDT) Received: from localhost.localdomain (66-90-148-125.dyn.grandenetworks.net. [66.90.148.125]) by smtp.googlemail.com with ESMTPSA id h189sm10626808oic.37.2017.04.13.08.04.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 13 Apr 2017 08:04:02 -0700 (PDT) From: Rob Herring To: Marcel Holtmann , linux-bluetooth@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, Gustavo Padovan , Johan Hedberg , Mark Rutland , Wei Xu , Eyal Reizer , Satish Patel , netdev@vger.kernel.org, devicetree@vger.kernel.org Subject: [PATCH v3 1/4] dt-bindings: net: Add TI WiLink shared transport binding Date: Thu, 13 Apr 2017 10:03:50 -0500 Message-Id: <20170413150353.7389-2-robh@kernel.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170413150353.7389-1-robh@kernel.org> References: <20170413150353.7389-1-robh@kernel.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add serial slave device binding for the TI WiLink series of Bluetooth/FM/GPS devices. Signed-off-by: Rob Herring Cc: Mark Rutland Cc: netdev@vger.kernel.org Cc: devicetree@vger.kernel.org --- v3: - rebase on bluetooth-next .../devicetree/bindings/net/ti,wilink-st.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/ti,wilink-st.txt -- 2.11.0 diff --git a/Documentation/devicetree/bindings/net/ti,wilink-st.txt b/Documentation/devicetree/bindings/net/ti,wilink-st.txt new file mode 100644 index 000000000000..cbad73a84ac4 --- /dev/null +++ b/Documentation/devicetree/bindings/net/ti,wilink-st.txt @@ -0,0 +1,35 @@ +TI WiLink 7/8 (wl12xx/wl18xx) Shared Transport BT/FM/GPS devices + +TI WiLink devices have a UART interface for providing Bluetooth, FM radio, +and GPS over what's called "shared transport". The shared transport is +standard BT HCI protocol with additional channels for the other functions. + +These devices also have a separate WiFi interface as described in +wireless/ti,wlcore.txt. + +This bindings follows the UART slave device binding in +../serial/slave-device.txt. + +Required properties: + - compatible: should be one of the following: + "ti,wl1271-st" + "ti,wl1273-st" + "ti,wl1831-st" + "ti,wl1835-st" + "ti,wl1837-st" + +Optional properties: + - enable-gpios : GPIO signal controlling enabling of BT. Active high. + - vio-supply : Vio input supply (1.8V) + - vbat-supply : Vbat input supply (2.9-4.8V) + +Example: + +&serial0 { + compatible = "ns16550a"; + ... + bluetooth { + compatible = "ti,wl1835-st"; + enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + }; +}; From patchwork Thu Apr 13 15:03:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Rob Herring \(Arm\)" X-Patchwork-Id: 97378 Delivered-To: patch@linaro.org Received: by 10.182.246.10 with SMTP id xs10csp787173obc; Thu, 13 Apr 2017 08:04:28 -0700 (PDT) X-Received: by 10.84.160.226 with SMTP id v31mr4889151plg.122.1492095868469; Thu, 13 Apr 2017 08:04:28 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p10si24176207pge.361.2017.04.13.08.04.28; Thu, 13 Apr 2017 08:04:28 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754710AbdDMPE1 (ORCPT + 6 others); Thu, 13 Apr 2017 11:04:27 -0400 Received: from mail-oi0-f67.google.com ([209.85.218.67]:33660 "EHLO mail-oi0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754503AbdDMPEF (ORCPT ); Thu, 13 Apr 2017 11:04:05 -0400 Received: by mail-oi0-f67.google.com with SMTP id t63so12468116oih.0; Thu, 13 Apr 2017 08:04:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=l2Np4pIZRjqwdXQQa1uyHnhSzlddKMNgH9pBJFM3Qmc=; b=lPGu9VoS6l/uBOO/q/npWuXup940V9YMW1zXHK/PMfybJJsnNfpN3clI2+kR+3vJ23 OjB2FGMc8EN15vYTT3Veq/0Ijq1zNaH758hMED3TJeZhRRlK8L6GYIQbD/cicr3wAPGG PMA4KeDXXGBrd7niBKpbKR0Seb303DX+bFs0NSP/M1cgYTgDG7yF3L+xBIrTNkkIKN7h Df7XEkEJTqRV3e2hZ07yDnA2e0TaFlcPy9+xiD6ff+5K5w5PuT8IscpYXt2HEng6INJm PVnqSpyhpYvAPOeJTDT+ncgnUkm4e6E2n2tqn1dSHXP9bgHkib3qfLfDUBkWcpRySQdD SSGg== X-Gm-Message-State: AN3rC/7bGatlazfURf9f8f1fvMeEbZrsxzhSzi6+E9ZdnPSet0cTQeAm F2n/f+sIZTkznA== X-Received: by 10.157.53.34 with SMTP id o31mr2159082otc.76.1492095844464; Thu, 13 Apr 2017 08:04:04 -0700 (PDT) Received: from localhost.localdomain (66-90-148-125.dyn.grandenetworks.net. [66.90.148.125]) by smtp.googlemail.com with ESMTPSA id h189sm10626808oic.37.2017.04.13.08.04.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 13 Apr 2017 08:04:03 -0700 (PDT) From: Rob Herring To: Marcel Holtmann , linux-bluetooth@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, Gustavo Padovan , Johan Hedberg , Mark Rutland , Wei Xu , Eyal Reizer , Satish Patel , netdev@vger.kernel.org, devicetree@vger.kernel.org Subject: [PATCH v3 2/4] bluetooth: hci_uart: remove unused hci_uart_init_tty Date: Thu, 13 Apr 2017 10:03:51 -0500 Message-Id: <20170413150353.7389-3-robh@kernel.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170413150353.7389-1-robh@kernel.org> References: <20170413150353.7389-1-robh@kernel.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org There are no users of hci_uart_init_tty, so remove it. Signed-off-by: Rob Herring Cc: Marcel Holtmann Cc: Gustavo Padovan Cc: Johan Hedberg Cc: linux-bluetooth@vger.kernel.org --- v3: - rebase on bluetooth-next drivers/bluetooth/hci_ldisc.c | 19 ------------------- drivers/bluetooth/hci_uart.h | 1 - 2 files changed, 20 deletions(-) -- 2.11.0 diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 17bcbc13623f..cec4438ede01 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -319,25 +319,6 @@ void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, hu->oper_speed = oper_speed; } -void hci_uart_init_tty(struct hci_uart *hu) -{ - struct tty_struct *tty = hu->tty; - struct ktermios ktermios; - - /* Bring the UART into a known 8 bits no parity hw fc state */ - ktermios = tty->termios; - ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | - INLCR | IGNCR | ICRNL | IXON); - ktermios.c_oflag &= ~OPOST; - ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - ktermios.c_cflag &= ~(CSIZE | PARENB); - ktermios.c_cflag |= CS8; - ktermios.c_cflag |= CRTSCTS; - - /* tty_set_termios() return not checked as it is always 0 */ - tty_set_termios(tty, &ktermios); -} - void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed) { struct tty_struct *tty = hu->tty; diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 1b41c661bbb8..2b05e557fad0 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -114,7 +114,6 @@ int hci_uart_register_device(struct hci_uart *hu, const struct hci_uart_proto *p int hci_uart_tx_wakeup(struct hci_uart *hu); int hci_uart_init_ready(struct hci_uart *hu); -void hci_uart_init_tty(struct hci_uart *hu); void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed); void hci_uart_set_flow_control(struct hci_uart *hu, bool enable); void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, From patchwork Thu Apr 13 15:03:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Rob Herring \(Arm\)" X-Patchwork-Id: 97377 Delivered-To: patch@linaro.org Received: by 10.182.246.10 with SMTP id xs10csp787039obc; Thu, 13 Apr 2017 08:04:14 -0700 (PDT) X-Received: by 10.84.214.16 with SMTP id h16mr4887064pli.96.1492095854708; Thu, 13 Apr 2017 08:04:14 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p10si24176207pge.361.2017.04.13.08.04.14; Thu, 13 Apr 2017 08:04:14 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754675AbdDMPEM (ORCPT + 6 others); Thu, 13 Apr 2017 11:04:12 -0400 Received: from mail-oi0-f66.google.com ([209.85.218.66]:34320 "EHLO mail-oi0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754578AbdDMPEH (ORCPT ); Thu, 13 Apr 2017 11:04:07 -0400 Received: by mail-oi0-f66.google.com with SMTP id t14so3052598oif.1; Thu, 13 Apr 2017 08:04:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=tlLgZDczsV69oKxFjSW84fwgTrL2rmzXJ2Y9nKoT17Q=; b=gtugevl8Qc2/QSqgSNKQXnw4OjiDDY86LHafIi2T5fYVk7gr5InjVVORgySnPR7/fc Ak9KyQu1gp1EfpRWg6CuZzobG01sX+3uQquqYCI3kdr62XhPzRB+Fxc2B2KlG2nNeeV2 XxqHPfNb7FHKQUBZr4PV4VTDgCIaeY6nCxRyg58WqE+siD8rwM2lRD9uX7XsrKSwwB+U yHwF+Q3+9fRGdIpQ9VYwCNl1mupZqVJTA//y8zJmHJF+Dc/ncpYRby4Alk/s/FVPT5/X KgZzJq3TAEKXwvxc9mqCDQDwYHkLAFz5b7t8H7Qtp1y9dNjW/WwS8qfVfvAtR/UflKky 0pkA== X-Gm-Message-State: AN3rC/5LObL93Mmnrsuyk3xalTgCWlia4NS6f+SrgImceosKmb3PoIuQ M70gOiHyRkgMwa/cBMs= X-Received: by 10.157.63.220 with SMTP id i28mr1707405ote.47.1492095845540; Thu, 13 Apr 2017 08:04:05 -0700 (PDT) Received: from localhost.localdomain (66-90-148-125.dyn.grandenetworks.net. [66.90.148.125]) by smtp.googlemail.com with ESMTPSA id h189sm10626808oic.37.2017.04.13.08.04.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 13 Apr 2017 08:04:05 -0700 (PDT) From: Rob Herring To: Marcel Holtmann , linux-bluetooth@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, Gustavo Padovan , Johan Hedberg , Mark Rutland , Wei Xu , Eyal Reizer , Satish Patel , netdev@vger.kernel.org, devicetree@vger.kernel.org Subject: [PATCH v3 3/4] bluetooth: hci_uart: add LL protocol serdev driver support Date: Thu, 13 Apr 2017 10:03:52 -0500 Message-Id: <20170413150353.7389-4-robh@kernel.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170413150353.7389-1-robh@kernel.org> References: <20170413150353.7389-1-robh@kernel.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Turns out that the LL protocol and the TI-ST are the same thing AFAICT. The TI-ST adds firmware loading, GPIO control, and shared access for NFC, FM radio, etc. For now, we're only implementing what is needed for BT. This mirrors other drivers like BCM and Intel, but uses the new serdev bus. The firmware loading is greatly simplified by using existing infrastructure to send commands. It may be a bit slower than the original code using synchronous functions, but the real bottleneck is likely doing firmware load at 115.2kbps. Signed-off-by: Rob Herring Cc: Marcel Holtmann Cc: Gustavo Padovan Cc: Johan Hedberg Cc: linux-bluetooth@vger.kernel.org --- v3: - rebase on bluetooth-next - Add explicit of.h include v2: - Use IS_ENABLED() to fix module build drivers/bluetooth/hci_ll.c | 262 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 261 insertions(+), 1 deletion(-) -- 2.11.0 diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index 02692fe30279..485e8eb04542 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -34,20 +34,24 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include #include +#include +#include #include +#include #include #include +#include #include "hci_uart.h" @@ -76,6 +80,12 @@ struct hcill_cmd { u8 cmd; } __packed; +struct ll_device { + struct hci_uart hu; + struct serdev_device *serdev; + struct gpio_desc *enable_gpio; +}; + struct ll_struct { unsigned long rx_state; unsigned long rx_count; @@ -136,6 +146,9 @@ static int ll_open(struct hci_uart *hu) hu->priv = ll; + if (hu->serdev) + serdev_device_open(hu->serdev); + return 0; } @@ -164,6 +177,13 @@ static int ll_close(struct hci_uart *hu) kfree_skb(ll->rx_skb); + if (hu->serdev) { + struct ll_device *lldev = serdev_device_get_drvdata(hu->serdev); + gpiod_set_value_cansleep(lldev->enable_gpio, 0); + + serdev_device_close(hu->serdev); + } + hu->priv = NULL; kfree(ll); @@ -505,9 +525,245 @@ static struct sk_buff *ll_dequeue(struct hci_uart *hu) return skb_dequeue(&ll->txq); } +#if IS_ENABLED(CONFIG_SERIAL_DEV_BUS) +static int read_local_version(struct hci_dev *hdev) +{ + int err = 0; + unsigned short version = 0; + struct sk_buff *skb; + struct hci_rp_read_local_version *ver; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Reading TI version information failed (%ld)", + PTR_ERR(skb)); + err = PTR_ERR(skb); + goto out; + } + if (skb->len != sizeof(*ver)) { + err = -EILSEQ; + goto out; + } + + ver = (struct hci_rp_read_local_version *)skb->data; + if (le16_to_cpu(ver->manufacturer) != 13) { + err = -ENODEV; + goto out; + } + + version = le16_to_cpu(ver->lmp_subver); + +out: + if (err) bt_dev_err(hdev, "Failed to read TI version info: %d", err); + kfree_skb(skb); + return err ? err : version; +} + +/** + * download_firmware - + * internal function which parses through the .bts firmware + * script file intreprets SEND, DELAY actions only as of now + */ +static int download_firmware(struct ll_device *lldev) +{ + unsigned short chip, min_ver, maj_ver; + int version, err, len; + unsigned char *ptr, *action_ptr; + unsigned char bts_scr_name[40]; /* 40 char long bts scr name? */ + const struct firmware *fw; + struct sk_buff *skb; + struct hci_command *cmd; + + version = read_local_version(lldev->hu.hdev); + if (version < 0) + return version; + + chip = (version & 0x7C00) >> 10; + min_ver = (version & 0x007F); + maj_ver = (version & 0x0380) >> 7; + if (version & 0x8000) + maj_ver |= 0x0008; + + snprintf(bts_scr_name, sizeof(bts_scr_name), + "ti-connectivity/TIInit_%d.%d.%d.bts", + chip, maj_ver, min_ver); + + err = request_firmware(&fw, bts_scr_name, &lldev->serdev->dev); + if (err || !fw->data || !fw->size) { + bt_dev_err(lldev->hu.hdev, "request_firmware failed(errno %d) for %s", + err, bts_scr_name); + return -EINVAL; + } + ptr = (void *)fw->data; + len = fw->size; + /* bts_header to remove out magic number and + * version + */ + ptr += sizeof(struct bts_header); + len -= sizeof(struct bts_header); + + while (len > 0 && ptr) { + bt_dev_dbg(lldev->hu.hdev, " action size %d, type %d ", + ((struct bts_action *)ptr)->size, + ((struct bts_action *)ptr)->type); + + action_ptr = &(((struct bts_action *)ptr)->data[0]); + + switch (((struct bts_action *)ptr)->type) { + case ACTION_SEND_COMMAND: /* action send */ + bt_dev_dbg(lldev->hu.hdev, "S"); + cmd = (struct hci_command *)action_ptr; + if (cmd->opcode == 0xff36) { + /* ignore remote change + * baud rate HCI VS command */ + bt_dev_warn(lldev->hu.hdev, "change remote baud rate command in firmware"); + break; + } + if (cmd->prefix != 1) + bt_dev_dbg(lldev->hu.hdev, "command type %d\n", cmd->prefix); + + skb = __hci_cmd_sync(lldev->hu.hdev, cmd->opcode, cmd->plen, &cmd->speed, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(lldev->hu.hdev, "send command failed\n"); + goto out_rel_fw; + } + kfree_skb(skb); + break; + case ACTION_WAIT_EVENT: /* wait */ + /* no need to wait as command was synchronous */ + bt_dev_dbg(lldev->hu.hdev, "W"); + break; + case ACTION_DELAY: /* sleep */ + bt_dev_info(lldev->hu.hdev, "sleep command in scr"); + mdelay(((struct bts_action_delay *)action_ptr)->msec); + break; + } + len -= (sizeof(struct bts_action) + + ((struct bts_action *)ptr)->size); + ptr += sizeof(struct bts_action) + + ((struct bts_action *)ptr)->size; + } + +out_rel_fw: + /* fw download complete */ + release_firmware(fw); + return err; +} + +static int ll_setup(struct hci_uart *hu) +{ + int err, retry = 3; + struct ll_device *lldev; + struct serdev_device *serdev = hu->serdev; + u32 speed; + + if (!serdev) + return 0; + + lldev = serdev_device_get_drvdata(serdev); + + serdev_device_set_flow_control(serdev, true); + + do { + /* Configure BT_EN to HIGH state */ + gpiod_set_value_cansleep(lldev->enable_gpio, 0); + msleep(5); + gpiod_set_value_cansleep(lldev->enable_gpio, 1); + msleep(100); + + err = download_firmware(lldev); + if (!err) + break; + + /* Toggle BT_EN and retry */ + bt_dev_err(hu->hdev, "download firmware failed, retrying..."); + } while (retry--); + + if (err) + return err; + + /* Operational speed if any */ + if (hu->oper_speed) + speed = hu->oper_speed; + else if (hu->proto->oper_speed) + speed = hu->proto->oper_speed; + else + speed = 0; + + if (speed) { + struct sk_buff *skb = __hci_cmd_sync(hu->hdev, 0xff36, sizeof(speed), &speed, HCI_INIT_TIMEOUT); + if (!IS_ERR(skb)) { + kfree_skb(skb); + serdev_device_set_baudrate(serdev, speed); + } + } + + return 0; +} + +static const struct hci_uart_proto llp; + +static int hci_ti_probe(struct serdev_device *serdev) +{ + struct hci_uart *hu; + struct ll_device *lldev; + u32 max_speed = 3000000; + + lldev = devm_kzalloc(&serdev->dev, sizeof(struct ll_device), GFP_KERNEL); + if (!lldev) + return -ENOMEM; + hu = &lldev->hu; + + serdev_device_set_drvdata(serdev, lldev); + lldev->serdev = hu->serdev = serdev; + + lldev->enable_gpio = devm_gpiod_get_optional(&serdev->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(lldev->enable_gpio)) + return PTR_ERR(lldev->enable_gpio); + + of_property_read_u32(serdev->dev.of_node, "max-speed", &max_speed); + hci_uart_set_speeds(hu, 115200, max_speed); + + return hci_uart_register_device(hu, &llp); +} + +static void hci_ti_remove(struct serdev_device *serdev) +{ + struct ll_device *lldev = serdev_device_get_drvdata(serdev); + struct hci_uart *hu = &lldev->hu; + struct hci_dev *hdev = hu->hdev; + + cancel_work_sync(&hu->write_work); + + hci_unregister_dev(hdev); + hci_free_dev(hdev); + hu->proto->close(hu); +} + +static const struct of_device_id hci_ti_of_match[] = { + { .compatible = "ti,wl1831-st" }, + { .compatible = "ti,wl1835-st" }, + { .compatible = "ti,wl1837-st" }, + {}, +}; +MODULE_DEVICE_TABLE(of, hci_ti_of_match); + +static struct serdev_device_driver hci_ti_drv = { + .driver = { + .name = "hci-ti", + .of_match_table = of_match_ptr(hci_ti_of_match), + }, + .probe = hci_ti_probe, + .remove = hci_ti_remove, +}; +#else +#define ll_setup NULL +#endif + static const struct hci_uart_proto llp = { .id = HCI_UART_LL, .name = "LL", + .setup = ll_setup, .open = ll_open, .close = ll_close, .recv = ll_recv, @@ -518,10 +774,14 @@ static const struct hci_uart_proto llp = { int __init ll_init(void) { + serdev_device_driver_register(&hci_ti_drv); + return hci_uart_register_proto(&llp); } int __exit ll_deinit(void) { + serdev_device_driver_unregister(&hci_ti_drv); + return hci_uart_unregister_proto(&llp); }