From: Ilya Faenson <ifaenson-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
To: Marcel Holtmann <marcel-kz+m5ild9QBg9hUCZPvPmw@public.gmane.org>
Cc: linux-bluetooth-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-spec-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Ilya Faenson <ifaenson-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Subject: [RFC v4 3/4] Broadcom Bluetooth protocol UART support
Date: Fri, 22 May 2015 16:10:19 -0400 [thread overview]
Message-ID: <1432325420-12782-4-git-send-email-ifaenson@broadcom.com> (raw)
In-Reply-To: <1432325420-12782-1-git-send-email-ifaenson-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Ilya Faenson <ifaenson-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
drivers/bluetooth/btbcm.c | 155 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 150 insertions(+), 5 deletions(-)
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index 4bba866..8b5530d 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -3,6 +3,7 @@
* Bluetooth support for Broadcom devices
*
* Copyright (C) 2015 Intel Corporation
+ * Copyright (C) 2015 Broadcom Corporation
*
*
* This program is free software; you can redistribute it and/or modify
@@ -23,14 +24,16 @@
#include <linux/module.h>
#include <linux/firmware.h>
+#include <linux/tty.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
+#include "hci_uart.h"
#include "btbcm.h"
-#define VERSION "0.1"
+#define VERSION "0.2"
#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
@@ -246,8 +249,10 @@ static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev)
static const struct {
u16 subver;
const char *name;
+ u32 baud_rate; /* operational baud rate */
} bcm_uart_subver_table[] = {
- { 0x410e, "BCM43341B0" }, /* 002.001.014 */
+ { 0x410e, "BCM43341B0", 3000000}, /* 002.001.014 */
+ { 0x610c, "BCM4354_003.001.012.0306.0659", 3000000}, /* 003.001.012 */
{ }
};
@@ -268,6 +273,127 @@ static const struct {
{ }
};
+/*
+ * Set the UART into the defaults
+ */
+int btbcm_init_uart(struct hci_uart *hu)
+{
+ struct tty_struct *tty = hu->tty;
+ struct ktermios ktermios;
+ int err, speed;
+
+ /* Flush the line discipline buffers and the TTY buffers */
+ if (tty->ldisc->ops->flush_buffer)
+ tty->ldisc->ops->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
+
+
+ /* Init UART to default settings */
+ 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 | CBAUD);
+ ktermios.c_cflag |= CS8;
+ ktermios.c_cflag |= CRTSCTS;
+ ktermios.c_cflag |= B115200;
+ ktermios.c_ispeed = 115200;
+ ktermios.c_ospeed = 115200;
+ err = tty_set_termios(tty, &ktermios);
+ if (err) {
+ BT_DBG("init_uart set_termios failure %d", err);
+ return err;
+ }
+
+ speed = tty_get_baud_rate(tty);
+
+ BT_DBG("init_uart set_termios completed, spd %d", speed);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btbcm_init_uart);
+
+/*
+ * Set the baud rate on the UART and the device
+ */
+int btbcm_set_baud_rate(struct hci_uart *hu, int baud_rate)
+{
+ struct tty_struct *tty = hu->tty;
+ struct ktermios ktermios;
+ int status, speed, cflag;
+ struct sk_buff *skb;
+ u8 enable = 0x01;
+ u8 baud_rate_vsc_pars[] = {0, 0, 0, 0x10, 0x0e, 0};
+
+ /* If the baud rate is higher than 3000000, change the clock */
+ if (baud_rate > 3000000) {
+ skb = __hci_cmd_sync(hu->hdev, 0xfc45, 1, &enable,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ status = PTR_ERR(skb);
+ return status;
+ }
+
+ kfree_skb(skb);
+ BT_DBG("set_baud_rate write UART 48 MHz VSC succeeded");
+ }
+
+ /* Now let the device know about the rate change */
+ put_unaligned_le32((u32)baud_rate, &baud_rate_vsc_pars[2]);
+ skb = __hci_cmd_sync(hu->hdev, 0xfc18, sizeof(baud_rate_vsc_pars),
+ baud_rate_vsc_pars, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ status = PTR_ERR(skb);
+ BT_ERR("set_baud_rate VSC failed (%d)", status);
+ return status;
+ }
+
+ kfree_skb(skb);
+ BT_DBG("set_baud_rate VSC succeeded");
+
+ /* Set UART into this rate as well */
+ ktermios = tty->termios;
+ BT_DBG("set_baud_rate start flags c_o %x c_l %x c_c %x spd %d/%d",
+ ktermios.c_oflag, ktermios.c_lflag, ktermios.c_cflag,
+ ktermios.c_ispeed, ktermios.c_ospeed);
+ switch (baud_rate) {
+ case 115200:
+ cflag |= B115200; break;
+ case 921600:
+ cflag |= B921600; break;
+ case 3000000:
+ cflag |= B3000000; break;
+ case 3500000:
+ cflag |= B3500000; break;
+ case 4000000:
+ cflag |= B4000000; break;
+ default:
+ BT_DBG("set_baud_rate unknown rate %d", baud_rate);
+ return -EINVAL;
+ }
+
+ ktermios.c_cflag &= ~CBAUD;
+ ktermios.c_cflag |= cflag;
+ ktermios.c_ispeed = baud_rate;
+ ktermios.c_ospeed = baud_rate;
+ status = tty_set_termios(tty, &ktermios);
+ if (status) {
+ BT_DBG("set_baud_rate set_termios failure %d", status);
+ return status;
+ }
+
+ speed = tty_get_baud_rate(tty);
+ BT_DBG("set_baud_rate set_termios completed, spd %d", speed);
+ ktermios = tty->termios;
+ BT_DBG("set_baud_rate flags c_o %x c_l %x c_c %x spd %d/%d",
+ ktermios.c_oflag, ktermios.c_lflag, ktermios.c_cflag,
+ ktermios.c_ispeed, ktermios.c_ospeed);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btbcm_set_baud_rate);
+
int btbcm_setup_patchram(struct hci_dev *hdev)
{
char fw_name[64];
@@ -275,7 +401,8 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
const char *hw_name = NULL;
struct sk_buff *skb;
struct hci_rp_read_local_version *ver;
- int i, err;
+ int i, err, is_uart = false;
+ struct hci_uart *hu = hci_get_drvdata(hdev);
/* Reset */
err = btbcm_reset(hdev);
@@ -297,14 +424,18 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
if (IS_ERR(skb))
return PTR_ERR(skb);
- BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
+ BT_INFO("%s: BCM: chip id %u, rev 0x%x subver 0x%x",
+ hdev->name, skb->data[1], rev, subver);
kfree_skb(skb);
switch ((rev & 0xf000) >> 12) {
case 0:
+ case 1:
for (i = 0; bcm_uart_subver_table[i].name; i++) {
if (subver == bcm_uart_subver_table[i].subver) {
hw_name = bcm_uart_subver_table[i].name;
+ BT_INFO("UART firmware found: %s", hw_name);
+ is_uart = true;
break;
}
}
@@ -312,7 +443,7 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
snprintf(fw_name, sizeof(fw_name), "brcm/%s.hcd",
hw_name ? : "BCM");
break;
- case 1:
+
case 2:
/* Read USB Product Info */
skb = btbcm_read_usb_product(hdev);
@@ -345,11 +476,25 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
if (err == -ENOENT)
return 0;
+ /* Once the patch is downloaded, the device is back at default rate */
+ if (is_uart) {
+ err = btbcm_init_uart(hu);
+ if (err)
+ return 0;
+ }
+
/* Reset */
err = btbcm_reset(hdev);
if (err)
return err;
+ if (is_uart) {
+ err = btbcm_set_baud_rate(hu,
+ bcm_uart_subver_table[i].baud_rate);
+ if (err)
+ return 0;
+ }
+
/* Read Local Version Info */
skb = btbcm_read_local_version(hdev);
if (IS_ERR(skb))
--
1.9.1
next prev parent reply other threads:[~2015-05-22 20:10 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-22 20:10 [RFC v4 0/4] Broadcom Bluetooth UART device driver Ilya Faenson
[not found] ` <1432325420-12782-1-git-send-email-ifaenson-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2015-05-22 20:10 ` [RFC v4 1/4] Broadcom Bluetooth UART Device Tree bindings Ilya Faenson
[not found] ` <1432325420-12782-2-git-send-email-ifaenson-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2015-06-02 0:18 ` Rob Herring
[not found] ` <CAL_JsqLO+g56KYUocpWLpz4dDTP0fEXTa4RjJzeRsPvYjCyF4A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-06-02 12:20 ` Ilya Faenson
[not found] ` <E0D3336E15B58B4294723AC879BA5E9425D49D-Wwdb2uEOBX8N93KskqRXH71+IgudQmzARxWJa1zDYLQ@public.gmane.org>
2015-06-02 15:34 ` Rob Herring
2015-05-22 20:10 ` [RFC v4 2/4] Broadcom Bluetooth UART Platform Driver Ilya Faenson
2015-05-22 20:10 ` Ilya Faenson [this message]
2015-05-22 20:10 ` [RFC v4 4/4] BlueZ Broadcom UART Protocol Ilya Faenson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1432325420-12782-4-git-send-email-ifaenson@broadcom.com \
--to=ifaenson-dy08kvg/lbpwk0htik3j/w@public.gmane.org \
--cc=devicetree-spec-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-bluetooth-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=marcel-kz+m5ild9QBg9hUCZPvPmw@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).