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

Commit 05f8f252 authored by John W. Linville's avatar John W. Linville
Browse files

Merge branch 'for-upstream' of...

parents 4416f5d2 d839c813
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -81,6 +81,9 @@ static struct usb_device_id ath3k_table[] = {
	/* Atheros AR5BBU12 with sflash firmware */
	{ USB_DEVICE(0x0489, 0xE02C) },

	/* Atheros AR5BBU22 with sflash firmware */
	{ USB_DEVICE(0x0489, 0xE03C) },

	{ }	/* Terminating entry */
};

@@ -99,6 +102,9 @@ static struct usb_device_id ath3k_blist_tbl[] = {
	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },

	/* Atheros AR5BBU22 with sflash firmware */
	{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },

	{ }	/* Terminating entry */
};

+3 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ struct btmrvl_adapter {
	u8 wakeup_tries;
	wait_queue_head_t cmd_wait_q;
	u8 cmd_complete;
	bool is_suspended;
};

struct btmrvl_private {
@@ -139,8 +140,10 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);

int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv);
int btmrvl_enable_ps(struct btmrvl_private *priv);
int btmrvl_prepare_command(struct btmrvl_private *priv);
int btmrvl_enable_hs(struct btmrvl_private *priv);

#ifdef CONFIG_DEBUG_FS
void btmrvl_debugfs_init(struct hci_dev *hdev);
+33 −23
Original line number Diff line number Diff line
@@ -200,6 +200,36 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
}
EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd);

int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv)
{
	struct sk_buff *skb;
	struct btmrvl_cmd *cmd;

	skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
	if (!skb) {
		BT_ERR("No free skb");
		return -ENOMEM;
	}

	cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
	cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF,
						   BT_CMD_HOST_SLEEP_CONFIG));
	cmd->length = 2;
	cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
	cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);

	bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;

	skb->dev = (void *) priv->btmrvl_dev.hcidev;
	skb_queue_head(&priv->adapter->tx_queue, skb);

	BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", cmd->data[0],
	       cmd->data[1]);

	return 0;
}
EXPORT_SYMBOL_GPL(btmrvl_send_hscfg_cmd);

int btmrvl_enable_ps(struct btmrvl_private *priv)
{
	struct sk_buff *skb;
@@ -232,7 +262,7 @@ int btmrvl_enable_ps(struct btmrvl_private *priv)
}
EXPORT_SYMBOL_GPL(btmrvl_enable_ps);

static int btmrvl_enable_hs(struct btmrvl_private *priv)
int btmrvl_enable_hs(struct btmrvl_private *priv)
{
	struct sk_buff *skb;
	struct btmrvl_cmd *cmd;
@@ -268,35 +298,15 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv)

	return ret;
}
EXPORT_SYMBOL_GPL(btmrvl_enable_hs);

int btmrvl_prepare_command(struct btmrvl_private *priv)
{
	struct sk_buff *skb = NULL;
	struct btmrvl_cmd *cmd;
	int ret = 0;

	if (priv->btmrvl_dev.hscfgcmd) {
		priv->btmrvl_dev.hscfgcmd = 0;

		skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
		if (skb == NULL) {
			BT_ERR("No free skb");
			return -ENOMEM;
		}

		cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
		cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_CONFIG));
		cmd->length = 2;
		cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
		cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);

		bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;

		skb->dev = (void *) priv->btmrvl_dev.hcidev;
		skb_queue_head(&priv->adapter->tx_queue, skb);

		BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x",
						cmd->data[0], cmd->data[1]);
		btmrvl_send_hscfg_cmd(priv);
	}

	if (priv->btmrvl_dev.pscmd) {
+105 −7
Original line number Diff line number Diff line
@@ -339,9 +339,7 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)

done:
	kfree(tmphlprbuf);
	if (fw_helper)
	release_firmware(fw_helper);

	return ret;
}

@@ -484,10 +482,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)

done:
	kfree(tmpfwbuf);

	if (fw_firmware)
	release_firmware(fw_firmware);

	return ret;
}

@@ -1013,6 +1008,9 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
	priv->btmrvl_dev.psmode = 1;
	btmrvl_enable_ps(priv);

	priv->btmrvl_dev.gpio_gap = 0xffff;
	btmrvl_send_hscfg_cmd(priv);

	return 0;

disable_host_int:
@@ -1048,11 +1046,111 @@ static void btmrvl_sdio_remove(struct sdio_func *func)
	}
}

static int btmrvl_sdio_suspend(struct device *dev)
{
	struct sdio_func *func = dev_to_sdio_func(dev);
	struct btmrvl_sdio_card *card;
	struct btmrvl_private *priv;
	mmc_pm_flag_t pm_flags;
	struct hci_dev *hcidev;

	if (func) {
		pm_flags = sdio_get_host_pm_caps(func);
		BT_DBG("%s: suspend: PM flags = 0x%x", sdio_func_id(func),
		       pm_flags);
		if (!(pm_flags & MMC_PM_KEEP_POWER)) {
			BT_ERR("%s: cannot remain alive while suspended",
			       sdio_func_id(func));
			return -ENOSYS;
		}
		card = sdio_get_drvdata(func);
		if (!card || !card->priv) {
			BT_ERR("card or priv structure is not valid");
			return 0;
		}
	} else {
		BT_ERR("sdio_func is not specified");
		return 0;
	}

	priv = card->priv;

	if (priv->adapter->hs_state != HS_ACTIVATED) {
		if (btmrvl_enable_hs(priv)) {
			BT_ERR("HS not actived, suspend failed!");
			return -EBUSY;
		}
	}
	hcidev = priv->btmrvl_dev.hcidev;
	BT_DBG("%s: SDIO suspend", hcidev->name);
	hci_suspend_dev(hcidev);
	skb_queue_purge(&priv->adapter->tx_queue);

	priv->adapter->is_suspended = true;

	/* We will keep the power when hs enabled successfully */
	if (priv->adapter->hs_state == HS_ACTIVATED) {
		BT_DBG("suspend with MMC_PM_KEEP_POWER");
		return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
	} else {
		BT_DBG("suspend without MMC_PM_KEEP_POWER");
		return 0;
	}
}

static int btmrvl_sdio_resume(struct device *dev)
{
	struct sdio_func *func = dev_to_sdio_func(dev);
	struct btmrvl_sdio_card *card;
	struct btmrvl_private *priv;
	mmc_pm_flag_t pm_flags;
	struct hci_dev *hcidev;

	if (func) {
		pm_flags = sdio_get_host_pm_caps(func);
		BT_DBG("%s: resume: PM flags = 0x%x", sdio_func_id(func),
		       pm_flags);
		card = sdio_get_drvdata(func);
		if (!card || !card->priv) {
			BT_ERR("card or priv structure is not valid");
			return 0;
		}
	} else {
		BT_ERR("sdio_func is not specified");
		return 0;
	}
	priv = card->priv;

	if (!priv->adapter->is_suspended) {
		BT_DBG("device already resumed");
		return 0;
	}

	priv->adapter->is_suspended = false;
	hcidev = priv->btmrvl_dev.hcidev;
	BT_DBG("%s: SDIO resume", hcidev->name);
	hci_resume_dev(hcidev);
	priv->hw_wakeup_firmware(priv);
	priv->adapter->hs_state = HS_DEACTIVATED;
	BT_DBG("%s: HS DEACTIVATED in resume!", hcidev->name);

	return 0;
}

static const struct dev_pm_ops btmrvl_sdio_pm_ops = {
	.suspend	= btmrvl_sdio_suspend,
	.resume		= btmrvl_sdio_resume,
};

static struct sdio_driver bt_mrvl_sdio = {
	.name		= "btmrvl_sdio",
	.id_table	= btmrvl_sdio_ids,
	.probe		= btmrvl_sdio_probe,
	.remove		= btmrvl_sdio_remove,
	.drv = {
		.owner = THIS_MODULE,
		.pm = &btmrvl_sdio_pm_ops,
	}
};

static int __init btmrvl_sdio_init_module(void)
+14 −2
Original line number Diff line number Diff line
@@ -143,6 +143,9 @@ static struct usb_device_id blacklist_table[] = {
	/* Atheros AR5BBU12 with sflash firmware */
	{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },

	/* Atheros AR5BBU12 with sflash firmware */
	{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },

	/* Broadcom BCM2035 */
	{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
@@ -855,6 +858,7 @@ static void btusb_work(struct work_struct *work)
{
	struct btusb_data *data = container_of(work, struct btusb_data, work);
	struct hci_dev *hdev = data->hdev;
	int new_alts;
	int err;

	if (hdev->conn_hash.sco_num > 0) {
@@ -868,11 +872,19 @@ static void btusb_work(struct work_struct *work)

			set_bit(BTUSB_DID_ISO_RESUME, &data->flags);
		}
		if (data->isoc_altsetting != 2) {

		if (hdev->voice_setting & 0x0020) {
			static const int alts[3] = { 2, 4, 5 };
			new_alts = alts[hdev->conn_hash.sco_num - 1];
		} else {
			new_alts = hdev->conn_hash.sco_num;
		}

		if (data->isoc_altsetting != new_alts) {
			clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
			usb_kill_anchored_urbs(&data->isoc_anchor);

			if (__set_isoc_interface(hdev, 2) < 0)
			if (__set_isoc_interface(hdev, new_alts) < 0)
				return;
		}

Loading