Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f38c173f authored by Bhasker Neti's avatar Bhasker Neti
Browse files

Bluetooth: x86-Rome driver support



Add USB client driver support for Rome USB chip.

Change-Id: I781dcdc913291ab0695ced1b34fde2710049586e
Signed-off-by: default avatarBhasker Neti <bneti@codeaurora.org>
parent 480c7178
Loading
Loading
Loading
Loading
+141 −13
Original line number Diff line number Diff line
/*
 * Copyright (c) 2008-2009 Atheros Communications Inc.
 * Copyright (c) 2014 The Linux Foundation. All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
@@ -32,6 +33,19 @@
#define VERSION "1.0"
#define ATH3K_FIRMWARE	"ath3k-1.fw"

#define ROME2_1_USB_RAMPATCH_FILE	"ar3k/rampatch_2.1.tlv"
#define ROME2_1_USB_NVM_FILE		"ar3k/nvm_tlv_usb_2.1.bin"

#define ROME1_1_USB_RAMPATCH_FILE	"ar3k/rampatch_1.1.img"
#define ROME1_1_USB_NVM_FILE		"ar3k/nvm_tlv_usb_1.1.bin"

#define ROME2_1_USB_RAMPATCH_HEADER	sizeof(struct rome2_1_version)
#define ROME1_1_USB_RAMPATCH_HEADER	sizeof(struct rome1_1_version)
#define ROME1_1_USB_NVM_HEADER		0x04
#define ROME2_1_USB_NVM_HEADER		0x04
#define ROME2_1_USB_CHIP_VERSION		0x200
#define ROME1_1_USB_CHIP_VERSION		0x101

#define ATH3K_DNLOAD				0x01
#define ATH3K_GETSTATE				0x05
#define ATH3K_SET_NORMAL_MODE			0x07
@@ -57,6 +71,34 @@ struct ath3k_version {
	unsigned char	reserved[0x07];
};

struct __packed rome1_1_version {
	u8	type;
	u8	length[3];
	u8	sign_ver;
	u8	sign_algo;
	u8	resv1[2];
	u16	product_id;
	u16	build_ver;
	u16	patch_ver;
	u8	resv2[2];
	u32	entry_addr;
};
struct __packed rome2_1_version {
	u8	type;
	u8	length[3];
	u32	total_len;
	u32	patch_len;
	u8	sign_ver;
	u8	sign_algo;
	u8	resv1[2];
	u16	product_id;
	u16	build_ver;
	u16	patch_ver;
	u8	resv2[2];
	u32	entry_addr;
};


static struct usb_device_id ath3k_table[] = {
	/* Atheros AR3011 */
	{ USB_DEVICE(0x0CF3, 0x3000) },
@@ -243,8 +285,27 @@ static int ath3k_get_version(struct usb_device *udev,
	return ret;
}

int get_rome_version(struct usb_device *udev)
{
	struct ath3k_version fw_version;
	int ret = 0;

	ret = ath3k_get_version(udev, &fw_version);
	if (ret < 0) {
		BT_ERR("Failed to get Rome Firmware version");
		return ret;
	}
	if ((fw_version.rom_version == ROME2_1_USB_CHIP_VERSION) ||
		(fw_version.rom_version == ROME1_1_USB_CHIP_VERSION))
		ret = fw_version.rom_version;
	else
		ret = 0;
	return ret;
}
EXPORT_SYMBOL(get_rome_version);

static int ath3k_load_fwfile(struct usb_device *udev,
		const struct firmware *firmware)
		const struct firmware *firmware, int header_h)
{
	u8 *send_buf;
	int err, pipe, len, size, count, sent = 0;
@@ -258,7 +319,7 @@ static int ath3k_load_fwfile(struct usb_device *udev,
		return -ENOMEM;
	}

	size = min_t(uint, count, FW_HDR_SIZE);
	size = min_t(uint, count, header_h);
	memcpy(send_buf, firmware->data, size);

	pipe = usb_sndctrlpipe(udev, 0);
@@ -334,6 +395,8 @@ static int ath3k_load_patch(struct usb_device *udev)
	char filename[ATH3K_NAME_LEN] = {0};
	const struct firmware *firmware;
	struct ath3k_version fw_version, pt_version;
	struct rome2_1_version *rome2_1_version;
	struct rome1_1_version *rome1_1_version;
	int ret;

	ret = ath3k_get_state(udev, &fw_state);
@@ -352,20 +415,45 @@ static int ath3k_load_patch(struct usb_device *udev)
		BT_ERR("Can't get version to change to load ram patch err");
		return ret;
	}

	if (fw_version.rom_version == ROME1_1_USB_CHIP_VERSION) {
		BT_DBG("Chip Detected as ROME1.1");
		snprintf(filename, ATH3K_NAME_LEN, ROME1_1_USB_RAMPATCH_FILE);
	} else if (fw_version.rom_version == ROME2_1_USB_CHIP_VERSION) {
		BT_DBG("Chip Detected as ROME2.1");
		snprintf(filename, ATH3K_NAME_LEN, ROME2_1_USB_RAMPATCH_FILE);
	} else {
		BT_DBG("Chip Detected as Ath3k");
		snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu",
		fw_version.rom_version);

	}
	ret = request_firmware(&firmware, filename, &udev->dev);
	if (ret < 0) {
		BT_ERR("Patch file not found %s", filename);
		return ret;
	}

	pt_version.rom_version = *(int *)(firmware->data + firmware->size - 8);
	if (fw_version.rom_version == ROME2_1_USB_CHIP_VERSION) {
		rome2_1_version = (struct rome2_1_version *) firmware->data;
		pt_version.rom_version = rome2_1_version->build_ver;
		pt_version.build_version = rome2_1_version->patch_ver;
		BT_DBG("pt_ver.rom2.1_ver : 0x%x", pt_version.rom_version);
		BT_DBG("pt_ver.build2.1_ver: 0x%x", pt_version.build_version);
		BT_DBG("fw_ver.rom2.1_ver: 0x%x", fw_version.rom_version);
		BT_DBG("fw_ver.build2.1_ver: 0x%x", fw_version.build_version);
	} else if (fw_version.rom_version == ROME1_1_USB_CHIP_VERSION) {
		rome1_1_version = (struct rome1_1_version *) firmware->data;
		pt_version.build_version = rome1_1_version->build_ver;
		pt_version.rom_version = rome1_1_version->patch_ver;
		BT_DBG("pt_ver.rom1.1_ver : 0x%x", pt_version.rom_version);
		BT_DBG("pt_ver.build1.1_ver: 0x%x", pt_version.build_version);
		BT_DBG("fw_ver.rom1.1_ver: 0x%x", fw_version.rom_version);
		BT_DBG("fw_ver.build1.1_ver: 0x%x", fw_version.build_version);
	} else {
		pt_version.rom_version = *(int *)(firmware->data +
						firmware->size - 8);
		pt_version.build_version = *(int *)
		(firmware->data + firmware->size - 4);

	}
	if ((pt_version.rom_version != fw_version.rom_version) ||
		(pt_version.build_version <= fw_version.build_version)) {
		BT_ERR("Patch file version did not match with firmware");
@@ -373,7 +461,15 @@ static int ath3k_load_patch(struct usb_device *udev)
		return -EINVAL;
	}

	ret = ath3k_load_fwfile(udev, firmware);
	if (fw_version.rom_version == ROME2_1_USB_CHIP_VERSION)
		ret = ath3k_load_fwfile(udev, firmware,
						ROME2_1_USB_RAMPATCH_HEADER);
	else if (fw_version.rom_version == ROME1_1_USB_CHIP_VERSION)
		ret = ath3k_load_fwfile(udev, firmware,
						 ROME1_1_USB_RAMPATCH_HEADER);
	else
		ret = ath3k_load_fwfile(udev, firmware, FW_HDR_SIZE);

	release_firmware(firmware);

	return ret;
@@ -415,6 +511,11 @@ static int ath3k_load_syscfg(struct usb_device *udev)
		break;
	}

	if (fw_version.rom_version == ROME2_1_USB_CHIP_VERSION)
		snprintf(filename, ATH3K_NAME_LEN, ROME2_1_USB_NVM_FILE);
	else if (fw_version.rom_version == ROME1_1_USB_CHIP_VERSION)
		snprintf(filename, ATH3K_NAME_LEN, ROME1_1_USB_NVM_FILE);
	else
		snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s",
			fw_version.rom_version, clk_value, ".dfu");

@@ -424,12 +525,36 @@ static int ath3k_load_syscfg(struct usb_device *udev)
		return ret;
	}

	ret = ath3k_load_fwfile(udev, firmware);
	if (fw_version.rom_version == ROME2_1_USB_CHIP_VERSION)
		ret = ath3k_load_fwfile(udev, firmware, ROME2_1_USB_NVM_HEADER);
	else if (fw_version.rom_version == ROME1_1_USB_CHIP_VERSION)
		ret = ath3k_load_fwfile(udev, firmware, ROME1_1_USB_NVM_HEADER);
	else
		ret = ath3k_load_fwfile(udev, firmware, FW_HDR_SIZE);
	release_firmware(firmware);

	return ret;
}


int rome_download(struct usb_device *udev)
{
	int ret;

	ret = ath3k_load_patch(udev);
	if (ret < 0) {
		BT_ERR("Loading patch file failed");
		return ret;
	}
	ret = ath3k_load_syscfg(udev);
	if (ret < 0) {
		BT_ERR("Loading sysconfig file failed");
		return ret;
	}

	return ret;
}
EXPORT_SYMBOL(rome_download);
static int ath3k_probe(struct usb_interface *intf,
			const struct usb_device_id *id)
{
@@ -441,7 +566,10 @@ static int ath3k_probe(struct usb_interface *intf,

	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
		return -ENODEV;

	if (get_rome_version(udev)) {
		BT_INFO("Rome detected, fw dnld will be triggered from btusb");
		return -ENODEV;
	}
	/* match device ID in ath3k blacklist table */
	if (!id->driver_info) {
		const struct usb_device_id *match;
+8 −4
Original line number Diff line number Diff line
@@ -4,7 +4,6 @@
 *
 *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
@@ -1332,7 +1331,7 @@ static int btusb_probe(struct usb_interface *intf,
	struct usb_endpoint_descriptor *ep_desc;
	struct btusb_data *data;
	struct hci_dev *hdev;
	int i, err;
	int i, version, err;

	BT_DBG("intf %p id %p", intf, id);

@@ -1362,12 +1361,17 @@ static int btusb_probe(struct usb_interface *intf,
	if (id->driver_info & BTUSB_ATH3012) {
		struct usb_device *udev = interface_to_usbdev(intf);

		version = get_rome_version(udev);
		BT_INFO("Rome Version: 0x%x",  version);
		/* Old firmware would otherwise let ath3k driver load
		 * patch and sysconfig files */
		if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001)
		if (version)
			rome_download(udev);
		else if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001) {
			BT_INFO("FW for ar3k is yet to be downloaded");
			return -ENODEV;
		}

	}
	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;
+5 −0
Original line number Diff line number Diff line
/*
   BlueZ - Bluetooth protocol stack for Linux
   Copyright (C) 2000-2001 Qualcomm Incorporated
   Copyright (C) 2014 The Linux Foundation. All rights reserved.

   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>

@@ -28,6 +29,7 @@
#include <linux/poll.h>
#include <net/sock.h>
#include <linux/seq_file.h>
#include <linux/usb.h>

#ifndef AF_BLUETOOTH
#define AF_BLUETOOTH	31
@@ -344,4 +346,7 @@ void sco_exit(void);

void bt_sock_reclassify_lock(struct sock *sk, int proto);

int get_rome_version(struct usb_device *udev);
int rome_download(struct usb_device *udev);

#endif /* __BLUETOOTH_H */