162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// Copyright (c) 2018 MediaTek Inc.
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/*
562306a36Sopenharmony_ci * Bluetooth support for MediaTek serial devices
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Sean Wang <sean.wang@mediatek.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/unaligned.h>
1262306a36Sopenharmony_ci#include <linux/atomic.h>
1362306a36Sopenharmony_ci#include <linux/clk.h>
1462306a36Sopenharmony_ci#include <linux/firmware.h>
1562306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1662306a36Sopenharmony_ci#include <linux/iopoll.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/of.h>
2062306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
2162306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2262306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
2362306a36Sopenharmony_ci#include <linux/serdev.h>
2462306a36Sopenharmony_ci#include <linux/skbuff.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
2762306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "h4_recv.h"
3062306a36Sopenharmony_ci#include "btmtk.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define VERSION "0.2"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define MTK_STP_TLR_SIZE	2
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define BTMTKUART_TX_STATE_ACTIVE	1
3762306a36Sopenharmony_ci#define BTMTKUART_TX_STATE_WAKEUP	2
3862306a36Sopenharmony_ci#define BTMTKUART_TX_WAIT_VND_EVT	3
3962306a36Sopenharmony_ci#define BTMTKUART_REQUIRED_WAKEUP	4
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define BTMTKUART_FLAG_STANDALONE_HW	 BIT(0)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct mtk_stp_hdr {
4462306a36Sopenharmony_ci	u8	prefix;
4562306a36Sopenharmony_ci	__be16	dlen;
4662306a36Sopenharmony_ci	u8	cs;
4762306a36Sopenharmony_ci} __packed;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistruct btmtkuart_data {
5062306a36Sopenharmony_ci	unsigned int flags;
5162306a36Sopenharmony_ci	const char *fwname;
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistruct btmtkuart_dev {
5562306a36Sopenharmony_ci	struct hci_dev *hdev;
5662306a36Sopenharmony_ci	struct serdev_device *serdev;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	struct clk *clk;
5962306a36Sopenharmony_ci	struct clk *osc;
6062306a36Sopenharmony_ci	struct regulator *vcc;
6162306a36Sopenharmony_ci	struct gpio_desc *reset;
6262306a36Sopenharmony_ci	struct gpio_desc *boot;
6362306a36Sopenharmony_ci	struct pinctrl *pinctrl;
6462306a36Sopenharmony_ci	struct pinctrl_state *pins_runtime;
6562306a36Sopenharmony_ci	struct pinctrl_state *pins_boot;
6662306a36Sopenharmony_ci	speed_t	desired_speed;
6762306a36Sopenharmony_ci	speed_t	curr_speed;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	struct work_struct tx_work;
7062306a36Sopenharmony_ci	unsigned long tx_state;
7162306a36Sopenharmony_ci	struct sk_buff_head txq;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	struct sk_buff *rx_skb;
7462306a36Sopenharmony_ci	struct sk_buff *evt_skb;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	u8	stp_pad[6];
7762306a36Sopenharmony_ci	u8	stp_cursor;
7862306a36Sopenharmony_ci	u16	stp_dlen;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	const struct btmtkuart_data *data;
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#define btmtkuart_is_standalone(bdev)	\
8462306a36Sopenharmony_ci	((bdev)->data->flags & BTMTKUART_FLAG_STANDALONE_HW)
8562306a36Sopenharmony_ci#define btmtkuart_is_builtin_soc(bdev)	\
8662306a36Sopenharmony_ci	!((bdev)->data->flags & BTMTKUART_FLAG_STANDALONE_HW)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic int mtk_hci_wmt_sync(struct hci_dev *hdev,
8962306a36Sopenharmony_ci			    struct btmtk_hci_wmt_params *wmt_params)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
9262306a36Sopenharmony_ci	struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
9362306a36Sopenharmony_ci	u32 hlen, status = BTMTK_WMT_INVALID;
9462306a36Sopenharmony_ci	struct btmtk_hci_wmt_evt *wmt_evt;
9562306a36Sopenharmony_ci	struct btmtk_hci_wmt_cmd *wc;
9662306a36Sopenharmony_ci	struct btmtk_wmt_hdr *hdr;
9762306a36Sopenharmony_ci	int err;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* Send the WMT command and wait until the WMT event returns */
10062306a36Sopenharmony_ci	hlen = sizeof(*hdr) + wmt_params->dlen;
10162306a36Sopenharmony_ci	if (hlen > 255) {
10262306a36Sopenharmony_ci		err = -EINVAL;
10362306a36Sopenharmony_ci		goto err_free_skb;
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	wc = kzalloc(hlen, GFP_KERNEL);
10762306a36Sopenharmony_ci	if (!wc) {
10862306a36Sopenharmony_ci		err = -ENOMEM;
10962306a36Sopenharmony_ci		goto err_free_skb;
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	hdr = &wc->hdr;
11362306a36Sopenharmony_ci	hdr->dir = 1;
11462306a36Sopenharmony_ci	hdr->op = wmt_params->op;
11562306a36Sopenharmony_ci	hdr->dlen = cpu_to_le16(wmt_params->dlen + 1);
11662306a36Sopenharmony_ci	hdr->flag = wmt_params->flag;
11762306a36Sopenharmony_ci	memcpy(wc->data, wmt_params->data, wmt_params->dlen);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	set_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	err = __hci_cmd_send(hdev, 0xfc6f, hlen, wc);
12262306a36Sopenharmony_ci	if (err < 0) {
12362306a36Sopenharmony_ci		clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
12462306a36Sopenharmony_ci		goto err_free_wc;
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* The vendor specific WMT commands are all answered by a vendor
12862306a36Sopenharmony_ci	 * specific event and will not have the Command Status or Command
12962306a36Sopenharmony_ci	 * Complete as with usual HCI command flow control.
13062306a36Sopenharmony_ci	 *
13162306a36Sopenharmony_ci	 * After sending the command, wait for BTMTKUART_TX_WAIT_VND_EVT
13262306a36Sopenharmony_ci	 * state to be cleared. The driver specific event receive routine
13362306a36Sopenharmony_ci	 * will clear that state and with that indicate completion of the
13462306a36Sopenharmony_ci	 * WMT command.
13562306a36Sopenharmony_ci	 */
13662306a36Sopenharmony_ci	err = wait_on_bit_timeout(&bdev->tx_state, BTMTKUART_TX_WAIT_VND_EVT,
13762306a36Sopenharmony_ci				  TASK_INTERRUPTIBLE, HCI_INIT_TIMEOUT);
13862306a36Sopenharmony_ci	if (err == -EINTR) {
13962306a36Sopenharmony_ci		bt_dev_err(hdev, "Execution of wmt command interrupted");
14062306a36Sopenharmony_ci		clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
14162306a36Sopenharmony_ci		goto err_free_wc;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (err) {
14562306a36Sopenharmony_ci		bt_dev_err(hdev, "Execution of wmt command timed out");
14662306a36Sopenharmony_ci		clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
14762306a36Sopenharmony_ci		err = -ETIMEDOUT;
14862306a36Sopenharmony_ci		goto err_free_wc;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* Parse and handle the return WMT event */
15262306a36Sopenharmony_ci	wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data;
15362306a36Sopenharmony_ci	if (wmt_evt->whdr.op != hdr->op) {
15462306a36Sopenharmony_ci		bt_dev_err(hdev, "Wrong op received %d expected %d",
15562306a36Sopenharmony_ci			   wmt_evt->whdr.op, hdr->op);
15662306a36Sopenharmony_ci		err = -EIO;
15762306a36Sopenharmony_ci		goto err_free_wc;
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	switch (wmt_evt->whdr.op) {
16162306a36Sopenharmony_ci	case BTMTK_WMT_SEMAPHORE:
16262306a36Sopenharmony_ci		if (wmt_evt->whdr.flag == 2)
16362306a36Sopenharmony_ci			status = BTMTK_WMT_PATCH_UNDONE;
16462306a36Sopenharmony_ci		else
16562306a36Sopenharmony_ci			status = BTMTK_WMT_PATCH_DONE;
16662306a36Sopenharmony_ci		break;
16762306a36Sopenharmony_ci	case BTMTK_WMT_FUNC_CTRL:
16862306a36Sopenharmony_ci		wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
16962306a36Sopenharmony_ci		if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
17062306a36Sopenharmony_ci			status = BTMTK_WMT_ON_DONE;
17162306a36Sopenharmony_ci		else if (be16_to_cpu(wmt_evt_funcc->status) == 0x420)
17262306a36Sopenharmony_ci			status = BTMTK_WMT_ON_PROGRESS;
17362306a36Sopenharmony_ci		else
17462306a36Sopenharmony_ci			status = BTMTK_WMT_ON_UNDONE;
17562306a36Sopenharmony_ci		break;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	if (wmt_params->status)
17962306a36Sopenharmony_ci		*wmt_params->status = status;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cierr_free_wc:
18262306a36Sopenharmony_ci	kfree(wc);
18362306a36Sopenharmony_cierr_free_skb:
18462306a36Sopenharmony_ci	kfree_skb(bdev->evt_skb);
18562306a36Sopenharmony_ci	bdev->evt_skb = NULL;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return err;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic int btmtkuart_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
19362306a36Sopenharmony_ci	struct hci_event_hdr *hdr = (void *)skb->data;
19462306a36Sopenharmony_ci	int err;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* When someone waits for the WMT event, the skb is being cloned
19762306a36Sopenharmony_ci	 * and being processed the events from there then.
19862306a36Sopenharmony_ci	 */
19962306a36Sopenharmony_ci	if (test_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state)) {
20062306a36Sopenharmony_ci		bdev->evt_skb = skb_clone(skb, GFP_KERNEL);
20162306a36Sopenharmony_ci		if (!bdev->evt_skb) {
20262306a36Sopenharmony_ci			err = -ENOMEM;
20362306a36Sopenharmony_ci			goto err_out;
20462306a36Sopenharmony_ci		}
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	err = hci_recv_frame(hdev, skb);
20862306a36Sopenharmony_ci	if (err < 0)
20962306a36Sopenharmony_ci		goto err_free_skb;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (hdr->evt == HCI_EV_WMT) {
21262306a36Sopenharmony_ci		if (test_and_clear_bit(BTMTKUART_TX_WAIT_VND_EVT,
21362306a36Sopenharmony_ci				       &bdev->tx_state)) {
21462306a36Sopenharmony_ci			/* Barrier to sync with other CPUs */
21562306a36Sopenharmony_ci			smp_mb__after_atomic();
21662306a36Sopenharmony_ci			wake_up_bit(&bdev->tx_state, BTMTKUART_TX_WAIT_VND_EVT);
21762306a36Sopenharmony_ci		}
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	return 0;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cierr_free_skb:
22362306a36Sopenharmony_ci	kfree_skb(bdev->evt_skb);
22462306a36Sopenharmony_ci	bdev->evt_skb = NULL;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cierr_out:
22762306a36Sopenharmony_ci	return err;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic const struct h4_recv_pkt mtk_recv_pkts[] = {
23162306a36Sopenharmony_ci	{ H4_RECV_ACL,      .recv = hci_recv_frame },
23262306a36Sopenharmony_ci	{ H4_RECV_SCO,      .recv = hci_recv_frame },
23362306a36Sopenharmony_ci	{ H4_RECV_EVENT,    .recv = btmtkuart_recv_event },
23462306a36Sopenharmony_ci};
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic void btmtkuart_tx_work(struct work_struct *work)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = container_of(work, struct btmtkuart_dev,
23962306a36Sopenharmony_ci						   tx_work);
24062306a36Sopenharmony_ci	struct serdev_device *serdev = bdev->serdev;
24162306a36Sopenharmony_ci	struct hci_dev *hdev = bdev->hdev;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	while (1) {
24462306a36Sopenharmony_ci		clear_bit(BTMTKUART_TX_STATE_WAKEUP, &bdev->tx_state);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		while (1) {
24762306a36Sopenharmony_ci			struct sk_buff *skb = skb_dequeue(&bdev->txq);
24862306a36Sopenharmony_ci			int len;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci			if (!skb)
25162306a36Sopenharmony_ci				break;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci			len = serdev_device_write_buf(serdev, skb->data,
25462306a36Sopenharmony_ci						      skb->len);
25562306a36Sopenharmony_ci			hdev->stat.byte_tx += len;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci			skb_pull(skb, len);
25862306a36Sopenharmony_ci			if (skb->len > 0) {
25962306a36Sopenharmony_ci				skb_queue_head(&bdev->txq, skb);
26062306a36Sopenharmony_ci				break;
26162306a36Sopenharmony_ci			}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci			switch (hci_skb_pkt_type(skb)) {
26462306a36Sopenharmony_ci			case HCI_COMMAND_PKT:
26562306a36Sopenharmony_ci				hdev->stat.cmd_tx++;
26662306a36Sopenharmony_ci				break;
26762306a36Sopenharmony_ci			case HCI_ACLDATA_PKT:
26862306a36Sopenharmony_ci				hdev->stat.acl_tx++;
26962306a36Sopenharmony_ci				break;
27062306a36Sopenharmony_ci			case HCI_SCODATA_PKT:
27162306a36Sopenharmony_ci				hdev->stat.sco_tx++;
27262306a36Sopenharmony_ci				break;
27362306a36Sopenharmony_ci			}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci			kfree_skb(skb);
27662306a36Sopenharmony_ci		}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		if (!test_bit(BTMTKUART_TX_STATE_WAKEUP, &bdev->tx_state))
27962306a36Sopenharmony_ci			break;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	clear_bit(BTMTKUART_TX_STATE_ACTIVE, &bdev->tx_state);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic void btmtkuart_tx_wakeup(struct btmtkuart_dev *bdev)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	if (test_and_set_bit(BTMTKUART_TX_STATE_ACTIVE, &bdev->tx_state))
28862306a36Sopenharmony_ci		set_bit(BTMTKUART_TX_STATE_WAKEUP, &bdev->tx_state);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	schedule_work(&bdev->tx_work);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic const unsigned char *
29462306a36Sopenharmony_cimtk_stp_split(struct btmtkuart_dev *bdev, const unsigned char *data, int count,
29562306a36Sopenharmony_ci	      int *sz_h4)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct mtk_stp_hdr *shdr;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/* The cursor is reset when all the data of STP is consumed out */
30062306a36Sopenharmony_ci	if (!bdev->stp_dlen && bdev->stp_cursor >= 6)
30162306a36Sopenharmony_ci		bdev->stp_cursor = 0;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* Filling pad until all STP info is obtained */
30462306a36Sopenharmony_ci	while (bdev->stp_cursor < 6 && count > 0) {
30562306a36Sopenharmony_ci		bdev->stp_pad[bdev->stp_cursor] = *data;
30662306a36Sopenharmony_ci		bdev->stp_cursor++;
30762306a36Sopenharmony_ci		data++;
30862306a36Sopenharmony_ci		count--;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/* Retrieve STP info and have a sanity check */
31262306a36Sopenharmony_ci	if (!bdev->stp_dlen && bdev->stp_cursor >= 6) {
31362306a36Sopenharmony_ci		shdr = (struct mtk_stp_hdr *)&bdev->stp_pad[2];
31462306a36Sopenharmony_ci		bdev->stp_dlen = be16_to_cpu(shdr->dlen) & 0x0fff;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		/* Resync STP when unexpected data is being read */
31762306a36Sopenharmony_ci		if (shdr->prefix != 0x80 || bdev->stp_dlen > 2048) {
31862306a36Sopenharmony_ci			bt_dev_err(bdev->hdev, "stp format unexpect (%d, %d)",
31962306a36Sopenharmony_ci				   shdr->prefix, bdev->stp_dlen);
32062306a36Sopenharmony_ci			bdev->stp_cursor = 2;
32162306a36Sopenharmony_ci			bdev->stp_dlen = 0;
32262306a36Sopenharmony_ci		}
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/* Directly quit when there's no data found for H4 can process */
32662306a36Sopenharmony_ci	if (count <= 0)
32762306a36Sopenharmony_ci		return NULL;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	/* Tranlate to how much the size of data H4 can handle so far */
33062306a36Sopenharmony_ci	*sz_h4 = min_t(int, count, bdev->stp_dlen);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/* Update the remaining size of STP packet */
33362306a36Sopenharmony_ci	bdev->stp_dlen -= *sz_h4;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* Data points to STP payload which can be handled by H4 */
33662306a36Sopenharmony_ci	return data;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic void btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
34262306a36Sopenharmony_ci	const unsigned char *p_left = data, *p_h4;
34362306a36Sopenharmony_ci	int sz_left = count, sz_h4, adv;
34462306a36Sopenharmony_ci	int err;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	while (sz_left > 0) {
34762306a36Sopenharmony_ci		/*  The serial data received from MT7622 BT controller is
34862306a36Sopenharmony_ci		 *  at all time padded around with the STP header and tailer.
34962306a36Sopenharmony_ci		 *
35062306a36Sopenharmony_ci		 *  A full STP packet is looking like
35162306a36Sopenharmony_ci		 *   -----------------------------------
35262306a36Sopenharmony_ci		 *  | STP header  |  H:4   | STP tailer |
35362306a36Sopenharmony_ci		 *   -----------------------------------
35462306a36Sopenharmony_ci		 *  but it doesn't guarantee to contain a full H:4 packet which
35562306a36Sopenharmony_ci		 *  means that it's possible for multiple STP packets forms a
35662306a36Sopenharmony_ci		 *  full H:4 packet that means extra STP header + length doesn't
35762306a36Sopenharmony_ci		 *  indicate a full H:4 frame, things can fragment. Whose length
35862306a36Sopenharmony_ci		 *  recorded in STP header just shows up the most length the
35962306a36Sopenharmony_ci		 *  H:4 engine can handle currently.
36062306a36Sopenharmony_ci		 */
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci		p_h4 = mtk_stp_split(bdev, p_left, sz_left, &sz_h4);
36362306a36Sopenharmony_ci		if (!p_h4)
36462306a36Sopenharmony_ci			break;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		adv = p_h4 - p_left;
36762306a36Sopenharmony_ci		sz_left -= adv;
36862306a36Sopenharmony_ci		p_left += adv;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		bdev->rx_skb = h4_recv_buf(bdev->hdev, bdev->rx_skb, p_h4,
37162306a36Sopenharmony_ci					   sz_h4, mtk_recv_pkts,
37262306a36Sopenharmony_ci					   ARRAY_SIZE(mtk_recv_pkts));
37362306a36Sopenharmony_ci		if (IS_ERR(bdev->rx_skb)) {
37462306a36Sopenharmony_ci			err = PTR_ERR(bdev->rx_skb);
37562306a36Sopenharmony_ci			bt_dev_err(bdev->hdev,
37662306a36Sopenharmony_ci				   "Frame reassembly failed (%d)", err);
37762306a36Sopenharmony_ci			bdev->rx_skb = NULL;
37862306a36Sopenharmony_ci			return;
37962306a36Sopenharmony_ci		}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci		sz_left -= sz_h4;
38262306a36Sopenharmony_ci		p_left += sz_h4;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic int btmtkuart_receive_buf(struct serdev_device *serdev, const u8 *data,
38762306a36Sopenharmony_ci				 size_t count)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	btmtkuart_recv(bdev->hdev, data, count);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	bdev->hdev->stat.byte_rx += count;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	return count;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic void btmtkuart_write_wakeup(struct serdev_device *serdev)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	btmtkuart_tx_wakeup(bdev);
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic const struct serdev_device_ops btmtkuart_client_ops = {
40662306a36Sopenharmony_ci	.receive_buf = btmtkuart_receive_buf,
40762306a36Sopenharmony_ci	.write_wakeup = btmtkuart_write_wakeup,
40862306a36Sopenharmony_ci};
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic int btmtkuart_open(struct hci_dev *hdev)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
41362306a36Sopenharmony_ci	struct device *dev;
41462306a36Sopenharmony_ci	int err;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	err = serdev_device_open(bdev->serdev);
41762306a36Sopenharmony_ci	if (err) {
41862306a36Sopenharmony_ci		bt_dev_err(hdev, "Unable to open UART device %s",
41962306a36Sopenharmony_ci			   dev_name(&bdev->serdev->dev));
42062306a36Sopenharmony_ci		goto err_open;
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (btmtkuart_is_standalone(bdev)) {
42462306a36Sopenharmony_ci		if (bdev->curr_speed != bdev->desired_speed)
42562306a36Sopenharmony_ci			err = serdev_device_set_baudrate(bdev->serdev,
42662306a36Sopenharmony_ci							 115200);
42762306a36Sopenharmony_ci		else
42862306a36Sopenharmony_ci			err = serdev_device_set_baudrate(bdev->serdev,
42962306a36Sopenharmony_ci							 bdev->desired_speed);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		if (err < 0) {
43262306a36Sopenharmony_ci			bt_dev_err(hdev, "Unable to set baudrate UART device %s",
43362306a36Sopenharmony_ci				   dev_name(&bdev->serdev->dev));
43462306a36Sopenharmony_ci			goto  err_serdev_close;
43562306a36Sopenharmony_ci		}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		serdev_device_set_flow_control(bdev->serdev, false);
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	bdev->stp_cursor = 2;
44162306a36Sopenharmony_ci	bdev->stp_dlen = 0;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	dev = &bdev->serdev->dev;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/* Enable the power domain and clock the device requires */
44662306a36Sopenharmony_ci	pm_runtime_enable(dev);
44762306a36Sopenharmony_ci	err = pm_runtime_resume_and_get(dev);
44862306a36Sopenharmony_ci	if (err < 0)
44962306a36Sopenharmony_ci		goto err_disable_rpm;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	err = clk_prepare_enable(bdev->clk);
45262306a36Sopenharmony_ci	if (err < 0)
45362306a36Sopenharmony_ci		goto err_put_rpm;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	return 0;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cierr_put_rpm:
45862306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
45962306a36Sopenharmony_cierr_disable_rpm:
46062306a36Sopenharmony_ci	pm_runtime_disable(dev);
46162306a36Sopenharmony_cierr_serdev_close:
46262306a36Sopenharmony_ci	serdev_device_close(bdev->serdev);
46362306a36Sopenharmony_cierr_open:
46462306a36Sopenharmony_ci	return err;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic int btmtkuart_close(struct hci_dev *hdev)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
47062306a36Sopenharmony_ci	struct device *dev = &bdev->serdev->dev;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* Shutdown the clock and power domain the device requires */
47362306a36Sopenharmony_ci	clk_disable_unprepare(bdev->clk);
47462306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
47562306a36Sopenharmony_ci	pm_runtime_disable(dev);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	serdev_device_close(bdev->serdev);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	return 0;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic int btmtkuart_flush(struct hci_dev *hdev)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/* Flush any pending characters */
48762306a36Sopenharmony_ci	serdev_device_write_flush(bdev->serdev);
48862306a36Sopenharmony_ci	skb_queue_purge(&bdev->txq);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	cancel_work_sync(&bdev->tx_work);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	kfree_skb(bdev->rx_skb);
49362306a36Sopenharmony_ci	bdev->rx_skb = NULL;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	bdev->stp_cursor = 2;
49662306a36Sopenharmony_ci	bdev->stp_dlen = 0;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return 0;
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic int btmtkuart_func_query(struct hci_dev *hdev)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct btmtk_hci_wmt_params wmt_params;
50462306a36Sopenharmony_ci	int status, err;
50562306a36Sopenharmony_ci	u8 param = 0;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/* Query whether the function is enabled */
50862306a36Sopenharmony_ci	wmt_params.op = BTMTK_WMT_FUNC_CTRL;
50962306a36Sopenharmony_ci	wmt_params.flag = 4;
51062306a36Sopenharmony_ci	wmt_params.dlen = sizeof(param);
51162306a36Sopenharmony_ci	wmt_params.data = &param;
51262306a36Sopenharmony_ci	wmt_params.status = &status;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	err = mtk_hci_wmt_sync(hdev, &wmt_params);
51562306a36Sopenharmony_ci	if (err < 0) {
51662306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to query function status (%d)", err);
51762306a36Sopenharmony_ci		return err;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	return status;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic int btmtkuart_change_baudrate(struct hci_dev *hdev)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
52662306a36Sopenharmony_ci	struct btmtk_hci_wmt_params wmt_params;
52762306a36Sopenharmony_ci	__le32 baudrate;
52862306a36Sopenharmony_ci	u8 param;
52962306a36Sopenharmony_ci	int err;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* Indicate the device to enter the probe state the host is
53262306a36Sopenharmony_ci	 * ready to change a new baudrate.
53362306a36Sopenharmony_ci	 */
53462306a36Sopenharmony_ci	baudrate = cpu_to_le32(bdev->desired_speed);
53562306a36Sopenharmony_ci	wmt_params.op = BTMTK_WMT_HIF;
53662306a36Sopenharmony_ci	wmt_params.flag = 1;
53762306a36Sopenharmony_ci	wmt_params.dlen = 4;
53862306a36Sopenharmony_ci	wmt_params.data = &baudrate;
53962306a36Sopenharmony_ci	wmt_params.status = NULL;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	err = mtk_hci_wmt_sync(hdev, &wmt_params);
54262306a36Sopenharmony_ci	if (err < 0) {
54362306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to device baudrate (%d)", err);
54462306a36Sopenharmony_ci		return err;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	err = serdev_device_set_baudrate(bdev->serdev,
54862306a36Sopenharmony_ci					 bdev->desired_speed);
54962306a36Sopenharmony_ci	if (err < 0) {
55062306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to set up host baudrate (%d)",
55162306a36Sopenharmony_ci			   err);
55262306a36Sopenharmony_ci		return err;
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	serdev_device_set_flow_control(bdev->serdev, false);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	/* Send a dummy byte 0xff to activate the new baudrate */
55862306a36Sopenharmony_ci	param = 0xff;
55962306a36Sopenharmony_ci	err = serdev_device_write_buf(bdev->serdev, &param, sizeof(param));
56062306a36Sopenharmony_ci	if (err < 0 || err < sizeof(param))
56162306a36Sopenharmony_ci		return err;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	serdev_device_wait_until_sent(bdev->serdev, 0);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* Wait some time for the device changing baudrate done */
56662306a36Sopenharmony_ci	usleep_range(20000, 22000);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	/* Test the new baudrate */
56962306a36Sopenharmony_ci	wmt_params.op = BTMTK_WMT_TEST;
57062306a36Sopenharmony_ci	wmt_params.flag = 7;
57162306a36Sopenharmony_ci	wmt_params.dlen = 0;
57262306a36Sopenharmony_ci	wmt_params.data = NULL;
57362306a36Sopenharmony_ci	wmt_params.status = NULL;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	err = mtk_hci_wmt_sync(hdev, &wmt_params);
57662306a36Sopenharmony_ci	if (err < 0) {
57762306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to test new baudrate (%d)",
57862306a36Sopenharmony_ci			   err);
57962306a36Sopenharmony_ci		return err;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	bdev->curr_speed = bdev->desired_speed;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	return 0;
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic int btmtkuart_setup(struct hci_dev *hdev)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
59062306a36Sopenharmony_ci	struct btmtk_hci_wmt_params wmt_params;
59162306a36Sopenharmony_ci	ktime_t calltime, delta, rettime;
59262306a36Sopenharmony_ci	struct btmtk_tci_sleep tci_sleep;
59362306a36Sopenharmony_ci	unsigned long long duration;
59462306a36Sopenharmony_ci	struct sk_buff *skb;
59562306a36Sopenharmony_ci	int err, status;
59662306a36Sopenharmony_ci	u8 param = 0x1;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	calltime = ktime_get();
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	/* Wakeup MCUSYS is required for certain devices before we start to
60162306a36Sopenharmony_ci	 * do any setups.
60262306a36Sopenharmony_ci	 */
60362306a36Sopenharmony_ci	if (test_bit(BTMTKUART_REQUIRED_WAKEUP, &bdev->tx_state)) {
60462306a36Sopenharmony_ci		wmt_params.op = BTMTK_WMT_WAKEUP;
60562306a36Sopenharmony_ci		wmt_params.flag = 3;
60662306a36Sopenharmony_ci		wmt_params.dlen = 0;
60762306a36Sopenharmony_ci		wmt_params.data = NULL;
60862306a36Sopenharmony_ci		wmt_params.status = NULL;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		err = mtk_hci_wmt_sync(hdev, &wmt_params);
61162306a36Sopenharmony_ci		if (err < 0) {
61262306a36Sopenharmony_ci			bt_dev_err(hdev, "Failed to wakeup the chip (%d)", err);
61362306a36Sopenharmony_ci			return err;
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		clear_bit(BTMTKUART_REQUIRED_WAKEUP, &bdev->tx_state);
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (btmtkuart_is_standalone(bdev))
62062306a36Sopenharmony_ci		btmtkuart_change_baudrate(hdev);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/* Query whether the firmware is already download */
62362306a36Sopenharmony_ci	wmt_params.op = BTMTK_WMT_SEMAPHORE;
62462306a36Sopenharmony_ci	wmt_params.flag = 1;
62562306a36Sopenharmony_ci	wmt_params.dlen = 0;
62662306a36Sopenharmony_ci	wmt_params.data = NULL;
62762306a36Sopenharmony_ci	wmt_params.status = &status;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	err = mtk_hci_wmt_sync(hdev, &wmt_params);
63062306a36Sopenharmony_ci	if (err < 0) {
63162306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to query firmware status (%d)", err);
63262306a36Sopenharmony_ci		return err;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (status == BTMTK_WMT_PATCH_DONE) {
63662306a36Sopenharmony_ci		bt_dev_info(hdev, "Firmware already downloaded");
63762306a36Sopenharmony_ci		goto ignore_setup_fw;
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	/* Setup a firmware which the device definitely requires */
64162306a36Sopenharmony_ci	err = btmtk_setup_firmware(hdev, bdev->data->fwname, mtk_hci_wmt_sync);
64262306a36Sopenharmony_ci	if (err < 0)
64362306a36Sopenharmony_ci		return err;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ciignore_setup_fw:
64662306a36Sopenharmony_ci	/* Query whether the device is already enabled */
64762306a36Sopenharmony_ci	err = readx_poll_timeout(btmtkuart_func_query, hdev, status,
64862306a36Sopenharmony_ci				 status < 0 || status != BTMTK_WMT_ON_PROGRESS,
64962306a36Sopenharmony_ci				 2000, 5000000);
65062306a36Sopenharmony_ci	/* -ETIMEDOUT happens */
65162306a36Sopenharmony_ci	if (err < 0)
65262306a36Sopenharmony_ci		return err;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	/* The other errors happen in btusb_mtk_func_query */
65562306a36Sopenharmony_ci	if (status < 0)
65662306a36Sopenharmony_ci		return status;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	if (status == BTMTK_WMT_ON_DONE) {
65962306a36Sopenharmony_ci		bt_dev_info(hdev, "function already on");
66062306a36Sopenharmony_ci		goto ignore_func_on;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	/* Enable Bluetooth protocol */
66462306a36Sopenharmony_ci	wmt_params.op = BTMTK_WMT_FUNC_CTRL;
66562306a36Sopenharmony_ci	wmt_params.flag = 0;
66662306a36Sopenharmony_ci	wmt_params.dlen = sizeof(param);
66762306a36Sopenharmony_ci	wmt_params.data = &param;
66862306a36Sopenharmony_ci	wmt_params.status = NULL;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	err = mtk_hci_wmt_sync(hdev, &wmt_params);
67162306a36Sopenharmony_ci	if (err < 0) {
67262306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
67362306a36Sopenharmony_ci		return err;
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ciignore_func_on:
67762306a36Sopenharmony_ci	/* Apply the low power environment setup */
67862306a36Sopenharmony_ci	tci_sleep.mode = 0x5;
67962306a36Sopenharmony_ci	tci_sleep.duration = cpu_to_le16(0x640);
68062306a36Sopenharmony_ci	tci_sleep.host_duration = cpu_to_le16(0x640);
68162306a36Sopenharmony_ci	tci_sleep.host_wakeup_pin = 0;
68262306a36Sopenharmony_ci	tci_sleep.time_compensation = 0;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc7a, sizeof(tci_sleep), &tci_sleep,
68562306a36Sopenharmony_ci			     HCI_INIT_TIMEOUT);
68662306a36Sopenharmony_ci	if (IS_ERR(skb)) {
68762306a36Sopenharmony_ci		err = PTR_ERR(skb);
68862306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to apply low power setting (%d)", err);
68962306a36Sopenharmony_ci		return err;
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci	kfree_skb(skb);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	rettime = ktime_get();
69462306a36Sopenharmony_ci	delta = ktime_sub(rettime, calltime);
69562306a36Sopenharmony_ci	duration = (unsigned long long)ktime_to_ns(delta) >> 10;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	bt_dev_info(hdev, "Device setup in %llu usecs", duration);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	return 0;
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_cistatic int btmtkuart_shutdown(struct hci_dev *hdev)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct btmtk_hci_wmt_params wmt_params;
70562306a36Sopenharmony_ci	u8 param = 0x0;
70662306a36Sopenharmony_ci	int err;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* Disable the device */
70962306a36Sopenharmony_ci	wmt_params.op = BTMTK_WMT_FUNC_CTRL;
71062306a36Sopenharmony_ci	wmt_params.flag = 0;
71162306a36Sopenharmony_ci	wmt_params.dlen = sizeof(param);
71262306a36Sopenharmony_ci	wmt_params.data = &param;
71362306a36Sopenharmony_ci	wmt_params.status = NULL;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	err = mtk_hci_wmt_sync(hdev, &wmt_params);
71662306a36Sopenharmony_ci	if (err < 0) {
71762306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
71862306a36Sopenharmony_ci		return err;
71962306a36Sopenharmony_ci	}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	return 0;
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic int btmtkuart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
72762306a36Sopenharmony_ci	struct mtk_stp_hdr *shdr;
72862306a36Sopenharmony_ci	int err, dlen, type = 0;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	/* Prepend skb with frame type */
73162306a36Sopenharmony_ci	memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	/* Make sure that there is enough rooms for STP header and trailer */
73462306a36Sopenharmony_ci	if (unlikely(skb_headroom(skb) < sizeof(*shdr)) ||
73562306a36Sopenharmony_ci	    (skb_tailroom(skb) < MTK_STP_TLR_SIZE)) {
73662306a36Sopenharmony_ci		err = pskb_expand_head(skb, sizeof(*shdr), MTK_STP_TLR_SIZE,
73762306a36Sopenharmony_ci				       GFP_ATOMIC);
73862306a36Sopenharmony_ci		if (err < 0)
73962306a36Sopenharmony_ci			return err;
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	/* Add the STP header */
74362306a36Sopenharmony_ci	dlen = skb->len;
74462306a36Sopenharmony_ci	shdr = skb_push(skb, sizeof(*shdr));
74562306a36Sopenharmony_ci	shdr->prefix = 0x80;
74662306a36Sopenharmony_ci	shdr->dlen = cpu_to_be16((dlen & 0x0fff) | (type << 12));
74762306a36Sopenharmony_ci	shdr->cs = 0;		/* MT7622 doesn't care about checksum value */
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	/* Add the STP trailer */
75062306a36Sopenharmony_ci	skb_put_zero(skb, MTK_STP_TLR_SIZE);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	skb_queue_tail(&bdev->txq, skb);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	btmtkuart_tx_wakeup(bdev);
75562306a36Sopenharmony_ci	return 0;
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic int btmtkuart_parse_dt(struct serdev_device *serdev)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);
76162306a36Sopenharmony_ci	struct device_node *node = serdev->dev.of_node;
76262306a36Sopenharmony_ci	u32 speed = 921600;
76362306a36Sopenharmony_ci	int err;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	if (btmtkuart_is_standalone(bdev)) {
76662306a36Sopenharmony_ci		of_property_read_u32(node, "current-speed", &speed);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		bdev->desired_speed = speed;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci		bdev->vcc = devm_regulator_get(&serdev->dev, "vcc");
77162306a36Sopenharmony_ci		if (IS_ERR(bdev->vcc)) {
77262306a36Sopenharmony_ci			err = PTR_ERR(bdev->vcc);
77362306a36Sopenharmony_ci			return err;
77462306a36Sopenharmony_ci		}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		bdev->osc = devm_clk_get_optional(&serdev->dev, "osc");
77762306a36Sopenharmony_ci		if (IS_ERR(bdev->osc)) {
77862306a36Sopenharmony_ci			err = PTR_ERR(bdev->osc);
77962306a36Sopenharmony_ci			return err;
78062306a36Sopenharmony_ci		}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci		bdev->boot = devm_gpiod_get_optional(&serdev->dev, "boot",
78362306a36Sopenharmony_ci						     GPIOD_OUT_LOW);
78462306a36Sopenharmony_ci		if (IS_ERR(bdev->boot)) {
78562306a36Sopenharmony_ci			err = PTR_ERR(bdev->boot);
78662306a36Sopenharmony_ci			return err;
78762306a36Sopenharmony_ci		}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci		bdev->pinctrl = devm_pinctrl_get(&serdev->dev);
79062306a36Sopenharmony_ci		if (IS_ERR(bdev->pinctrl)) {
79162306a36Sopenharmony_ci			err = PTR_ERR(bdev->pinctrl);
79262306a36Sopenharmony_ci			return err;
79362306a36Sopenharmony_ci		}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		bdev->pins_boot = pinctrl_lookup_state(bdev->pinctrl,
79662306a36Sopenharmony_ci						       "default");
79762306a36Sopenharmony_ci		if (IS_ERR(bdev->pins_boot) && !bdev->boot) {
79862306a36Sopenharmony_ci			err = PTR_ERR(bdev->pins_boot);
79962306a36Sopenharmony_ci			dev_err(&serdev->dev,
80062306a36Sopenharmony_ci				"Should assign RXD to LOW at boot stage\n");
80162306a36Sopenharmony_ci			return err;
80262306a36Sopenharmony_ci		}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci		bdev->pins_runtime = pinctrl_lookup_state(bdev->pinctrl,
80562306a36Sopenharmony_ci							  "runtime");
80662306a36Sopenharmony_ci		if (IS_ERR(bdev->pins_runtime)) {
80762306a36Sopenharmony_ci			err = PTR_ERR(bdev->pins_runtime);
80862306a36Sopenharmony_ci			return err;
80962306a36Sopenharmony_ci		}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci		bdev->reset = devm_gpiod_get_optional(&serdev->dev, "reset",
81262306a36Sopenharmony_ci						      GPIOD_OUT_LOW);
81362306a36Sopenharmony_ci		if (IS_ERR(bdev->reset)) {
81462306a36Sopenharmony_ci			err = PTR_ERR(bdev->reset);
81562306a36Sopenharmony_ci			return err;
81662306a36Sopenharmony_ci		}
81762306a36Sopenharmony_ci	} else if (btmtkuart_is_builtin_soc(bdev)) {
81862306a36Sopenharmony_ci		bdev->clk = devm_clk_get(&serdev->dev, "ref");
81962306a36Sopenharmony_ci		if (IS_ERR(bdev->clk))
82062306a36Sopenharmony_ci			return PTR_ERR(bdev->clk);
82162306a36Sopenharmony_ci	}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	return 0;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic int btmtkuart_probe(struct serdev_device *serdev)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	struct btmtkuart_dev *bdev;
82962306a36Sopenharmony_ci	struct hci_dev *hdev;
83062306a36Sopenharmony_ci	int err;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	bdev = devm_kzalloc(&serdev->dev, sizeof(*bdev), GFP_KERNEL);
83362306a36Sopenharmony_ci	if (!bdev)
83462306a36Sopenharmony_ci		return -ENOMEM;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	bdev->data = of_device_get_match_data(&serdev->dev);
83762306a36Sopenharmony_ci	if (!bdev->data)
83862306a36Sopenharmony_ci		return -ENODEV;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	bdev->serdev = serdev;
84162306a36Sopenharmony_ci	serdev_device_set_drvdata(serdev, bdev);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	serdev_device_set_client_ops(serdev, &btmtkuart_client_ops);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	err = btmtkuart_parse_dt(serdev);
84662306a36Sopenharmony_ci	if (err < 0)
84762306a36Sopenharmony_ci		return err;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	INIT_WORK(&bdev->tx_work, btmtkuart_tx_work);
85062306a36Sopenharmony_ci	skb_queue_head_init(&bdev->txq);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	/* Initialize and register HCI device */
85362306a36Sopenharmony_ci	hdev = hci_alloc_dev();
85462306a36Sopenharmony_ci	if (!hdev) {
85562306a36Sopenharmony_ci		dev_err(&serdev->dev, "Can't allocate HCI device\n");
85662306a36Sopenharmony_ci		return -ENOMEM;
85762306a36Sopenharmony_ci	}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	bdev->hdev = hdev;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	hdev->bus = HCI_UART;
86262306a36Sopenharmony_ci	hci_set_drvdata(hdev, bdev);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	hdev->open     = btmtkuart_open;
86562306a36Sopenharmony_ci	hdev->close    = btmtkuart_close;
86662306a36Sopenharmony_ci	hdev->flush    = btmtkuart_flush;
86762306a36Sopenharmony_ci	hdev->setup    = btmtkuart_setup;
86862306a36Sopenharmony_ci	hdev->shutdown = btmtkuart_shutdown;
86962306a36Sopenharmony_ci	hdev->send     = btmtkuart_send_frame;
87062306a36Sopenharmony_ci	hdev->set_bdaddr = btmtk_set_bdaddr;
87162306a36Sopenharmony_ci	SET_HCIDEV_DEV(hdev, &serdev->dev);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	hdev->manufacturer = 70;
87462306a36Sopenharmony_ci	set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	if (btmtkuart_is_standalone(bdev)) {
87762306a36Sopenharmony_ci		err = clk_prepare_enable(bdev->osc);
87862306a36Sopenharmony_ci		if (err < 0)
87962306a36Sopenharmony_ci			goto err_hci_free_dev;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci		if (bdev->boot) {
88262306a36Sopenharmony_ci			gpiod_set_value_cansleep(bdev->boot, 1);
88362306a36Sopenharmony_ci		} else {
88462306a36Sopenharmony_ci			/* Switch to the specific pin state for the booting
88562306a36Sopenharmony_ci			 * requires.
88662306a36Sopenharmony_ci			 */
88762306a36Sopenharmony_ci			pinctrl_select_state(bdev->pinctrl, bdev->pins_boot);
88862306a36Sopenharmony_ci		}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci		/* Power on */
89162306a36Sopenharmony_ci		err = regulator_enable(bdev->vcc);
89262306a36Sopenharmony_ci		if (err < 0)
89362306a36Sopenharmony_ci			goto err_clk_disable_unprepare;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		/* Reset if the reset-gpios is available otherwise the board
89662306a36Sopenharmony_ci		 * -level design should be guaranteed.
89762306a36Sopenharmony_ci		 */
89862306a36Sopenharmony_ci		if (bdev->reset) {
89962306a36Sopenharmony_ci			gpiod_set_value_cansleep(bdev->reset, 1);
90062306a36Sopenharmony_ci			usleep_range(1000, 2000);
90162306a36Sopenharmony_ci			gpiod_set_value_cansleep(bdev->reset, 0);
90262306a36Sopenharmony_ci		}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci		/* Wait some time until device got ready and switch to the pin
90562306a36Sopenharmony_ci		 * mode the device requires for UART transfers.
90662306a36Sopenharmony_ci		 */
90762306a36Sopenharmony_ci		msleep(50);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci		if (bdev->boot)
91062306a36Sopenharmony_ci			devm_gpiod_put(&serdev->dev, bdev->boot);
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci		pinctrl_select_state(bdev->pinctrl, bdev->pins_runtime);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci		/* A standalone device doesn't depends on power domain on SoC,
91562306a36Sopenharmony_ci		 * so mark it as no callbacks.
91662306a36Sopenharmony_ci		 */
91762306a36Sopenharmony_ci		pm_runtime_no_callbacks(&serdev->dev);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci		set_bit(BTMTKUART_REQUIRED_WAKEUP, &bdev->tx_state);
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	err = hci_register_dev(hdev);
92362306a36Sopenharmony_ci	if (err < 0) {
92462306a36Sopenharmony_ci		dev_err(&serdev->dev, "Can't register HCI device\n");
92562306a36Sopenharmony_ci		goto err_regulator_disable;
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	return 0;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_cierr_regulator_disable:
93162306a36Sopenharmony_ci	if (btmtkuart_is_standalone(bdev))
93262306a36Sopenharmony_ci		regulator_disable(bdev->vcc);
93362306a36Sopenharmony_cierr_clk_disable_unprepare:
93462306a36Sopenharmony_ci	if (btmtkuart_is_standalone(bdev))
93562306a36Sopenharmony_ci		clk_disable_unprepare(bdev->osc);
93662306a36Sopenharmony_cierr_hci_free_dev:
93762306a36Sopenharmony_ci	hci_free_dev(hdev);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	return err;
94062306a36Sopenharmony_ci}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_cistatic void btmtkuart_remove(struct serdev_device *serdev)
94362306a36Sopenharmony_ci{
94462306a36Sopenharmony_ci	struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);
94562306a36Sopenharmony_ci	struct hci_dev *hdev = bdev->hdev;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	if (btmtkuart_is_standalone(bdev)) {
94862306a36Sopenharmony_ci		regulator_disable(bdev->vcc);
94962306a36Sopenharmony_ci		clk_disable_unprepare(bdev->osc);
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	hci_unregister_dev(hdev);
95362306a36Sopenharmony_ci	hci_free_dev(hdev);
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic const struct btmtkuart_data mt7622_data __maybe_unused = {
95762306a36Sopenharmony_ci	.fwname = FIRMWARE_MT7622,
95862306a36Sopenharmony_ci};
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_cistatic const struct btmtkuart_data mt7663_data __maybe_unused = {
96162306a36Sopenharmony_ci	.flags = BTMTKUART_FLAG_STANDALONE_HW,
96262306a36Sopenharmony_ci	.fwname = FIRMWARE_MT7663,
96362306a36Sopenharmony_ci};
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_cistatic const struct btmtkuart_data mt7668_data __maybe_unused = {
96662306a36Sopenharmony_ci	.flags = BTMTKUART_FLAG_STANDALONE_HW,
96762306a36Sopenharmony_ci	.fwname = FIRMWARE_MT7668,
96862306a36Sopenharmony_ci};
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci#ifdef CONFIG_OF
97162306a36Sopenharmony_cistatic const struct of_device_id mtk_of_match_table[] = {
97262306a36Sopenharmony_ci	{ .compatible = "mediatek,mt7622-bluetooth", .data = &mt7622_data},
97362306a36Sopenharmony_ci	{ .compatible = "mediatek,mt7663u-bluetooth", .data = &mt7663_data},
97462306a36Sopenharmony_ci	{ .compatible = "mediatek,mt7668u-bluetooth", .data = &mt7668_data},
97562306a36Sopenharmony_ci	{ }
97662306a36Sopenharmony_ci};
97762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mtk_of_match_table);
97862306a36Sopenharmony_ci#endif
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_cistatic struct serdev_device_driver btmtkuart_driver = {
98162306a36Sopenharmony_ci	.probe = btmtkuart_probe,
98262306a36Sopenharmony_ci	.remove = btmtkuart_remove,
98362306a36Sopenharmony_ci	.driver = {
98462306a36Sopenharmony_ci		.name = "btmtkuart",
98562306a36Sopenharmony_ci		.of_match_table = of_match_ptr(mtk_of_match_table),
98662306a36Sopenharmony_ci	},
98762306a36Sopenharmony_ci};
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cimodule_serdev_device_driver(btmtkuart_driver);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ciMODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
99262306a36Sopenharmony_ciMODULE_DESCRIPTION("MediaTek Bluetooth Serial driver ver " VERSION);
99362306a36Sopenharmony_ciMODULE_VERSION(VERSION);
99462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
995