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

Commit b9caaabb authored by David S. Miller's avatar David S. Miller
Browse files
parents fc57e515 7e743090
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -82,6 +82,8 @@ block/
	- info on the Block I/O (BIO) layer.
blockdev/
	- info on block devices & drivers
btmrvl.txt
	- info on Marvell Bluetooth driver usage.
cachetlb.txt
	- describes the cache/TLB flushing interfaces Linux uses.
cdrom/
+119 −0
Original line number Diff line number Diff line
=======================================================================
		README for btmrvl driver
=======================================================================


All commands are used via debugfs interface.

=====================
Set/get driver configurations:

Path:	/debug/btmrvl/config/

gpiogap=[n]
hscfgcmd
	These commands are used to configure the host sleep parameters.
	bit 8:0  -- Gap
	bit 16:8 -- GPIO

	where GPIO is the pin number of GPIO used to wake up the host.
	It could be any valid GPIO pin# (e.g. 0-7) or 0xff (SDIO interface
	wakeup will be used instead).

	where Gap is the gap in milli seconds between wakeup signal and
	wakeup event, or 0xff for special host sleep setting.

	Usage:
		# Use SDIO interface to wake up the host and set GAP to 0x80:
		echo 0xff80 > /debug/btmrvl/config/gpiogap
		echo 1 > /debug/btmrvl/config/hscfgcmd

		# Use GPIO pin #3 to wake up the host and set GAP to 0xff:
		echo 0x03ff >  /debug/btmrvl/config/gpiogap
		echo 1 > /debug/btmrvl/config/hscfgcmd

psmode=[n]
pscmd
	These commands are used to enable/disable auto sleep mode

	where the option is:
			1 	-- Enable auto sleep mode
			0 	-- Disable auto sleep mode

	Usage:
		# Enable auto sleep mode
		echo 1 > /debug/btmrvl/config/psmode
		echo 1 > /debug/btmrvl/config/pscmd

		# Disable auto sleep mode
		echo 0 > /debug/btmrvl/config/psmode
		echo 1 > /debug/btmrvl/config/pscmd


hsmode=[n]
hscmd
	These commands are used to enable host sleep or wake up firmware

	where the option is:
			1	-- Enable host sleep
			0	-- Wake up firmware

	Usage:
		# Enable host sleep
		echo 1 > /debug/btmrvl/config/hsmode
		echo 1 > /debug/btmrvl/config/hscmd

		# Wake up firmware
		echo 0 > /debug/btmrvl/config/hsmode
		echo 1 > /debug/btmrvl/config/hscmd


======================
Get driver status:

Path:	/debug/btmrvl/status/

Usage:
	cat /debug/btmrvl/status/<args>

where the args are:

curpsmode
	This command displays current auto sleep status.

psstate
	This command display the power save state.

hsstate
	This command display the host sleep state.

txdnldrdy
	This command displays the value of Tx download ready flag.


=====================

Use hcitool to issue raw hci command, refer to hcitool manual

	Usage: Hcitool cmd <ogf> <ocf> [Parameters]

	Interface Control Command
	hcitool cmd 0x3f 0x5b 0xf5 0x01 0x00    --Enable All interface
	hcitool cmd 0x3f 0x5b 0xf5 0x01 0x01    --Enable Wlan interface
	hcitool cmd 0x3f 0x5b 0xf5 0x01 0x02    --Enable BT interface
	hcitool cmd 0x3f 0x5b 0xf5 0x00 0x00    --Disable All interface
	hcitool cmd 0x3f 0x5b 0xf5 0x00 0x01    --Disable Wlan interface
	hcitool cmd 0x3f 0x5b 0xf5 0x00 0x02    --Disable BT interface

=======================================================================


SD8688 firmware:

/lib/firmware/sd8688_helper.bin
/lib/firmware/sd8688.bin


The images can be downloaded from:

git.infradead.org/users/dwmw2/linux-firmware.git/libertas/
+25 −0
Original line number Diff line number Diff line
@@ -170,5 +170,30 @@ config BT_HCIVHCI
	  Say Y here to compile support for virtual HCI devices into the
	  kernel or say M to compile it as module (hci_vhci).

config BT_MRVL
	tristate "Marvell Bluetooth driver support"
	help
	  The core driver to support Marvell Bluetooth devices.

	  This driver is required if you want to support
	  Marvell Bluetooth devices, such as 8688.

	  Say Y here to compile Marvell Bluetooth driver
	  into the kernel or say M to compile it as module.

config BT_MRVL_SDIO
	tristate "Marvell BT-over-SDIO driver"
	depends on BT_MRVL && MMC
	select FW_LOADER
	help
	  The driver for Marvell Bluetooth chipsets with SDIO interface.

	  This driver is required if you want to use Marvell Bluetooth
	  devices with SDIO interface. Currently only SD8688 chipset is
	  supported.

	  Say Y here to compile support for Marvell BT-over-SDIO driver
	  into the kernel or say M to compile it as module.

endmenu
+6 −0
Original line number Diff line number Diff line
@@ -15,6 +15,12 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
obj-$(CONFIG_BT_HCIBTUSB)	+= btusb.o
obj-$(CONFIG_BT_HCIBTSDIO)	+= btsdio.o

obj-$(CONFIG_BT_MRVL)		+= btmrvl.o
obj-$(CONFIG_BT_MRVL_SDIO)	+= btmrvl_sdio.o

btmrvl-y			:= btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS)	+= btmrvl_debugfs.o

hci_uart-y				:= hci_ldisc.o
hci_uart-$(CONFIG_BT_HCIUART_H4)	+= hci_h4.o
hci_uart-$(CONFIG_BT_HCIUART_BCSP)	+= hci_bcsp.o
+432 −0
Original line number Diff line number Diff line
/**
 * Marvell Bluetooth driver: debugfs related functions
 *
 * Copyright (C) 2009, Marvell International Ltd.
 *
 * This software file (the "File") is distributed by Marvell International
 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
 * (the "License").  You may use, redistribute and/or modify this File in
 * accordance with the terms and conditions of the License, a copy of which
 * is available by writing to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
 *
 *
 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
 * this warranty disclaimer.
 **/

#include <linux/debugfs.h>

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>

#include "btmrvl_drv.h"

struct btmrvl_debugfs_data {
	struct dentry *root_dir, *config_dir, *status_dir;

	/* config */
	struct dentry *drvdbg;
	struct dentry *psmode;
	struct dentry *pscmd;
	struct dentry *hsmode;
	struct dentry *hscmd;
	struct dentry *gpiogap;
	struct dentry *hscfgcmd;

	/* status */
	struct dentry *curpsmode;
	struct dentry *hsstate;
	struct dentry *psstate;
	struct dentry *txdnldready;
};

static int btmrvl_open_generic(struct inode *inode, struct file *file)
{
	file->private_data = inode->i_private;
	return 0;
}

static ssize_t btmrvl_hscfgcmd_write(struct file *file,
			const char __user *ubuf, size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	long result, ret;

	memset(buf, 0, sizeof(buf));

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

	ret = strict_strtol(buf, 10, &result);

	priv->btmrvl_dev.hscfgcmd = result;

	if (priv->btmrvl_dev.hscfgcmd) {
		btmrvl_prepare_command(priv);
		wake_up_interruptible(&priv->main_thread.wait_q);
	}

	return count;
}

static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
						priv->btmrvl_dev.hscfgcmd);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_hscfgcmd_fops = {
	.read	= btmrvl_hscfgcmd_read,
	.write	= btmrvl_hscfgcmd_write,
	.open	= btmrvl_open_generic,
};

static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	long result, ret;

	memset(buf, 0, sizeof(buf));

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

	ret = strict_strtol(buf, 10, &result);

	priv->btmrvl_dev.psmode = result;

	return count;
}

static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
						priv->btmrvl_dev.psmode);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_psmode_fops = {
	.read	= btmrvl_psmode_read,
	.write	= btmrvl_psmode_write,
	.open	= btmrvl_open_generic,
};

static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	long result, ret;

	memset(buf, 0, sizeof(buf));

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

	ret = strict_strtol(buf, 10, &result);

	priv->btmrvl_dev.pscmd = result;

	if (priv->btmrvl_dev.pscmd) {
		btmrvl_prepare_command(priv);
		wake_up_interruptible(&priv->main_thread.wait_q);
	}

	return count;

}

static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_pscmd_fops = {
	.read = btmrvl_pscmd_read,
	.write = btmrvl_pscmd_write,
	.open = btmrvl_open_generic,
};

static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	long result, ret;

	memset(buf, 0, sizeof(buf));

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

	ret = strict_strtol(buf, 16, &result);

	priv->btmrvl_dev.gpio_gap = result;

	return count;
}

static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n",
						priv->btmrvl_dev.gpio_gap);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_gpiogap_fops = {
	.read	= btmrvl_gpiogap_read,
	.write	= btmrvl_gpiogap_write,
	.open	= btmrvl_open_generic,
};

static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = (struct btmrvl_private *) file->private_data;
	char buf[16];
	long result, ret;

	memset(buf, 0, sizeof(buf));

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

	ret = strict_strtol(buf, 10, &result);

	priv->btmrvl_dev.hscmd = result;
	if (priv->btmrvl_dev.hscmd) {
		btmrvl_prepare_command(priv);
		wake_up_interruptible(&priv->main_thread.wait_q);
	}

	return count;
}

static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_hscmd_fops = {
	.read	= btmrvl_hscmd_read,
	.write	= btmrvl_hscmd_write,
	.open	= btmrvl_open_generic,
};

static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	long result, ret;

	memset(buf, 0, sizeof(buf));

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

	ret = strict_strtol(buf, 10, &result);

	priv->btmrvl_dev.hsmode = result;

	return count;
}

static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_hsmode_fops = {
	.read	= btmrvl_hsmode_read,
	.write	= btmrvl_hsmode_write,
	.open	= btmrvl_open_generic,
};

static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_curpsmode_fops = {
	.read	= btmrvl_curpsmode_read,
	.open	= btmrvl_open_generic,
};

static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_psstate_fops = {
	.read	= btmrvl_psstate_read,
	.open	= btmrvl_open_generic,
};

static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_hsstate_fops = {
	.read	= btmrvl_hsstate_read,
	.open	= btmrvl_open_generic,
};

static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
					priv->btmrvl_dev.tx_dnld_rdy);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_txdnldready_fops = {
	.read	= btmrvl_txdnldready_read,
	.open	= btmrvl_open_generic,
};

void btmrvl_debugfs_init(struct hci_dev *hdev)
{
	struct btmrvl_private *priv = hdev->driver_data;
	struct btmrvl_debugfs_data *dbg;

	dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
	priv->debugfs_data = dbg;

	if (!dbg) {
		BT_ERR("Can not allocate memory for btmrvl_debugfs_data.");
		return;
	}

	dbg->root_dir = debugfs_create_dir("btmrvl", NULL);

	dbg->config_dir = debugfs_create_dir("config", dbg->root_dir);

	dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
				hdev->driver_data, &btmrvl_psmode_fops);
	dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir,
				hdev->driver_data, &btmrvl_pscmd_fops);
	dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir,
				hdev->driver_data, &btmrvl_gpiogap_fops);
	dbg->hsmode =  debugfs_create_file("hsmode", 0644, dbg->config_dir,
				hdev->driver_data, &btmrvl_hsmode_fops);
	dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir,
				hdev->driver_data, &btmrvl_hscmd_fops);
	dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
				hdev->driver_data, &btmrvl_hscfgcmd_fops);

	dbg->status_dir = debugfs_create_dir("status", dbg->root_dir);
	dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
						dbg->status_dir,
						hdev->driver_data,
						&btmrvl_curpsmode_fops);
	dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir,
				hdev->driver_data, &btmrvl_psstate_fops);
	dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir,
				hdev->driver_data, &btmrvl_hsstate_fops);
	dbg->txdnldready = debugfs_create_file("txdnldready", 0444,
						dbg->status_dir,
						hdev->driver_data,
						&btmrvl_txdnldready_fops);
}

void btmrvl_debugfs_remove(struct hci_dev *hdev)
{
	struct btmrvl_private *priv = hdev->driver_data;
	struct btmrvl_debugfs_data *dbg = priv->debugfs_data;

	if (!dbg)
		return;

	debugfs_remove(dbg->psmode);
	debugfs_remove(dbg->pscmd);
	debugfs_remove(dbg->gpiogap);
	debugfs_remove(dbg->hsmode);
	debugfs_remove(dbg->hscmd);
	debugfs_remove(dbg->hscfgcmd);
	debugfs_remove(dbg->config_dir);

	debugfs_remove(dbg->curpsmode);
	debugfs_remove(dbg->psstate);
	debugfs_remove(dbg->hsstate);
	debugfs_remove(dbg->txdnldready);
	debugfs_remove(dbg->status_dir);

	debugfs_remove(dbg->root_dir);

	kfree(dbg);
}
Loading