xref: /openbmc/linux/drivers/bluetooth/btbcm.c (revision fec0de23)
14fba30f0SMarcel Holtmann /*
24fba30f0SMarcel Holtmann  *
34fba30f0SMarcel Holtmann  *  Bluetooth support for Broadcom devices
44fba30f0SMarcel Holtmann  *
54fba30f0SMarcel Holtmann  *  Copyright (C) 2015  Intel Corporation
64fba30f0SMarcel Holtmann  *
74fba30f0SMarcel Holtmann  *
84fba30f0SMarcel Holtmann  *  This program is free software; you can redistribute it and/or modify
94fba30f0SMarcel Holtmann  *  it under the terms of the GNU General Public License as published by
104fba30f0SMarcel Holtmann  *  the Free Software Foundation; either version 2 of the License, or
114fba30f0SMarcel Holtmann  *  (at your option) any later version.
124fba30f0SMarcel Holtmann  *
134fba30f0SMarcel Holtmann  *  This program is distributed in the hope that it will be useful,
144fba30f0SMarcel Holtmann  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
154fba30f0SMarcel Holtmann  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
164fba30f0SMarcel Holtmann  *  GNU General Public License for more details.
174fba30f0SMarcel Holtmann  *
184fba30f0SMarcel Holtmann  *  You should have received a copy of the GNU General Public License
194fba30f0SMarcel Holtmann  *  along with this program; if not, write to the Free Software
204fba30f0SMarcel Holtmann  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
214fba30f0SMarcel Holtmann  *
224fba30f0SMarcel Holtmann  */
234fba30f0SMarcel Holtmann 
244fba30f0SMarcel Holtmann #include <linux/module.h>
251c8ba6d0SMarcel Holtmann #include <linux/firmware.h>
261c8ba6d0SMarcel Holtmann #include <asm/unaligned.h>
274fba30f0SMarcel Holtmann 
284fba30f0SMarcel Holtmann #include <net/bluetooth/bluetooth.h>
294fba30f0SMarcel Holtmann #include <net/bluetooth/hci_core.h>
304fba30f0SMarcel Holtmann 
314fba30f0SMarcel Holtmann #include "btbcm.h"
324fba30f0SMarcel Holtmann 
334fba30f0SMarcel Holtmann #define VERSION "0.1"
344fba30f0SMarcel Holtmann 
354fba30f0SMarcel Holtmann #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
36a8f3b941SFrederic Danis #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
374a546ec3SFrederic Danis #define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}})
384fba30f0SMarcel Holtmann 
394fba30f0SMarcel Holtmann int btbcm_check_bdaddr(struct hci_dev *hdev)
404fba30f0SMarcel Holtmann {
414fba30f0SMarcel Holtmann 	struct hci_rp_read_bd_addr *bda;
424fba30f0SMarcel Holtmann 	struct sk_buff *skb;
434fba30f0SMarcel Holtmann 
444fba30f0SMarcel Holtmann 	skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,
454fba30f0SMarcel Holtmann 			     HCI_INIT_TIMEOUT);
464fba30f0SMarcel Holtmann 	if (IS_ERR(skb)) {
474fba30f0SMarcel Holtmann 		int err = PTR_ERR(skb);
482064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Reading device address failed (%d)", err);
494fba30f0SMarcel Holtmann 		return err;
504fba30f0SMarcel Holtmann 	}
514fba30f0SMarcel Holtmann 
524fba30f0SMarcel Holtmann 	if (skb->len != sizeof(*bda)) {
532064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Device address length mismatch");
544fba30f0SMarcel Holtmann 		kfree_skb(skb);
554fba30f0SMarcel Holtmann 		return -EIO;
564fba30f0SMarcel Holtmann 	}
574fba30f0SMarcel Holtmann 
584fba30f0SMarcel Holtmann 	bda = (struct hci_rp_read_bd_addr *)skb->data;
594fba30f0SMarcel Holtmann 
60a8f3b941SFrederic Danis 	/* Check if the address indicates a controller with either an
61a8f3b941SFrederic Danis 	 * invalid or default address. In both cases the device needs
62a8f3b941SFrederic Danis 	 * to be marked as not having a valid address.
63a8f3b941SFrederic Danis 	 *
64a8f3b941SFrederic Danis 	 * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller
654fba30f0SMarcel Holtmann 	 * with no configured address.
66a8f3b941SFrederic Danis 	 *
67a8f3b941SFrederic Danis 	 * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller
68a8f3b941SFrederic Danis 	 * with waiting for configuration state.
694a546ec3SFrederic Danis 	 *
704a546ec3SFrederic Danis 	 * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller
714a546ec3SFrederic Danis 	 * with waiting for configuration state.
724fba30f0SMarcel Holtmann 	 */
73a8f3b941SFrederic Danis 	if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) ||
744a546ec3SFrederic Danis 	    !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) ||
754a546ec3SFrederic Danis 	    !bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) {
762064ee33SMarcel Holtmann 		bt_dev_info(hdev, "BCM: Using default device address (%pMR)",
772064ee33SMarcel Holtmann 			    &bda->bdaddr);
784fba30f0SMarcel Holtmann 		set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
794fba30f0SMarcel Holtmann 	}
804fba30f0SMarcel Holtmann 
814fba30f0SMarcel Holtmann 	kfree_skb(skb);
824fba30f0SMarcel Holtmann 
834fba30f0SMarcel Holtmann 	return 0;
844fba30f0SMarcel Holtmann }
854fba30f0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_check_bdaddr);
864fba30f0SMarcel Holtmann 
874fba30f0SMarcel Holtmann int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
884fba30f0SMarcel Holtmann {
894fba30f0SMarcel Holtmann 	struct sk_buff *skb;
904fba30f0SMarcel Holtmann 	int err;
914fba30f0SMarcel Holtmann 
924fba30f0SMarcel Holtmann 	skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT);
934fba30f0SMarcel Holtmann 	if (IS_ERR(skb)) {
944fba30f0SMarcel Holtmann 		err = PTR_ERR(skb);
952064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Change address command failed (%d)", err);
964fba30f0SMarcel Holtmann 		return err;
974fba30f0SMarcel Holtmann 	}
984fba30f0SMarcel Holtmann 	kfree_skb(skb);
994fba30f0SMarcel Holtmann 
1004fba30f0SMarcel Holtmann 	return 0;
1014fba30f0SMarcel Holtmann }
1024fba30f0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_set_bdaddr);
1034fba30f0SMarcel Holtmann 
10418aeb444SFrederic Danis int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw)
10550862ee5SMarcel Holtmann {
10650862ee5SMarcel Holtmann 	const struct hci_command_hdr *cmd;
10750862ee5SMarcel Holtmann 	const u8 *fw_ptr;
10850862ee5SMarcel Holtmann 	size_t fw_size;
10950862ee5SMarcel Holtmann 	struct sk_buff *skb;
11050862ee5SMarcel Holtmann 	u16 opcode;
11118aeb444SFrederic Danis 	int err = 0;
11250862ee5SMarcel Holtmann 
11350862ee5SMarcel Holtmann 	/* Start Download */
11450862ee5SMarcel Holtmann 	skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
11550862ee5SMarcel Holtmann 	if (IS_ERR(skb)) {
11650862ee5SMarcel Holtmann 		err = PTR_ERR(skb);
1172064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Download Minidrv command failed (%d)",
1182064ee33SMarcel Holtmann 			   err);
11950862ee5SMarcel Holtmann 		goto done;
12050862ee5SMarcel Holtmann 	}
12150862ee5SMarcel Holtmann 	kfree_skb(skb);
12250862ee5SMarcel Holtmann 
12350862ee5SMarcel Holtmann 	/* 50 msec delay after Download Minidrv completes */
12450862ee5SMarcel Holtmann 	msleep(50);
12550862ee5SMarcel Holtmann 
12650862ee5SMarcel Holtmann 	fw_ptr = fw->data;
12750862ee5SMarcel Holtmann 	fw_size = fw->size;
12850862ee5SMarcel Holtmann 
12950862ee5SMarcel Holtmann 	while (fw_size >= sizeof(*cmd)) {
13050862ee5SMarcel Holtmann 		const u8 *cmd_param;
13150862ee5SMarcel Holtmann 
13250862ee5SMarcel Holtmann 		cmd = (struct hci_command_hdr *)fw_ptr;
13350862ee5SMarcel Holtmann 		fw_ptr += sizeof(*cmd);
13450862ee5SMarcel Holtmann 		fw_size -= sizeof(*cmd);
13550862ee5SMarcel Holtmann 
13650862ee5SMarcel Holtmann 		if (fw_size < cmd->plen) {
1372064ee33SMarcel Holtmann 			bt_dev_err(hdev, "BCM: Patch is corrupted");
13850862ee5SMarcel Holtmann 			err = -EINVAL;
13950862ee5SMarcel Holtmann 			goto done;
14050862ee5SMarcel Holtmann 		}
14150862ee5SMarcel Holtmann 
14250862ee5SMarcel Holtmann 		cmd_param = fw_ptr;
14350862ee5SMarcel Holtmann 		fw_ptr += cmd->plen;
14450862ee5SMarcel Holtmann 		fw_size -= cmd->plen;
14550862ee5SMarcel Holtmann 
14650862ee5SMarcel Holtmann 		opcode = le16_to_cpu(cmd->opcode);
14750862ee5SMarcel Holtmann 
14850862ee5SMarcel Holtmann 		skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param,
14950862ee5SMarcel Holtmann 				     HCI_INIT_TIMEOUT);
15050862ee5SMarcel Holtmann 		if (IS_ERR(skb)) {
15150862ee5SMarcel Holtmann 			err = PTR_ERR(skb);
1522064ee33SMarcel Holtmann 			bt_dev_err(hdev, "BCM: Patch command %04x failed (%d)",
1532064ee33SMarcel Holtmann 				   opcode, err);
15450862ee5SMarcel Holtmann 			goto done;
15550862ee5SMarcel Holtmann 		}
15650862ee5SMarcel Holtmann 		kfree_skb(skb);
15750862ee5SMarcel Holtmann 	}
15850862ee5SMarcel Holtmann 
15950862ee5SMarcel Holtmann 	/* 250 msec delay after Launch Ram completes */
16050862ee5SMarcel Holtmann 	msleep(250);
16150862ee5SMarcel Holtmann 
16250862ee5SMarcel Holtmann done:
16350862ee5SMarcel Holtmann 	return err;
16450862ee5SMarcel Holtmann }
16550862ee5SMarcel Holtmann EXPORT_SYMBOL(btbcm_patchram);
16650862ee5SMarcel Holtmann 
1671c8ba6d0SMarcel Holtmann static int btbcm_reset(struct hci_dev *hdev)
1681c8ba6d0SMarcel Holtmann {
1691c8ba6d0SMarcel Holtmann 	struct sk_buff *skb;
1701c8ba6d0SMarcel Holtmann 
1711c8ba6d0SMarcel Holtmann 	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
1721c8ba6d0SMarcel Holtmann 	if (IS_ERR(skb)) {
1731c8ba6d0SMarcel Holtmann 		int err = PTR_ERR(skb);
1742064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Reset failed (%d)", err);
1751c8ba6d0SMarcel Holtmann 		return err;
1761c8ba6d0SMarcel Holtmann 	}
1771c8ba6d0SMarcel Holtmann 	kfree_skb(skb);
1781c8ba6d0SMarcel Holtmann 
1793af3a594SWen-chien Jesse Sung 	/* 100 msec delay for module to complete reset process */
1803af3a594SWen-chien Jesse Sung 	msleep(100);
1813af3a594SWen-chien Jesse Sung 
1821c8ba6d0SMarcel Holtmann 	return 0;
1831c8ba6d0SMarcel Holtmann }
1841c8ba6d0SMarcel Holtmann 
1859bc63ca0SMarcel Holtmann static struct sk_buff *btbcm_read_local_name(struct hci_dev *hdev)
1869bc63ca0SMarcel Holtmann {
1879bc63ca0SMarcel Holtmann 	struct sk_buff *skb;
1889bc63ca0SMarcel Holtmann 
1899bc63ca0SMarcel Holtmann 	skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL,
1909bc63ca0SMarcel Holtmann 			     HCI_INIT_TIMEOUT);
1919bc63ca0SMarcel Holtmann 	if (IS_ERR(skb)) {
1922064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Reading local name failed (%ld)",
1932064ee33SMarcel Holtmann 			   PTR_ERR(skb));
1949bc63ca0SMarcel Holtmann 		return skb;
1959bc63ca0SMarcel Holtmann 	}
1969bc63ca0SMarcel Holtmann 
1979bc63ca0SMarcel Holtmann 	if (skb->len != sizeof(struct hci_rp_read_local_name)) {
1982064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Local name length mismatch");
1999bc63ca0SMarcel Holtmann 		kfree_skb(skb);
2009bc63ca0SMarcel Holtmann 		return ERR_PTR(-EIO);
2019bc63ca0SMarcel Holtmann 	}
2029bc63ca0SMarcel Holtmann 
2039bc63ca0SMarcel Holtmann 	return skb;
2049bc63ca0SMarcel Holtmann }
2059bc63ca0SMarcel Holtmann 
2061c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev)
2071c8ba6d0SMarcel Holtmann {
2081c8ba6d0SMarcel Holtmann 	struct sk_buff *skb;
2091c8ba6d0SMarcel Holtmann 
2101c8ba6d0SMarcel Holtmann 	skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
2111c8ba6d0SMarcel Holtmann 			     HCI_INIT_TIMEOUT);
2121c8ba6d0SMarcel Holtmann 	if (IS_ERR(skb)) {
2132064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Reading local version info failed (%ld)",
2142064ee33SMarcel Holtmann 			   PTR_ERR(skb));
2151c8ba6d0SMarcel Holtmann 		return skb;
2161c8ba6d0SMarcel Holtmann 	}
2171c8ba6d0SMarcel Holtmann 
2181c8ba6d0SMarcel Holtmann 	if (skb->len != sizeof(struct hci_rp_read_local_version)) {
2192064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Local version length mismatch");
2201c8ba6d0SMarcel Holtmann 		kfree_skb(skb);
2211c8ba6d0SMarcel Holtmann 		return ERR_PTR(-EIO);
2221c8ba6d0SMarcel Holtmann 	}
2231c8ba6d0SMarcel Holtmann 
2241c8ba6d0SMarcel Holtmann 	return skb;
2251c8ba6d0SMarcel Holtmann }
2261c8ba6d0SMarcel Holtmann 
2271c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_verbose_config(struct hci_dev *hdev)
2281c8ba6d0SMarcel Holtmann {
2291c8ba6d0SMarcel Holtmann 	struct sk_buff *skb;
2301c8ba6d0SMarcel Holtmann 
2311c8ba6d0SMarcel Holtmann 	skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT);
2321c8ba6d0SMarcel Holtmann 	if (IS_ERR(skb)) {
2332064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Read verbose config info failed (%ld)",
2342064ee33SMarcel Holtmann 			   PTR_ERR(skb));
2351c8ba6d0SMarcel Holtmann 		return skb;
2361c8ba6d0SMarcel Holtmann 	}
2371c8ba6d0SMarcel Holtmann 
2381c8ba6d0SMarcel Holtmann 	if (skb->len != 7) {
2392064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Verbose config length mismatch");
2401c8ba6d0SMarcel Holtmann 		kfree_skb(skb);
2411c8ba6d0SMarcel Holtmann 		return ERR_PTR(-EIO);
2421c8ba6d0SMarcel Holtmann 	}
2431c8ba6d0SMarcel Holtmann 
2441c8ba6d0SMarcel Holtmann 	return skb;
2451c8ba6d0SMarcel Holtmann }
2461c8ba6d0SMarcel Holtmann 
2474284ecbeSMarcel Holtmann static struct sk_buff *btbcm_read_controller_features(struct hci_dev *hdev)
2484284ecbeSMarcel Holtmann {
2494284ecbeSMarcel Holtmann 	struct sk_buff *skb;
2504284ecbeSMarcel Holtmann 
2514284ecbeSMarcel Holtmann 	skb = __hci_cmd_sync(hdev, 0xfc6e, 0, NULL, HCI_INIT_TIMEOUT);
2524284ecbeSMarcel Holtmann 	if (IS_ERR(skb)) {
2532064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Read controller features failed (%ld)",
2542064ee33SMarcel Holtmann 			   PTR_ERR(skb));
2554284ecbeSMarcel Holtmann 		return skb;
2564284ecbeSMarcel Holtmann 	}
2574284ecbeSMarcel Holtmann 
2584284ecbeSMarcel Holtmann 	if (skb->len != 9) {
2592064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Controller features length mismatch");
2604284ecbeSMarcel Holtmann 		kfree_skb(skb);
2614284ecbeSMarcel Holtmann 		return ERR_PTR(-EIO);
2624284ecbeSMarcel Holtmann 	}
2634284ecbeSMarcel Holtmann 
2644284ecbeSMarcel Holtmann 	return skb;
2654284ecbeSMarcel Holtmann }
2664284ecbeSMarcel Holtmann 
2671c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev)
2681c8ba6d0SMarcel Holtmann {
2691c8ba6d0SMarcel Holtmann 	struct sk_buff *skb;
2701c8ba6d0SMarcel Holtmann 
2711c8ba6d0SMarcel Holtmann 	skb = __hci_cmd_sync(hdev, 0xfc5a, 0, NULL, HCI_INIT_TIMEOUT);
2721c8ba6d0SMarcel Holtmann 	if (IS_ERR(skb)) {
2732064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: Read USB product info failed (%ld)",
2742064ee33SMarcel Holtmann 			   PTR_ERR(skb));
2751c8ba6d0SMarcel Holtmann 		return skb;
2761c8ba6d0SMarcel Holtmann 	}
2771c8ba6d0SMarcel Holtmann 
2781c8ba6d0SMarcel Holtmann 	if (skb->len != 5) {
2792064ee33SMarcel Holtmann 		bt_dev_err(hdev, "BCM: USB product length mismatch");
2801c8ba6d0SMarcel Holtmann 		kfree_skb(skb);
2811c8ba6d0SMarcel Holtmann 		return ERR_PTR(-EIO);
2821c8ba6d0SMarcel Holtmann 	}
2831c8ba6d0SMarcel Holtmann 
2841c8ba6d0SMarcel Holtmann 	return skb;
2851c8ba6d0SMarcel Holtmann }
2861c8ba6d0SMarcel Holtmann 
287e76dc1ddSMarcel Holtmann static int btbcm_read_info(struct hci_dev *hdev)
288e76dc1ddSMarcel Holtmann {
289e76dc1ddSMarcel Holtmann 	struct sk_buff *skb;
290e76dc1ddSMarcel Holtmann 
291e76dc1ddSMarcel Holtmann 	/* Read Verbose Config Version Info */
292e76dc1ddSMarcel Holtmann 	skb = btbcm_read_verbose_config(hdev);
293e76dc1ddSMarcel Holtmann 	if (IS_ERR(skb))
294e76dc1ddSMarcel Holtmann 		return PTR_ERR(skb);
295e76dc1ddSMarcel Holtmann 
2962064ee33SMarcel Holtmann 	bt_dev_info(hdev, "BCM: chip id %u", skb->data[1]);
297e76dc1ddSMarcel Holtmann 	kfree_skb(skb);
298e76dc1ddSMarcel Holtmann 
299e76dc1ddSMarcel Holtmann 	/* Read Controller Features */
300e76dc1ddSMarcel Holtmann 	skb = btbcm_read_controller_features(hdev);
301e76dc1ddSMarcel Holtmann 	if (IS_ERR(skb))
302e76dc1ddSMarcel Holtmann 		return PTR_ERR(skb);
303e76dc1ddSMarcel Holtmann 
3042064ee33SMarcel Holtmann 	bt_dev_info(hdev, "BCM: features 0x%2.2x", skb->data[1]);
305e76dc1ddSMarcel Holtmann 	kfree_skb(skb);
306e76dc1ddSMarcel Holtmann 
307e76dc1ddSMarcel Holtmann 	/* Read Local Name */
308e76dc1ddSMarcel Holtmann 	skb = btbcm_read_local_name(hdev);
309e76dc1ddSMarcel Holtmann 	if (IS_ERR(skb))
310e76dc1ddSMarcel Holtmann 		return PTR_ERR(skb);
311e76dc1ddSMarcel Holtmann 
3122064ee33SMarcel Holtmann 	bt_dev_info(hdev, "%s", (char *)(skb->data + 1));
313e76dc1ddSMarcel Holtmann 	kfree_skb(skb);
314e76dc1ddSMarcel Holtmann 
315e76dc1ddSMarcel Holtmann 	return 0;
316e76dc1ddSMarcel Holtmann }
317e76dc1ddSMarcel Holtmann 
318f7328381SHans de Goede struct bcm_subver_table {
3191c8ba6d0SMarcel Holtmann 	u16 subver;
3201c8ba6d0SMarcel Holtmann 	const char *name;
321f7328381SHans de Goede };
322f7328381SHans de Goede 
323f7328381SHans de Goede static const struct bcm_subver_table bcm_uart_subver_table[] = {
3244a546ec3SFrederic Danis 	{ 0x4103, "BCM4330B1"	},	/* 002.001.003 */
3259a0bb57dSMarcel Holtmann 	{ 0x410e, "BCM43341B0"	},	/* 002.001.014 */
326a8f3b941SFrederic Danis 	{ 0x4406, "BCM4324B3"	},	/* 002.004.006 */
32740db5f0eSIlya Faenson 	{ 0x610c, "BCM4354"	},	/* 003.001.012 */
328d456f678SJörg Krause 	{ 0x2122, "BCM4343A0"	},	/* 001.001.034 */
329feb16722SIan Molton 	{ 0x2209, "BCM43430A1"  },	/* 001.002.009 */
33018a39b9aSIan W MORRISON 	{ 0x6119, "BCM4345C0"	},	/* 003.001.025 */
331b133e0c4SHans de Goede 	{ 0x230f, "BCM4356A2"	},	/* 001.003.015 */
3329a0bb57dSMarcel Holtmann 	{ }
3339a0bb57dSMarcel Holtmann };
3349a0bb57dSMarcel Holtmann 
335fec0de23SHans de Goede static const struct bcm_subver_table bcm_usb_subver_table[] = {
336fec0de23SHans de Goede 	{ 0x210b, "BCM43142A0"	},	/* 001.001.011 */
337fec0de23SHans de Goede 	{ 0x2112, "BCM4314A0"	},	/* 001.001.018 */
338fec0de23SHans de Goede 	{ 0x2118, "BCM20702A0"	},	/* 001.001.024 */
339fec0de23SHans de Goede 	{ 0x2126, "BCM4335A0"	},	/* 001.001.038 */
340fec0de23SHans de Goede 	{ 0x220e, "BCM20702A1"	},	/* 001.002.014 */
341fec0de23SHans de Goede 	{ 0x230f, "BCM4354A2"	},	/* 001.003.015 */
342fec0de23SHans de Goede 	{ 0x4106, "BCM4335B0"	},	/* 002.001.006 */
343fec0de23SHans de Goede 	{ 0x410e, "BCM20702B0"	},	/* 002.001.014 */
344fec0de23SHans de Goede 	{ 0x6109, "BCM4335C0"	},	/* 003.001.009 */
345fec0de23SHans de Goede 	{ 0x610c, "BCM4354"	},	/* 003.001.012 */
346fec0de23SHans de Goede 	{ }
347fec0de23SHans de Goede };
348fec0de23SHans de Goede 
34975e167e6SFrederic Danis int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len)
35075e167e6SFrederic Danis {
351fec0de23SHans de Goede 	u16 subver, rev, pid, vid;
35275e167e6SFrederic Danis 	const char *hw_name = NULL;
35375e167e6SFrederic Danis 	struct sk_buff *skb;
35475e167e6SFrederic Danis 	struct hci_rp_read_local_version *ver;
355fec0de23SHans de Goede 	const struct bcm_subver_table *bcm_subver_table;
35675e167e6SFrederic Danis 	int i, err;
35775e167e6SFrederic Danis 
35875e167e6SFrederic Danis 	/* Reset */
35975e167e6SFrederic Danis 	err = btbcm_reset(hdev);
36075e167e6SFrederic Danis 	if (err)
36175e167e6SFrederic Danis 		return err;
36275e167e6SFrederic Danis 
36375e167e6SFrederic Danis 	/* Read Local Version Info */
36475e167e6SFrederic Danis 	skb = btbcm_read_local_version(hdev);
36575e167e6SFrederic Danis 	if (IS_ERR(skb))
36675e167e6SFrederic Danis 		return PTR_ERR(skb);
36775e167e6SFrederic Danis 
36875e167e6SFrederic Danis 	ver = (struct hci_rp_read_local_version *)skb->data;
36975e167e6SFrederic Danis 	rev = le16_to_cpu(ver->hci_rev);
37075e167e6SFrederic Danis 	subver = le16_to_cpu(ver->lmp_subver);
37175e167e6SFrederic Danis 	kfree_skb(skb);
37275e167e6SFrederic Danis 
373e76dc1ddSMarcel Holtmann 	/* Read controller information */
374e76dc1ddSMarcel Holtmann 	err = btbcm_read_info(hdev);
375e76dc1ddSMarcel Holtmann 	if (err)
376e76dc1ddSMarcel Holtmann 		return err;
37775e167e6SFrederic Danis 
378fec0de23SHans de Goede 	/* Upper nibble of rev should be between 0 and 3? */
379fec0de23SHans de Goede 	if (((rev & 0xf000) >> 12) > 3)
380fec0de23SHans de Goede 		return 0;
381fec0de23SHans de Goede 
382fec0de23SHans de Goede 	bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table :
383fec0de23SHans de Goede 						    bcm_uart_subver_table;
384fec0de23SHans de Goede 
385fec0de23SHans de Goede 	for (i = 0; bcm_subver_table[i].name; i++) {
386fec0de23SHans de Goede 		if (subver == bcm_subver_table[i].subver) {
387fec0de23SHans de Goede 			hw_name = bcm_subver_table[i].name;
38875e167e6SFrederic Danis 			break;
38975e167e6SFrederic Danis 		}
39075e167e6SFrederic Danis 	}
39175e167e6SFrederic Danis 
392fec0de23SHans de Goede 	if (hdev->bus == HCI_USB) {
393fec0de23SHans de Goede 		/* Read USB Product Info */
394fec0de23SHans de Goede 		skb = btbcm_read_usb_product(hdev);
395fec0de23SHans de Goede 		if (IS_ERR(skb))
396fec0de23SHans de Goede 			return PTR_ERR(skb);
397fec0de23SHans de Goede 
398fec0de23SHans de Goede 		vid = get_unaligned_le16(skb->data + 1);
399fec0de23SHans de Goede 		pid = get_unaligned_le16(skb->data + 3);
400fec0de23SHans de Goede 		kfree_skb(skb);
401fec0de23SHans de Goede 
402fec0de23SHans de Goede 		snprintf(fw_name, len, "brcm/%s-%4.4x-%4.4x.hcd",
403fec0de23SHans de Goede 			 hw_name ? : "BCM", vid, pid);
404fec0de23SHans de Goede 	} else {
405fec0de23SHans de Goede 		snprintf(fw_name, len, "brcm/%s.hcd",
406fec0de23SHans de Goede 			 hw_name ? : "BCM");
40775e167e6SFrederic Danis 	}
40875e167e6SFrederic Danis 
4092064ee33SMarcel Holtmann 	bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u",
4108045ce21SMarcel Holtmann 		    hw_name ? : "BCM", (subver & 0xe000) >> 13,
41175e167e6SFrederic Danis 		    (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
41275e167e6SFrederic Danis 
41375e167e6SFrederic Danis 	return 0;
41475e167e6SFrederic Danis }
41575e167e6SFrederic Danis EXPORT_SYMBOL_GPL(btbcm_initialize);
41675e167e6SFrederic Danis 
41775e167e6SFrederic Danis int btbcm_finalize(struct hci_dev *hdev)
41875e167e6SFrederic Danis {
41975e167e6SFrederic Danis 	struct sk_buff *skb;
42075e167e6SFrederic Danis 	struct hci_rp_read_local_version *ver;
42175e167e6SFrederic Danis 	u16 subver, rev;
42275e167e6SFrederic Danis 	int err;
42375e167e6SFrederic Danis 
42475e167e6SFrederic Danis 	/* Reset */
42575e167e6SFrederic Danis 	err = btbcm_reset(hdev);
42675e167e6SFrederic Danis 	if (err)
42775e167e6SFrederic Danis 		return err;
42875e167e6SFrederic Danis 
42975e167e6SFrederic Danis 	/* Read Local Version Info */
43075e167e6SFrederic Danis 	skb = btbcm_read_local_version(hdev);
43175e167e6SFrederic Danis 	if (IS_ERR(skb))
43275e167e6SFrederic Danis 		return PTR_ERR(skb);
43375e167e6SFrederic Danis 
43475e167e6SFrederic Danis 	ver = (struct hci_rp_read_local_version *)skb->data;
43575e167e6SFrederic Danis 	rev = le16_to_cpu(ver->hci_rev);
43675e167e6SFrederic Danis 	subver = le16_to_cpu(ver->lmp_subver);
43775e167e6SFrederic Danis 	kfree_skb(skb);
43875e167e6SFrederic Danis 
4392064ee33SMarcel Holtmann 	bt_dev_info(hdev, "BCM (%3.3u.%3.3u.%3.3u) build %4.4u",
4408045ce21SMarcel Holtmann 		    (subver & 0xe000) >> 13, (subver & 0x1f00) >> 8,
44175e167e6SFrederic Danis 		    (subver & 0x00ff), rev & 0x0fff);
44275e167e6SFrederic Danis 
44375e167e6SFrederic Danis 	btbcm_check_bdaddr(hdev);
44475e167e6SFrederic Danis 
44575e167e6SFrederic Danis 	set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
44675e167e6SFrederic Danis 
44775e167e6SFrederic Danis 	return 0;
44875e167e6SFrederic Danis }
44975e167e6SFrederic Danis EXPORT_SYMBOL_GPL(btbcm_finalize);
45075e167e6SFrederic Danis 
4511c8ba6d0SMarcel Holtmann int btbcm_setup_patchram(struct hci_dev *hdev)
4521c8ba6d0SMarcel Holtmann {
4531c8ba6d0SMarcel Holtmann 	char fw_name[64];
45418aeb444SFrederic Danis 	const struct firmware *fw;
45550862ee5SMarcel Holtmann 	u16 subver, rev, pid, vid;
4561c8ba6d0SMarcel Holtmann 	const char *hw_name = NULL;
4571c8ba6d0SMarcel Holtmann 	struct sk_buff *skb;
4581c8ba6d0SMarcel Holtmann 	struct hci_rp_read_local_version *ver;
459f7328381SHans de Goede 	const struct bcm_subver_table *bcm_subver_table;
4601c8ba6d0SMarcel Holtmann 	int i, err;
4611c8ba6d0SMarcel Holtmann 
4621c8ba6d0SMarcel Holtmann 	/* Reset */
4631c8ba6d0SMarcel Holtmann 	err = btbcm_reset(hdev);
4641c8ba6d0SMarcel Holtmann 	if (err)
4651c8ba6d0SMarcel Holtmann 		return err;
4661c8ba6d0SMarcel Holtmann 
4671c8ba6d0SMarcel Holtmann 	/* Read Local Version Info */
4681c8ba6d0SMarcel Holtmann 	skb = btbcm_read_local_version(hdev);
4691c8ba6d0SMarcel Holtmann 	if (IS_ERR(skb))
4701c8ba6d0SMarcel Holtmann 		return PTR_ERR(skb);
4711c8ba6d0SMarcel Holtmann 
4721c8ba6d0SMarcel Holtmann 	ver = (struct hci_rp_read_local_version *)skb->data;
4731c8ba6d0SMarcel Holtmann 	rev = le16_to_cpu(ver->hci_rev);
4741c8ba6d0SMarcel Holtmann 	subver = le16_to_cpu(ver->lmp_subver);
4751c8ba6d0SMarcel Holtmann 	kfree_skb(skb);
4761c8ba6d0SMarcel Holtmann 
477e76dc1ddSMarcel Holtmann 	/* Read controller information */
478e76dc1ddSMarcel Holtmann 	err = btbcm_read_info(hdev);
479e76dc1ddSMarcel Holtmann 	if (err)
480e76dc1ddSMarcel Holtmann 		return err;
4819bc63ca0SMarcel Holtmann 
4821b2525c0SHans de Goede 	/* Upper nibble of rev should be between 0 and 3? */
4831b2525c0SHans de Goede 	if (((rev & 0xf000) >> 12) > 3)
4841b2525c0SHans de Goede 		return 0;
4851b2525c0SHans de Goede 
486f7328381SHans de Goede 	bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table :
487f7328381SHans de Goede 						    bcm_uart_subver_table;
488f7328381SHans de Goede 
489f7328381SHans de Goede 	for (i = 0; bcm_subver_table[i].name; i++) {
490f7328381SHans de Goede 		if (subver == bcm_subver_table[i].subver) {
491f7328381SHans de Goede 			hw_name = bcm_subver_table[i].name;
4929a0bb57dSMarcel Holtmann 			break;
4939a0bb57dSMarcel Holtmann 		}
4949a0bb57dSMarcel Holtmann 	}
4959a0bb57dSMarcel Holtmann 
496f7328381SHans de Goede 	if (hdev->bus == HCI_USB) {
4971c8ba6d0SMarcel Holtmann 		/* Read USB Product Info */
4981c8ba6d0SMarcel Holtmann 		skb = btbcm_read_usb_product(hdev);
4991c8ba6d0SMarcel Holtmann 		if (IS_ERR(skb))
5001c8ba6d0SMarcel Holtmann 			return PTR_ERR(skb);
5011c8ba6d0SMarcel Holtmann 
5021c8ba6d0SMarcel Holtmann 		vid = get_unaligned_le16(skb->data + 1);
5031c8ba6d0SMarcel Holtmann 		pid = get_unaligned_le16(skb->data + 3);
5041c8ba6d0SMarcel Holtmann 		kfree_skb(skb);
5051c8ba6d0SMarcel Holtmann 
5069a0bb57dSMarcel Holtmann 		snprintf(fw_name, sizeof(fw_name), "brcm/%s-%4.4x-%4.4x.hcd",
5079a0bb57dSMarcel Holtmann 			 hw_name ? : "BCM", vid, pid);
508f7328381SHans de Goede 	} else {
509f7328381SHans de Goede 		snprintf(fw_name, sizeof(fw_name), "brcm/%s.hcd",
510f7328381SHans de Goede 			 hw_name ? : "BCM");
5119a0bb57dSMarcel Holtmann 	}
5129a0bb57dSMarcel Holtmann 
5132064ee33SMarcel Holtmann 	bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u",
5148045ce21SMarcel Holtmann 		    hw_name ? : "BCM", (subver & 0xe000) >> 13,
5151c8ba6d0SMarcel Holtmann 		    (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
5161c8ba6d0SMarcel Holtmann 
51718aeb444SFrederic Danis 	err = request_firmware(&fw, fw_name, &hdev->dev);
51818aeb444SFrederic Danis 	if (err < 0) {
5192064ee33SMarcel Holtmann 		bt_dev_info(hdev, "BCM: Patch %s not found", fw_name);
520ad750fa1SPetri Gynther 		goto done;
52118aeb444SFrederic Danis 	}
52218aeb444SFrederic Danis 
52318aeb444SFrederic Danis 	btbcm_patchram(hdev, fw);
52418aeb444SFrederic Danis 
52518aeb444SFrederic Danis 	release_firmware(fw);
5261c8ba6d0SMarcel Holtmann 
5271c8ba6d0SMarcel Holtmann 	/* Reset */
5281c8ba6d0SMarcel Holtmann 	err = btbcm_reset(hdev);
5291c8ba6d0SMarcel Holtmann 	if (err)
53050862ee5SMarcel Holtmann 		return err;
5311c8ba6d0SMarcel Holtmann 
5321c8ba6d0SMarcel Holtmann 	/* Read Local Version Info */
5331c8ba6d0SMarcel Holtmann 	skb = btbcm_read_local_version(hdev);
53450862ee5SMarcel Holtmann 	if (IS_ERR(skb))
53550862ee5SMarcel Holtmann 		return PTR_ERR(skb);
5361c8ba6d0SMarcel Holtmann 
5371c8ba6d0SMarcel Holtmann 	ver = (struct hci_rp_read_local_version *)skb->data;
5381c8ba6d0SMarcel Holtmann 	rev = le16_to_cpu(ver->hci_rev);
5391c8ba6d0SMarcel Holtmann 	subver = le16_to_cpu(ver->lmp_subver);
5401c8ba6d0SMarcel Holtmann 	kfree_skb(skb);
5411c8ba6d0SMarcel Holtmann 
5422064ee33SMarcel Holtmann 	bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u",
5438045ce21SMarcel Holtmann 		    hw_name ? : "BCM", (subver & 0xe000) >> 13,
5441c8ba6d0SMarcel Holtmann 		    (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
5451c8ba6d0SMarcel Holtmann 
5469bc63ca0SMarcel Holtmann 	/* Read Local Name */
5479bc63ca0SMarcel Holtmann 	skb = btbcm_read_local_name(hdev);
5489bc63ca0SMarcel Holtmann 	if (IS_ERR(skb))
5499bc63ca0SMarcel Holtmann 		return PTR_ERR(skb);
5509bc63ca0SMarcel Holtmann 
5512064ee33SMarcel Holtmann 	bt_dev_info(hdev, "%s", (char *)(skb->data + 1));
5529bc63ca0SMarcel Holtmann 	kfree_skb(skb);
5539bc63ca0SMarcel Holtmann 
554ad750fa1SPetri Gynther done:
5551c8ba6d0SMarcel Holtmann 	btbcm_check_bdaddr(hdev);
5561c8ba6d0SMarcel Holtmann 
557941521e2SMarcel Holtmann 	set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
558941521e2SMarcel Holtmann 
55950862ee5SMarcel Holtmann 	return 0;
5601c8ba6d0SMarcel Holtmann }
5611c8ba6d0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_setup_patchram);
5621c8ba6d0SMarcel Holtmann 
5631c8ba6d0SMarcel Holtmann int btbcm_setup_apple(struct hci_dev *hdev)
5641c8ba6d0SMarcel Holtmann {
5651c8ba6d0SMarcel Holtmann 	struct sk_buff *skb;
566b224d3ffSMarcel Holtmann 	int err;
567b224d3ffSMarcel Holtmann 
568b224d3ffSMarcel Holtmann 	/* Reset */
569b224d3ffSMarcel Holtmann 	err = btbcm_reset(hdev);
570b224d3ffSMarcel Holtmann 	if (err)
571b224d3ffSMarcel Holtmann 		return err;
5721c8ba6d0SMarcel Holtmann 
5731c8ba6d0SMarcel Holtmann 	/* Read Verbose Config Version Info */
5741c8ba6d0SMarcel Holtmann 	skb = btbcm_read_verbose_config(hdev);
5757bee8b08SChris Mason 	if (!IS_ERR(skb)) {
5762064ee33SMarcel Holtmann 		bt_dev_info(hdev, "BCM: chip id %u build %4.4u",
577b224d3ffSMarcel Holtmann 			    skb->data[1], get_unaligned_le16(skb->data + 5));
5781c8ba6d0SMarcel Holtmann 		kfree_skb(skb);
5797bee8b08SChris Mason 	}
5801c8ba6d0SMarcel Holtmann 
58134cea41eSMarcel Holtmann 	/* Read USB Product Info */
58234cea41eSMarcel Holtmann 	skb = btbcm_read_usb_product(hdev);
58334cea41eSMarcel Holtmann 	if (!IS_ERR(skb)) {
5842064ee33SMarcel Holtmann 		bt_dev_info(hdev, "BCM: product %4.4x:%4.4x",
58534cea41eSMarcel Holtmann 			    get_unaligned_le16(skb->data + 1),
58634cea41eSMarcel Holtmann 			    get_unaligned_le16(skb->data + 3));
58734cea41eSMarcel Holtmann 		kfree_skb(skb);
58834cea41eSMarcel Holtmann 	}
58934cea41eSMarcel Holtmann 
5904284ecbeSMarcel Holtmann 	/* Read Controller Features */
5914284ecbeSMarcel Holtmann 	skb = btbcm_read_controller_features(hdev);
5924284ecbeSMarcel Holtmann 	if (!IS_ERR(skb)) {
5932064ee33SMarcel Holtmann 		bt_dev_info(hdev, "BCM: features 0x%2.2x", skb->data[1]);
5944284ecbeSMarcel Holtmann 		kfree_skb(skb);
5954284ecbeSMarcel Holtmann 	}
5964284ecbeSMarcel Holtmann 
5979bc63ca0SMarcel Holtmann 	/* Read Local Name */
5989bc63ca0SMarcel Holtmann 	skb = btbcm_read_local_name(hdev);
5999bc63ca0SMarcel Holtmann 	if (!IS_ERR(skb)) {
6002064ee33SMarcel Holtmann 		bt_dev_info(hdev, "%s", (char *)(skb->data + 1));
6019bc63ca0SMarcel Holtmann 		kfree_skb(skb);
6029bc63ca0SMarcel Holtmann 	}
6039bc63ca0SMarcel Holtmann 
604941521e2SMarcel Holtmann 	set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
605941521e2SMarcel Holtmann 
6061c8ba6d0SMarcel Holtmann 	return 0;
6071c8ba6d0SMarcel Holtmann }
6081c8ba6d0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_setup_apple);
6091c8ba6d0SMarcel Holtmann 
6104fba30f0SMarcel Holtmann MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
6114fba30f0SMarcel Holtmann MODULE_DESCRIPTION("Bluetooth support for Broadcom devices ver " VERSION);
6124fba30f0SMarcel Holtmann MODULE_VERSION(VERSION);
6134fba30f0SMarcel Holtmann MODULE_LICENSE("GPL");
614