162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Bluetooth HCI UART H4 driver with Nokia Extensions AKA Nokia H4+
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2015 Marcel Holtmann <marcel@holtmann.org>
662306a36Sopenharmony_ci *  Copyright (C) 2015-2017 Sebastian Reichel <sre@kernel.org>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/errno.h>
1162306a36Sopenharmony_ci#include <linux/firmware.h>
1262306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/of.h>
1762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1862306a36Sopenharmony_ci#include <linux/serdev.h>
1962306a36Sopenharmony_ci#include <linux/skbuff.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/string.h>
2262306a36Sopenharmony_ci#include <linux/types.h>
2362306a36Sopenharmony_ci#include <asm/unaligned.h>
2462306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
2562306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "hci_uart.h"
2862306a36Sopenharmony_ci#include "btbcm.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define VERSION "0.1"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define NOKIA_ID_BCM2048	0x04
3362306a36Sopenharmony_ci#define NOKIA_ID_TI1271		0x31
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define FIRMWARE_BCM2048	"nokia/bcmfw.bin"
3662306a36Sopenharmony_ci#define FIRMWARE_TI1271		"nokia/ti1273.bin"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define HCI_NOKIA_NEG_PKT	0x06
3962306a36Sopenharmony_ci#define HCI_NOKIA_ALIVE_PKT	0x07
4062306a36Sopenharmony_ci#define HCI_NOKIA_RADIO_PKT	0x08
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define HCI_NOKIA_NEG_HDR_SIZE		1
4362306a36Sopenharmony_ci#define HCI_NOKIA_MAX_NEG_SIZE		255
4462306a36Sopenharmony_ci#define HCI_NOKIA_ALIVE_HDR_SIZE	1
4562306a36Sopenharmony_ci#define HCI_NOKIA_MAX_ALIVE_SIZE	255
4662306a36Sopenharmony_ci#define HCI_NOKIA_RADIO_HDR_SIZE	2
4762306a36Sopenharmony_ci#define HCI_NOKIA_MAX_RADIO_SIZE	255
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define NOKIA_PROTO_PKT		0x44
5062306a36Sopenharmony_ci#define NOKIA_PROTO_BYTE	0x4c
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define NOKIA_NEG_REQ		0x00
5362306a36Sopenharmony_ci#define NOKIA_NEG_ACK		0x20
5462306a36Sopenharmony_ci#define NOKIA_NEG_NAK		0x40
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define H4_TYPE_SIZE		1
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define NOKIA_RECV_ALIVE \
5962306a36Sopenharmony_ci	.type = HCI_NOKIA_ALIVE_PKT, \
6062306a36Sopenharmony_ci	.hlen = HCI_NOKIA_ALIVE_HDR_SIZE, \
6162306a36Sopenharmony_ci	.loff = 0, \
6262306a36Sopenharmony_ci	.lsize = 1, \
6362306a36Sopenharmony_ci	.maxlen = HCI_NOKIA_MAX_ALIVE_SIZE \
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define NOKIA_RECV_NEG \
6662306a36Sopenharmony_ci	.type = HCI_NOKIA_NEG_PKT, \
6762306a36Sopenharmony_ci	.hlen = HCI_NOKIA_NEG_HDR_SIZE, \
6862306a36Sopenharmony_ci	.loff = 0, \
6962306a36Sopenharmony_ci	.lsize = 1, \
7062306a36Sopenharmony_ci	.maxlen = HCI_NOKIA_MAX_NEG_SIZE \
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define NOKIA_RECV_RADIO \
7362306a36Sopenharmony_ci	.type = HCI_NOKIA_RADIO_PKT, \
7462306a36Sopenharmony_ci	.hlen = HCI_NOKIA_RADIO_HDR_SIZE, \
7562306a36Sopenharmony_ci	.loff = 1, \
7662306a36Sopenharmony_ci	.lsize = 1, \
7762306a36Sopenharmony_ci	.maxlen = HCI_NOKIA_MAX_RADIO_SIZE \
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistruct hci_nokia_neg_hdr {
8062306a36Sopenharmony_ci	u8	dlen;
8162306a36Sopenharmony_ci} __packed;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct hci_nokia_neg_cmd {
8462306a36Sopenharmony_ci	u8	ack;
8562306a36Sopenharmony_ci	u16	baud;
8662306a36Sopenharmony_ci	u16	unused1;
8762306a36Sopenharmony_ci	u8	proto;
8862306a36Sopenharmony_ci	u16	sys_clk;
8962306a36Sopenharmony_ci	u16	unused2;
9062306a36Sopenharmony_ci} __packed;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define NOKIA_ALIVE_REQ   0x55
9362306a36Sopenharmony_ci#define NOKIA_ALIVE_RESP  0xcc
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistruct hci_nokia_alive_hdr {
9662306a36Sopenharmony_ci	u8	dlen;
9762306a36Sopenharmony_ci} __packed;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistruct hci_nokia_alive_pkt {
10062306a36Sopenharmony_ci	u8	mid;
10162306a36Sopenharmony_ci	u8	unused;
10262306a36Sopenharmony_ci} __packed;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistruct hci_nokia_neg_evt {
10562306a36Sopenharmony_ci	u8	ack;
10662306a36Sopenharmony_ci	u16	baud;
10762306a36Sopenharmony_ci	u16	unused1;
10862306a36Sopenharmony_ci	u8	proto;
10962306a36Sopenharmony_ci	u16	sys_clk;
11062306a36Sopenharmony_ci	u16	unused2;
11162306a36Sopenharmony_ci	u8	man_id;
11262306a36Sopenharmony_ci	u8	ver_id;
11362306a36Sopenharmony_ci} __packed;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#define MAX_BAUD_RATE		3692300
11662306a36Sopenharmony_ci#define SETUP_BAUD_RATE		921600
11762306a36Sopenharmony_ci#define INIT_BAUD_RATE		120000
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistruct hci_nokia_radio_hdr {
12062306a36Sopenharmony_ci	u8	evt;
12162306a36Sopenharmony_ci	u8	dlen;
12262306a36Sopenharmony_ci} __packed;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistruct nokia_bt_dev {
12562306a36Sopenharmony_ci	struct hci_uart hu;
12662306a36Sopenharmony_ci	struct serdev_device *serdev;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	struct gpio_desc *reset;
12962306a36Sopenharmony_ci	struct gpio_desc *wakeup_host;
13062306a36Sopenharmony_ci	struct gpio_desc *wakeup_bt;
13162306a36Sopenharmony_ci	unsigned long sysclk_speed;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	int wake_irq;
13462306a36Sopenharmony_ci	struct sk_buff *rx_skb;
13562306a36Sopenharmony_ci	struct sk_buff_head txq;
13662306a36Sopenharmony_ci	bdaddr_t bdaddr;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	int init_error;
13962306a36Sopenharmony_ci	struct completion init_completion;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	u8 man_id;
14262306a36Sopenharmony_ci	u8 ver_id;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	bool initialized;
14562306a36Sopenharmony_ci	bool tx_enabled;
14662306a36Sopenharmony_ci	bool rx_enabled;
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void nokia_flow_control(struct serdev_device *serdev, bool enable)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	if (enable) {
15462306a36Sopenharmony_ci		serdev_device_set_rts(serdev, true);
15562306a36Sopenharmony_ci		serdev_device_set_flow_control(serdev, true);
15662306a36Sopenharmony_ci	} else {
15762306a36Sopenharmony_ci		serdev_device_set_flow_control(serdev, false);
15862306a36Sopenharmony_ci		serdev_device_set_rts(serdev, false);
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic irqreturn_t wakeup_handler(int irq, void *data)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = data;
16562306a36Sopenharmony_ci	struct device *dev = &btdev->serdev->dev;
16662306a36Sopenharmony_ci	int wake_state = gpiod_get_value(btdev->wakeup_host);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (btdev->rx_enabled == wake_state)
16962306a36Sopenharmony_ci		return IRQ_HANDLED;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (wake_state)
17262306a36Sopenharmony_ci		pm_runtime_get(dev);
17362306a36Sopenharmony_ci	else
17462306a36Sopenharmony_ci		pm_runtime_put(dev);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	btdev->rx_enabled = wake_state;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return IRQ_HANDLED;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic int nokia_reset(struct hci_uart *hu)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
18462306a36Sopenharmony_ci	struct device *dev = &btdev->serdev->dev;
18562306a36Sopenharmony_ci	int err;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	/* reset routine */
18862306a36Sopenharmony_ci	gpiod_set_value_cansleep(btdev->reset, 1);
18962306a36Sopenharmony_ci	gpiod_set_value_cansleep(btdev->wakeup_bt, 1);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	msleep(100);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/* safety check */
19462306a36Sopenharmony_ci	err = gpiod_get_value_cansleep(btdev->wakeup_host);
19562306a36Sopenharmony_ci	if (err == 1) {
19662306a36Sopenharmony_ci		dev_err(dev, "reset: host wakeup not low!");
19762306a36Sopenharmony_ci		return -EPROTO;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	/* flush queue */
20162306a36Sopenharmony_ci	serdev_device_write_flush(btdev->serdev);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	/* init uart */
20462306a36Sopenharmony_ci	nokia_flow_control(btdev->serdev, false);
20562306a36Sopenharmony_ci	serdev_device_set_baudrate(btdev->serdev, INIT_BAUD_RATE);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	gpiod_set_value_cansleep(btdev->reset, 0);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* wait for cts */
21062306a36Sopenharmony_ci	err = serdev_device_wait_for_cts(btdev->serdev, true, 200);
21162306a36Sopenharmony_ci	if (err < 0) {
21262306a36Sopenharmony_ci		dev_err(dev, "CTS not received: %d", err);
21362306a36Sopenharmony_ci		return err;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	nokia_flow_control(btdev->serdev, true);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return 0;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int nokia_send_alive_packet(struct hci_uart *hu)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
22462306a36Sopenharmony_ci	struct device *dev = &btdev->serdev->dev;
22562306a36Sopenharmony_ci	struct hci_nokia_alive_hdr *hdr;
22662306a36Sopenharmony_ci	struct hci_nokia_alive_pkt *pkt;
22762306a36Sopenharmony_ci	struct sk_buff *skb;
22862306a36Sopenharmony_ci	int len;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	init_completion(&btdev->init_completion);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	len = H4_TYPE_SIZE + sizeof(*hdr) + sizeof(*pkt);
23362306a36Sopenharmony_ci	skb = bt_skb_alloc(len, GFP_KERNEL);
23462306a36Sopenharmony_ci	if (!skb)
23562306a36Sopenharmony_ci		return -ENOMEM;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	hci_skb_pkt_type(skb) = HCI_NOKIA_ALIVE_PKT;
23862306a36Sopenharmony_ci	memset(skb->data, 0x00, len);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	hdr = skb_put(skb, sizeof(*hdr));
24162306a36Sopenharmony_ci	hdr->dlen = sizeof(*pkt);
24262306a36Sopenharmony_ci	pkt = skb_put(skb, sizeof(*pkt));
24362306a36Sopenharmony_ci	pkt->mid = NOKIA_ALIVE_REQ;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	nokia_enqueue(hu, skb);
24662306a36Sopenharmony_ci	hci_uart_tx_wakeup(hu);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	dev_dbg(dev, "Alive sent");
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (!wait_for_completion_interruptible_timeout(&btdev->init_completion,
25162306a36Sopenharmony_ci		msecs_to_jiffies(1000))) {
25262306a36Sopenharmony_ci		return -ETIMEDOUT;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (btdev->init_error < 0)
25662306a36Sopenharmony_ci		return btdev->init_error;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return 0;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic int nokia_send_negotiation(struct hci_uart *hu)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
26462306a36Sopenharmony_ci	struct device *dev = &btdev->serdev->dev;
26562306a36Sopenharmony_ci	struct hci_nokia_neg_cmd *neg_cmd;
26662306a36Sopenharmony_ci	struct hci_nokia_neg_hdr *neg_hdr;
26762306a36Sopenharmony_ci	struct sk_buff *skb;
26862306a36Sopenharmony_ci	int len, err;
26962306a36Sopenharmony_ci	u16 baud = DIV_ROUND_CLOSEST(btdev->sysclk_speed * 10, SETUP_BAUD_RATE);
27062306a36Sopenharmony_ci	int sysclk = btdev->sysclk_speed / 1000;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	len = H4_TYPE_SIZE + sizeof(*neg_hdr) + sizeof(*neg_cmd);
27362306a36Sopenharmony_ci	skb = bt_skb_alloc(len, GFP_KERNEL);
27462306a36Sopenharmony_ci	if (!skb)
27562306a36Sopenharmony_ci		return -ENOMEM;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	hci_skb_pkt_type(skb) = HCI_NOKIA_NEG_PKT;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	neg_hdr = skb_put(skb, sizeof(*neg_hdr));
28062306a36Sopenharmony_ci	neg_hdr->dlen = sizeof(*neg_cmd);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	neg_cmd = skb_put(skb, sizeof(*neg_cmd));
28362306a36Sopenharmony_ci	neg_cmd->ack = NOKIA_NEG_REQ;
28462306a36Sopenharmony_ci	neg_cmd->baud = cpu_to_le16(baud);
28562306a36Sopenharmony_ci	neg_cmd->unused1 = 0x0000;
28662306a36Sopenharmony_ci	neg_cmd->proto = NOKIA_PROTO_BYTE;
28762306a36Sopenharmony_ci	neg_cmd->sys_clk = cpu_to_le16(sysclk);
28862306a36Sopenharmony_ci	neg_cmd->unused2 = 0x0000;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	btdev->init_error = 0;
29162306a36Sopenharmony_ci	init_completion(&btdev->init_completion);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	nokia_enqueue(hu, skb);
29462306a36Sopenharmony_ci	hci_uart_tx_wakeup(hu);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	dev_dbg(dev, "Negotiation sent");
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (!wait_for_completion_interruptible_timeout(&btdev->init_completion,
29962306a36Sopenharmony_ci		msecs_to_jiffies(10000))) {
30062306a36Sopenharmony_ci		return -ETIMEDOUT;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (btdev->init_error < 0)
30462306a36Sopenharmony_ci		return btdev->init_error;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* Change to previously negotiated speed. Flow Control
30762306a36Sopenharmony_ci	 * is disabled until bluetooth adapter is ready to avoid
30862306a36Sopenharmony_ci	 * broken bytes being received.
30962306a36Sopenharmony_ci	 */
31062306a36Sopenharmony_ci	nokia_flow_control(btdev->serdev, false);
31162306a36Sopenharmony_ci	serdev_device_set_baudrate(btdev->serdev, SETUP_BAUD_RATE);
31262306a36Sopenharmony_ci	err = serdev_device_wait_for_cts(btdev->serdev, true, 200);
31362306a36Sopenharmony_ci	if (err < 0) {
31462306a36Sopenharmony_ci		dev_err(dev, "CTS not received: %d", err);
31562306a36Sopenharmony_ci		return err;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci	nokia_flow_control(btdev->serdev, true);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	dev_dbg(dev, "Negotiation successful");
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return 0;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic int nokia_setup_fw(struct hci_uart *hu)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
32762306a36Sopenharmony_ci	struct device *dev = &btdev->serdev->dev;
32862306a36Sopenharmony_ci	const char *fwname;
32962306a36Sopenharmony_ci	const struct firmware *fw;
33062306a36Sopenharmony_ci	const u8 *fw_ptr;
33162306a36Sopenharmony_ci	size_t fw_size;
33262306a36Sopenharmony_ci	int err;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	dev_dbg(dev, "setup firmware");
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (btdev->man_id == NOKIA_ID_BCM2048) {
33762306a36Sopenharmony_ci		fwname = FIRMWARE_BCM2048;
33862306a36Sopenharmony_ci	} else if (btdev->man_id == NOKIA_ID_TI1271) {
33962306a36Sopenharmony_ci		fwname = FIRMWARE_TI1271;
34062306a36Sopenharmony_ci	} else {
34162306a36Sopenharmony_ci		dev_err(dev, "Unsupported bluetooth device!");
34262306a36Sopenharmony_ci		return -ENODEV;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	err = request_firmware(&fw, fwname, dev);
34662306a36Sopenharmony_ci	if (err < 0) {
34762306a36Sopenharmony_ci		dev_err(dev, "%s: Failed to load Nokia firmware file (%d)",
34862306a36Sopenharmony_ci			hu->hdev->name, err);
34962306a36Sopenharmony_ci		return err;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	fw_ptr = fw->data;
35362306a36Sopenharmony_ci	fw_size = fw->size;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	while (fw_size >= 4) {
35662306a36Sopenharmony_ci		u16 pkt_size = get_unaligned_le16(fw_ptr);
35762306a36Sopenharmony_ci		u8 pkt_type = fw_ptr[2];
35862306a36Sopenharmony_ci		const struct hci_command_hdr *cmd;
35962306a36Sopenharmony_ci		u16 opcode;
36062306a36Sopenharmony_ci		struct sk_buff *skb;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci		switch (pkt_type) {
36362306a36Sopenharmony_ci		case HCI_COMMAND_PKT:
36462306a36Sopenharmony_ci			cmd = (struct hci_command_hdr *)(fw_ptr + 3);
36562306a36Sopenharmony_ci			opcode = le16_to_cpu(cmd->opcode);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci			skb = __hci_cmd_sync(hu->hdev, opcode, cmd->plen,
36862306a36Sopenharmony_ci					     fw_ptr + 3 + HCI_COMMAND_HDR_SIZE,
36962306a36Sopenharmony_ci					     HCI_INIT_TIMEOUT);
37062306a36Sopenharmony_ci			if (IS_ERR(skb)) {
37162306a36Sopenharmony_ci				err = PTR_ERR(skb);
37262306a36Sopenharmony_ci				dev_err(dev, "%s: FW command %04x failed (%d)",
37362306a36Sopenharmony_ci				       hu->hdev->name, opcode, err);
37462306a36Sopenharmony_ci				goto done;
37562306a36Sopenharmony_ci			}
37662306a36Sopenharmony_ci			kfree_skb(skb);
37762306a36Sopenharmony_ci			break;
37862306a36Sopenharmony_ci		case HCI_NOKIA_RADIO_PKT:
37962306a36Sopenharmony_ci		case HCI_NOKIA_NEG_PKT:
38062306a36Sopenharmony_ci		case HCI_NOKIA_ALIVE_PKT:
38162306a36Sopenharmony_ci			break;
38262306a36Sopenharmony_ci		}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		fw_ptr += pkt_size + 2;
38562306a36Sopenharmony_ci		fw_size -= pkt_size + 2;
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cidone:
38962306a36Sopenharmony_ci	release_firmware(fw);
39062306a36Sopenharmony_ci	return err;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic int nokia_setup(struct hci_uart *hu)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
39662306a36Sopenharmony_ci	struct device *dev = &btdev->serdev->dev;
39762306a36Sopenharmony_ci	int err;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	btdev->initialized = false;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	nokia_flow_control(btdev->serdev, false);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	pm_runtime_get_sync(dev);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (btdev->tx_enabled) {
40662306a36Sopenharmony_ci		gpiod_set_value_cansleep(btdev->wakeup_bt, 0);
40762306a36Sopenharmony_ci		pm_runtime_put(&btdev->serdev->dev);
40862306a36Sopenharmony_ci		btdev->tx_enabled = false;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	dev_dbg(dev, "protocol setup");
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/* 0. reset connection */
41462306a36Sopenharmony_ci	err = nokia_reset(hu);
41562306a36Sopenharmony_ci	if (err < 0) {
41662306a36Sopenharmony_ci		dev_err(dev, "Reset failed: %d", err);
41762306a36Sopenharmony_ci		goto out;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* 1. negotiate speed etc */
42162306a36Sopenharmony_ci	err = nokia_send_negotiation(hu);
42262306a36Sopenharmony_ci	if (err < 0) {
42362306a36Sopenharmony_ci		dev_err(dev, "Negotiation failed: %d", err);
42462306a36Sopenharmony_ci		goto out;
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/* 2. verify correct setup using alive packet */
42862306a36Sopenharmony_ci	err = nokia_send_alive_packet(hu);
42962306a36Sopenharmony_ci	if (err < 0) {
43062306a36Sopenharmony_ci		dev_err(dev, "Alive check failed: %d", err);
43162306a36Sopenharmony_ci		goto out;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	/* 3. send firmware */
43562306a36Sopenharmony_ci	err = nokia_setup_fw(hu);
43662306a36Sopenharmony_ci	if (err < 0) {
43762306a36Sopenharmony_ci		dev_err(dev, "Could not setup FW: %d", err);
43862306a36Sopenharmony_ci		goto out;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	nokia_flow_control(btdev->serdev, false);
44262306a36Sopenharmony_ci	serdev_device_set_baudrate(btdev->serdev, MAX_BAUD_RATE);
44362306a36Sopenharmony_ci	nokia_flow_control(btdev->serdev, true);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (btdev->man_id == NOKIA_ID_BCM2048) {
44662306a36Sopenharmony_ci		hu->hdev->set_bdaddr = btbcm_set_bdaddr;
44762306a36Sopenharmony_ci		set_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks);
44862306a36Sopenharmony_ci		dev_dbg(dev, "bcm2048 has invalid bluetooth address!");
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	dev_dbg(dev, "protocol setup done!");
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	gpiod_set_value_cansleep(btdev->wakeup_bt, 0);
45462306a36Sopenharmony_ci	pm_runtime_put(dev);
45562306a36Sopenharmony_ci	btdev->tx_enabled = false;
45662306a36Sopenharmony_ci	btdev->initialized = true;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return 0;
45962306a36Sopenharmony_ciout:
46062306a36Sopenharmony_ci	pm_runtime_put(dev);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	return err;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic int nokia_open(struct hci_uart *hu)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	struct device *dev = &hu->serdev->dev;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	dev_dbg(dev, "protocol open");
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	pm_runtime_enable(dev);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	return 0;
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic int nokia_flush(struct hci_uart *hu)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	dev_dbg(&btdev->serdev->dev, "flush device");
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	skb_queue_purge(&btdev->txq);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	return 0;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic int nokia_close(struct hci_uart *hu)
48862306a36Sopenharmony_ci{
48962306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
49062306a36Sopenharmony_ci	struct device *dev = &btdev->serdev->dev;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	dev_dbg(dev, "close device");
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	btdev->initialized = false;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	skb_queue_purge(&btdev->txq);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	kfree_skb(btdev->rx_skb);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	/* disable module */
50162306a36Sopenharmony_ci	gpiod_set_value(btdev->reset, 1);
50262306a36Sopenharmony_ci	gpiod_set_value(btdev->wakeup_bt, 0);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	pm_runtime_disable(&btdev->serdev->dev);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	return 0;
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci/* Enqueue frame for transmittion (padding, crc, etc) */
51062306a36Sopenharmony_cistatic int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
51362306a36Sopenharmony_ci	int err;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/* Prepend skb with frame type */
51662306a36Sopenharmony_ci	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* Packets must be word aligned */
51962306a36Sopenharmony_ci	if (skb->len % 2) {
52062306a36Sopenharmony_ci		err = skb_pad(skb, 1);
52162306a36Sopenharmony_ci		if (err)
52262306a36Sopenharmony_ci			return err;
52362306a36Sopenharmony_ci		skb_put(skb, 1);
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	skb_queue_tail(&btdev->txq, skb);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return 0;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic int nokia_recv_negotiation_packet(struct hci_dev *hdev,
53262306a36Sopenharmony_ci					 struct sk_buff *skb)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	struct hci_uart *hu = hci_get_drvdata(hdev);
53562306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
53662306a36Sopenharmony_ci	struct device *dev = &btdev->serdev->dev;
53762306a36Sopenharmony_ci	struct hci_nokia_neg_hdr *hdr;
53862306a36Sopenharmony_ci	struct hci_nokia_neg_evt *evt;
53962306a36Sopenharmony_ci	int ret = 0;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	hdr = (struct hci_nokia_neg_hdr *)skb->data;
54262306a36Sopenharmony_ci	if (hdr->dlen != sizeof(*evt)) {
54362306a36Sopenharmony_ci		btdev->init_error = -EIO;
54462306a36Sopenharmony_ci		ret = -EIO;
54562306a36Sopenharmony_ci		goto finish_neg;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	evt = skb_pull(skb, sizeof(*hdr));
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (evt->ack != NOKIA_NEG_ACK) {
55162306a36Sopenharmony_ci		dev_err(dev, "Negotiation received: wrong reply");
55262306a36Sopenharmony_ci		btdev->init_error = -EINVAL;
55362306a36Sopenharmony_ci		ret = -EINVAL;
55462306a36Sopenharmony_ci		goto finish_neg;
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	btdev->man_id = evt->man_id;
55862306a36Sopenharmony_ci	btdev->ver_id = evt->ver_id;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	dev_dbg(dev, "Negotiation received: baud=%u:clk=%u:manu=%u:vers=%u",
56162306a36Sopenharmony_ci		evt->baud, evt->sys_clk, evt->man_id, evt->ver_id);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cifinish_neg:
56462306a36Sopenharmony_ci	complete(&btdev->init_completion);
56562306a36Sopenharmony_ci	kfree_skb(skb);
56662306a36Sopenharmony_ci	return ret;
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic int nokia_recv_alive_packet(struct hci_dev *hdev, struct sk_buff *skb)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	struct hci_uart *hu = hci_get_drvdata(hdev);
57262306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
57362306a36Sopenharmony_ci	struct device *dev = &btdev->serdev->dev;
57462306a36Sopenharmony_ci	struct hci_nokia_alive_hdr *hdr;
57562306a36Sopenharmony_ci	struct hci_nokia_alive_pkt *pkt;
57662306a36Sopenharmony_ci	int ret = 0;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	hdr = (struct hci_nokia_alive_hdr *)skb->data;
57962306a36Sopenharmony_ci	if (hdr->dlen != sizeof(*pkt)) {
58062306a36Sopenharmony_ci		dev_err(dev, "Corrupted alive message");
58162306a36Sopenharmony_ci		btdev->init_error = -EIO;
58262306a36Sopenharmony_ci		ret = -EIO;
58362306a36Sopenharmony_ci		goto finish_alive;
58462306a36Sopenharmony_ci	}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	pkt = skb_pull(skb, sizeof(*hdr));
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (pkt->mid != NOKIA_ALIVE_RESP) {
58962306a36Sopenharmony_ci		dev_err(dev, "Alive received: invalid response: 0x%02x!",
59062306a36Sopenharmony_ci			pkt->mid);
59162306a36Sopenharmony_ci		btdev->init_error = -EINVAL;
59262306a36Sopenharmony_ci		ret = -EINVAL;
59362306a36Sopenharmony_ci		goto finish_alive;
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	dev_dbg(dev, "Alive received");
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cifinish_alive:
59962306a36Sopenharmony_ci	complete(&btdev->init_completion);
60062306a36Sopenharmony_ci	kfree_skb(skb);
60162306a36Sopenharmony_ci	return ret;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic int nokia_recv_radio(struct hci_dev *hdev, struct sk_buff *skb)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	/* Packets received on the dedicated radio channel are
60762306a36Sopenharmony_ci	 * HCI events and so feed them back into the core.
60862306a36Sopenharmony_ci	 */
60962306a36Sopenharmony_ci	hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
61062306a36Sopenharmony_ci	return hci_recv_frame(hdev, skb);
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci/* Recv data */
61462306a36Sopenharmony_cistatic const struct h4_recv_pkt nokia_recv_pkts[] = {
61562306a36Sopenharmony_ci	{ H4_RECV_ACL,		.recv = hci_recv_frame },
61662306a36Sopenharmony_ci	{ H4_RECV_SCO,		.recv = hci_recv_frame },
61762306a36Sopenharmony_ci	{ H4_RECV_EVENT,	.recv = hci_recv_frame },
61862306a36Sopenharmony_ci	{ NOKIA_RECV_ALIVE,	.recv = nokia_recv_alive_packet },
61962306a36Sopenharmony_ci	{ NOKIA_RECV_NEG,	.recv = nokia_recv_negotiation_packet },
62062306a36Sopenharmony_ci	{ NOKIA_RECV_RADIO,	.recv = nokia_recv_radio },
62162306a36Sopenharmony_ci};
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic int nokia_recv(struct hci_uart *hu, const void *data, int count)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
62662306a36Sopenharmony_ci	struct device *dev = &btdev->serdev->dev;
62762306a36Sopenharmony_ci	int err;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
63062306a36Sopenharmony_ci		return -EUNATCH;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	btdev->rx_skb = h4_recv_buf(hu->hdev, btdev->rx_skb, data, count,
63362306a36Sopenharmony_ci				  nokia_recv_pkts, ARRAY_SIZE(nokia_recv_pkts));
63462306a36Sopenharmony_ci	if (IS_ERR(btdev->rx_skb)) {
63562306a36Sopenharmony_ci		err = PTR_ERR(btdev->rx_skb);
63662306a36Sopenharmony_ci		dev_err(dev, "Frame reassembly failed (%d)", err);
63762306a36Sopenharmony_ci		btdev->rx_skb = NULL;
63862306a36Sopenharmony_ci		return err;
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	return count;
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistatic struct sk_buff *nokia_dequeue(struct hci_uart *hu)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = hu->priv;
64762306a36Sopenharmony_ci	struct device *dev = &btdev->serdev->dev;
64862306a36Sopenharmony_ci	struct sk_buff *result = skb_dequeue(&btdev->txq);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if (!btdev->initialized)
65162306a36Sopenharmony_ci		return result;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (btdev->tx_enabled == !!result)
65462306a36Sopenharmony_ci		return result;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	if (result) {
65762306a36Sopenharmony_ci		pm_runtime_get_sync(dev);
65862306a36Sopenharmony_ci		gpiod_set_value_cansleep(btdev->wakeup_bt, 1);
65962306a36Sopenharmony_ci	} else {
66062306a36Sopenharmony_ci		serdev_device_wait_until_sent(btdev->serdev, 0);
66162306a36Sopenharmony_ci		gpiod_set_value_cansleep(btdev->wakeup_bt, 0);
66262306a36Sopenharmony_ci		pm_runtime_put(dev);
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	btdev->tx_enabled = !!result;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	return result;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic const struct hci_uart_proto nokia_proto = {
67162306a36Sopenharmony_ci	.id		= HCI_UART_NOKIA,
67262306a36Sopenharmony_ci	.name		= "Nokia",
67362306a36Sopenharmony_ci	.open		= nokia_open,
67462306a36Sopenharmony_ci	.close		= nokia_close,
67562306a36Sopenharmony_ci	.recv		= nokia_recv,
67662306a36Sopenharmony_ci	.enqueue	= nokia_enqueue,
67762306a36Sopenharmony_ci	.dequeue	= nokia_dequeue,
67862306a36Sopenharmony_ci	.flush		= nokia_flush,
67962306a36Sopenharmony_ci	.setup		= nokia_setup,
68062306a36Sopenharmony_ci	.manufacturer	= 1,
68162306a36Sopenharmony_ci};
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_cistatic int nokia_bluetooth_serdev_probe(struct serdev_device *serdev)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	struct device *dev = &serdev->dev;
68662306a36Sopenharmony_ci	struct nokia_bt_dev *btdev;
68762306a36Sopenharmony_ci	struct clk *sysclk;
68862306a36Sopenharmony_ci	int err = 0;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	btdev = devm_kzalloc(dev, sizeof(*btdev), GFP_KERNEL);
69162306a36Sopenharmony_ci	if (!btdev)
69262306a36Sopenharmony_ci		return -ENOMEM;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	btdev->hu.serdev = btdev->serdev = serdev;
69562306a36Sopenharmony_ci	serdev_device_set_drvdata(serdev, btdev);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	btdev->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
69862306a36Sopenharmony_ci	if (IS_ERR(btdev->reset)) {
69962306a36Sopenharmony_ci		err = PTR_ERR(btdev->reset);
70062306a36Sopenharmony_ci		dev_err(dev, "could not get reset gpio: %d", err);
70162306a36Sopenharmony_ci		return err;
70262306a36Sopenharmony_ci	}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	btdev->wakeup_host = devm_gpiod_get(dev, "host-wakeup", GPIOD_IN);
70562306a36Sopenharmony_ci	if (IS_ERR(btdev->wakeup_host)) {
70662306a36Sopenharmony_ci		err = PTR_ERR(btdev->wakeup_host);
70762306a36Sopenharmony_ci		dev_err(dev, "could not get host wakeup gpio: %d", err);
70862306a36Sopenharmony_ci		return err;
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	btdev->wake_irq = gpiod_to_irq(btdev->wakeup_host);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	err = devm_request_threaded_irq(dev, btdev->wake_irq, NULL,
71462306a36Sopenharmony_ci		wakeup_handler,
71562306a36Sopenharmony_ci		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
71662306a36Sopenharmony_ci		"wakeup", btdev);
71762306a36Sopenharmony_ci	if (err) {
71862306a36Sopenharmony_ci		dev_err(dev, "could request wakeup irq: %d", err);
71962306a36Sopenharmony_ci		return err;
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	btdev->wakeup_bt = devm_gpiod_get(dev, "bluetooth-wakeup",
72362306a36Sopenharmony_ci					   GPIOD_OUT_LOW);
72462306a36Sopenharmony_ci	if (IS_ERR(btdev->wakeup_bt)) {
72562306a36Sopenharmony_ci		err = PTR_ERR(btdev->wakeup_bt);
72662306a36Sopenharmony_ci		dev_err(dev, "could not get BT wakeup gpio: %d", err);
72762306a36Sopenharmony_ci		return err;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	sysclk = devm_clk_get(dev, "sysclk");
73162306a36Sopenharmony_ci	if (IS_ERR(sysclk)) {
73262306a36Sopenharmony_ci		err = PTR_ERR(sysclk);
73362306a36Sopenharmony_ci		dev_err(dev, "could not get sysclk: %d", err);
73462306a36Sopenharmony_ci		return err;
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	err = clk_prepare_enable(sysclk);
73862306a36Sopenharmony_ci	if (err) {
73962306a36Sopenharmony_ci		dev_err(dev, "could not enable sysclk: %d", err);
74062306a36Sopenharmony_ci		return err;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci	btdev->sysclk_speed = clk_get_rate(sysclk);
74362306a36Sopenharmony_ci	clk_disable_unprepare(sysclk);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	skb_queue_head_init(&btdev->txq);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	btdev->hu.priv = btdev;
74862306a36Sopenharmony_ci	btdev->hu.alignment = 2; /* Nokia H4+ is word aligned */
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	err = hci_uart_register_device(&btdev->hu, &nokia_proto);
75162306a36Sopenharmony_ci	if (err) {
75262306a36Sopenharmony_ci		dev_err(dev, "could not register bluetooth uart: %d", err);
75362306a36Sopenharmony_ci		return err;
75462306a36Sopenharmony_ci	}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	return 0;
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_cistatic void nokia_bluetooth_serdev_remove(struct serdev_device *serdev)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	struct nokia_bt_dev *btdev = serdev_device_get_drvdata(serdev);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	hci_uart_unregister_device(&btdev->hu);
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_cistatic int nokia_bluetooth_runtime_suspend(struct device *dev)
76762306a36Sopenharmony_ci{
76862306a36Sopenharmony_ci	struct serdev_device *serdev = to_serdev_device(dev);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	nokia_flow_control(serdev, false);
77162306a36Sopenharmony_ci	return 0;
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic int nokia_bluetooth_runtime_resume(struct device *dev)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	struct serdev_device *serdev = to_serdev_device(dev);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	nokia_flow_control(serdev, true);
77962306a36Sopenharmony_ci	return 0;
78062306a36Sopenharmony_ci}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_cistatic const struct dev_pm_ops nokia_bluetooth_pm_ops = {
78362306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(nokia_bluetooth_runtime_suspend,
78462306a36Sopenharmony_ci			   nokia_bluetooth_runtime_resume,
78562306a36Sopenharmony_ci			   NULL)
78662306a36Sopenharmony_ci};
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci#ifdef CONFIG_OF
78962306a36Sopenharmony_cistatic const struct of_device_id nokia_bluetooth_of_match[] = {
79062306a36Sopenharmony_ci	{ .compatible = "nokia,h4p-bluetooth", },
79162306a36Sopenharmony_ci	{},
79262306a36Sopenharmony_ci};
79362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, nokia_bluetooth_of_match);
79462306a36Sopenharmony_ci#endif
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_cistatic struct serdev_device_driver nokia_bluetooth_serdev_driver = {
79762306a36Sopenharmony_ci	.probe = nokia_bluetooth_serdev_probe,
79862306a36Sopenharmony_ci	.remove = nokia_bluetooth_serdev_remove,
79962306a36Sopenharmony_ci	.driver = {
80062306a36Sopenharmony_ci		.name = "nokia-bluetooth",
80162306a36Sopenharmony_ci		.pm = &nokia_bluetooth_pm_ops,
80262306a36Sopenharmony_ci		.of_match_table = of_match_ptr(nokia_bluetooth_of_match),
80362306a36Sopenharmony_ci	},
80462306a36Sopenharmony_ci};
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cimodule_serdev_device_driver(nokia_bluetooth_serdev_driver);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ciMODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
80962306a36Sopenharmony_ciMODULE_DESCRIPTION("Bluetooth HCI UART Nokia H4+ driver ver " VERSION);
81062306a36Sopenharmony_ciMODULE_VERSION(VERSION);
81162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
812