11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
27dec65c8SJohan Hedberg /*
37dec65c8SJohan Hedberg *
47dec65c8SJohan Hedberg * Bluetooth HCI Three-wire UART driver
57dec65c8SJohan Hedberg *
67dec65c8SJohan Hedberg * Copyright (C) 2012 Intel Corporation
77dec65c8SJohan Hedberg */
87dec65c8SJohan Hedberg
94eb3cbc4SJeremy Cline #include <linux/acpi.h>
107dec65c8SJohan Hedberg #include <linux/errno.h>
114c791489SHans de Goede #include <linux/gpio/consumer.h>
124eb3cbc4SJeremy Cline #include <linux/kernel.h>
134eb3cbc4SJeremy Cline #include <linux/mod_devicetable.h>
14e15f44fbSRob Herring #include <linux/of.h>
15d9dd833cSArchie Pusaka #include <linux/pm_runtime.h>
16ce945552SHans de Goede #include <linux/serdev.h>
177dec65c8SJohan Hedberg #include <linux/skbuff.h>
187dec65c8SJohan Hedberg
197dec65c8SJohan Hedberg #include <net/bluetooth/bluetooth.h>
207dec65c8SJohan Hedberg #include <net/bluetooth/hci_core.h>
217dec65c8SJohan Hedberg
22b825d7c4SJeremy Cline #include "btrtl.h"
237dec65c8SJohan Hedberg #include "hci_uart.h"
247dec65c8SJohan Hedberg
25d9dd833cSArchie Pusaka #define SUSPEND_TIMEOUT_MS 6000
26d9dd833cSArchie Pusaka
27c0a1b73cSJohan Hedberg #define HCI_3WIRE_ACK_PKT 0
28c0a1b73cSJohan Hedberg #define HCI_3WIRE_LINK_PKT 15
29c0a1b73cSJohan Hedberg
30afdc944cSJohan Hedberg /* Sliding window size */
31afdc944cSJohan Hedberg #define H5_TX_WIN_MAX 4
323f27e95bSJohan Hedberg
333f27e95bSJohan Hedberg #define H5_ACK_TIMEOUT msecs_to_jiffies(250)
3440f10224SJohan Hedberg #define H5_SYNC_TIMEOUT msecs_to_jiffies(100)
353f27e95bSJohan Hedberg
36bc1f35b9SJohan Hedberg /*
37bc1f35b9SJohan Hedberg * Maximum Three-wire packet:
38bc1f35b9SJohan Hedberg * 4 byte header + max value for 12-bit length + 2 bytes for CRC
39bc1f35b9SJohan Hedberg */
40bc1f35b9SJohan Hedberg #define H5_MAX_LEN (4 + 0xfff + 2)
41bc1f35b9SJohan Hedberg
4201977c0bSJohan Hedberg /* Convenience macros for reading Three-wire header values */
4301977c0bSJohan Hedberg #define H5_HDR_SEQ(hdr) ((hdr)[0] & 0x07)
4401977c0bSJohan Hedberg #define H5_HDR_ACK(hdr) (((hdr)[0] >> 3) & 0x07)
4501977c0bSJohan Hedberg #define H5_HDR_CRC(hdr) (((hdr)[0] >> 6) & 0x01)
4601977c0bSJohan Hedberg #define H5_HDR_RELIABLE(hdr) (((hdr)[0] >> 7) & 0x01)
4701977c0bSJohan Hedberg #define H5_HDR_PKT_TYPE(hdr) ((hdr)[1] & 0x0f)
484223f368SAndrei Emeltchenko #define H5_HDR_LEN(hdr) ((((hdr)[1] >> 4) & 0x0f) + ((hdr)[2] << 4))
4901977c0bSJohan Hedberg
50bc1f35b9SJohan Hedberg #define SLIP_DELIMITER 0xc0
51bc1f35b9SJohan Hedberg #define SLIP_ESC 0xdb
52bc1f35b9SJohan Hedberg #define SLIP_ESC_DELIM 0xdc
53bc1f35b9SJohan Hedberg #define SLIP_ESC_ESC 0xdd
54bc1f35b9SJohan Hedberg
55e0482103SJohan Hedberg /* H5 state flags */
56e0482103SJohan Hedberg enum {
57e0482103SJohan Hedberg H5_RX_ESC, /* SLIP escape mode */
58e0482103SJohan Hedberg H5_TX_ACK_REQ, /* Pending ack to send */
5966f077ddSArchie Pusaka H5_WAKEUP_DISABLE, /* Device cannot wake host */
6030f11ddaSArchie Pusaka H5_HW_FLOW_CONTROL, /* Use HW flow control */
61e0482103SJohan Hedberg };
62e0482103SJohan Hedberg
637d664fbaSJohan Hedberg struct h5 {
64ce945552SHans de Goede /* Must be the first member, hci_serdev.c expects this. */
65ce945552SHans de Goede struct hci_uart serdev_hu;
66ce945552SHans de Goede
677d664fbaSJohan Hedberg struct sk_buff_head unack; /* Unack'ed packets queue */
687d664fbaSJohan Hedberg struct sk_buff_head rel; /* Reliable packets queue */
697d664fbaSJohan Hedberg struct sk_buff_head unrel; /* Unreliable packets queue */
707d664fbaSJohan Hedberg
71e0482103SJohan Hedberg unsigned long flags;
72e0482103SJohan Hedberg
73bc1f35b9SJohan Hedberg struct sk_buff *rx_skb; /* Receive buffer */
74bc1f35b9SJohan Hedberg size_t rx_pending; /* Expecting more bytes */
7543eb12d7SJohan Hedberg u8 rx_ack; /* Last ack number received */
76bc1f35b9SJohan Hedberg
77bc1f35b9SJohan Hedberg int (*rx_func)(struct hci_uart *hu, u8 c);
787d664fbaSJohan Hedberg
793f27e95bSJohan Hedberg struct timer_list timer; /* Retransmission timer */
8004356052SKees Cook struct hci_uart *hu; /* Parent HCI UART */
813f27e95bSJohan Hedberg
8243eb12d7SJohan Hedberg u8 tx_seq; /* Next seq number to send */
8340f10224SJohan Hedberg u8 tx_ack; /* Next ack number to send */
84afdc944cSJohan Hedberg u8 tx_win; /* Sliding window size */
8510122d07SJohan Hedberg
86f674a057SJohan Hedberg enum {
87f674a057SJohan Hedberg H5_UNINITIALIZED,
88f674a057SJohan Hedberg H5_INITIALIZED,
89f674a057SJohan Hedberg H5_ACTIVE,
90f674a057SJohan Hedberg } state;
91f674a057SJohan Hedberg
9295c5c220SJohan Hedberg enum {
9395c5c220SJohan Hedberg H5_AWAKE,
9495c5c220SJohan Hedberg H5_SLEEPING,
9595c5c220SJohan Hedberg H5_WAKING_UP,
9695c5c220SJohan Hedberg } sleep;
974eb3cbc4SJeremy Cline
984eb3cbc4SJeremy Cline const struct h5_vnd *vnd;
994eb3cbc4SJeremy Cline const char *id;
1004c791489SHans de Goede
1014c791489SHans de Goede struct gpio_desc *enable_gpio;
1024c791489SHans de Goede struct gpio_desc *device_wake_gpio;
1034eb3cbc4SJeremy Cline };
1044eb3cbc4SJeremy Cline
10566f077ddSArchie Pusaka enum h5_driver_info {
10666f077ddSArchie Pusaka H5_INFO_WAKEUP_DISABLE = BIT(0),
10766f077ddSArchie Pusaka };
10866f077ddSArchie Pusaka
1094eb3cbc4SJeremy Cline struct h5_vnd {
1104eb3cbc4SJeremy Cline int (*setup)(struct h5 *h5);
1114eb3cbc4SJeremy Cline void (*open)(struct h5 *h5);
1124eb3cbc4SJeremy Cline void (*close)(struct h5 *h5);
11328a75e4cSHans de Goede int (*suspend)(struct h5 *h5);
11428a75e4cSHans de Goede int (*resume)(struct h5 *h5);
1154c791489SHans de Goede const struct acpi_gpio_mapping *acpi_gpio_map;
1165939db19SAndrey Skvortsov int sizeof_priv;
1177d664fbaSJohan Hedberg };
1187d664fbaSJohan Hedberg
11966f077ddSArchie Pusaka struct h5_device_data {
12066f077ddSArchie Pusaka uint32_t driver_info;
12166f077ddSArchie Pusaka struct h5_vnd *vnd;
12266f077ddSArchie Pusaka };
12366f077ddSArchie Pusaka
124bc1f35b9SJohan Hedberg static void h5_reset_rx(struct h5 *h5);
125bc1f35b9SJohan Hedberg
h5_link_control(struct hci_uart * hu,const void * data,size_t len)12640f10224SJohan Hedberg static void h5_link_control(struct hci_uart *hu, const void *data, size_t len)
12740f10224SJohan Hedberg {
12840f10224SJohan Hedberg struct h5 *h5 = hu->priv;
12940f10224SJohan Hedberg struct sk_buff *nskb;
13040f10224SJohan Hedberg
13140f10224SJohan Hedberg nskb = alloc_skb(3, GFP_ATOMIC);
13240f10224SJohan Hedberg if (!nskb)
13340f10224SJohan Hedberg return;
13440f10224SJohan Hedberg
135618e8bc2SMarcel Holtmann hci_skb_pkt_type(nskb) = HCI_3WIRE_LINK_PKT;
13640f10224SJohan Hedberg
13759ae1d12SJohannes Berg skb_put_data(nskb, data, len);
13840f10224SJohan Hedberg
13940f10224SJohan Hedberg skb_queue_tail(&h5->unrel, nskb);
14040f10224SJohan Hedberg }
14140f10224SJohan Hedberg
h5_cfg_field(struct h5 * h5)142afdc944cSJohan Hedberg static u8 h5_cfg_field(struct h5 *h5)
143afdc944cSJohan Hedberg {
144afdc944cSJohan Hedberg /* Sliding window size (first 3 bits) */
145742c5951SAndrei Emeltchenko return h5->tx_win & 0x07;
146afdc944cSJohan Hedberg }
147afdc944cSJohan Hedberg
h5_timed_event(struct timer_list * t)14804356052SKees Cook static void h5_timed_event(struct timer_list *t)
149f674a057SJohan Hedberg {
150f674a057SJohan Hedberg const unsigned char sync_req[] = { 0x01, 0x7e };
15187a6b9bdSAndrei Emeltchenko unsigned char conf_req[3] = { 0x03, 0xfc };
15204356052SKees Cook struct h5 *h5 = from_timer(h5, t, timer);
15304356052SKees Cook struct hci_uart *hu = h5->hu;
154f674a057SJohan Hedberg struct sk_buff *skb;
155f674a057SJohan Hedberg unsigned long flags;
156f674a057SJohan Hedberg
15795c5c220SJohan Hedberg BT_DBG("%s", hu->hdev->name);
15895c5c220SJohan Hedberg
159f674a057SJohan Hedberg if (h5->state == H5_UNINITIALIZED)
160f674a057SJohan Hedberg h5_link_control(hu, sync_req, sizeof(sync_req));
161f674a057SJohan Hedberg
162afdc944cSJohan Hedberg if (h5->state == H5_INITIALIZED) {
163afdc944cSJohan Hedberg conf_req[2] = h5_cfg_field(h5);
164f674a057SJohan Hedberg h5_link_control(hu, conf_req, sizeof(conf_req));
165afdc944cSJohan Hedberg }
166f674a057SJohan Hedberg
167f674a057SJohan Hedberg if (h5->state != H5_ACTIVE) {
168f674a057SJohan Hedberg mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT);
169f674a057SJohan Hedberg goto wakeup;
170f674a057SJohan Hedberg }
171f674a057SJohan Hedberg
17295c5c220SJohan Hedberg if (h5->sleep != H5_AWAKE) {
17395c5c220SJohan Hedberg h5->sleep = H5_SLEEPING;
17495c5c220SJohan Hedberg goto wakeup;
17595c5c220SJohan Hedberg }
17695c5c220SJohan Hedberg
177f674a057SJohan Hedberg BT_DBG("hu %p retransmitting %u pkts", hu, h5->unack.qlen);
178f674a057SJohan Hedberg
179f674a057SJohan Hedberg spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING);
180f674a057SJohan Hedberg
181f674a057SJohan Hedberg while ((skb = __skb_dequeue_tail(&h5->unack)) != NULL) {
182f674a057SJohan Hedberg h5->tx_seq = (h5->tx_seq - 1) & 0x07;
183f674a057SJohan Hedberg skb_queue_head(&h5->rel, skb);
184f674a057SJohan Hedberg }
185f674a057SJohan Hedberg
186f674a057SJohan Hedberg spin_unlock_irqrestore(&h5->unack.lock, flags);
187f674a057SJohan Hedberg
188f674a057SJohan Hedberg wakeup:
189f674a057SJohan Hedberg hci_uart_tx_wakeup(hu);
190f674a057SJohan Hedberg }
191f674a057SJohan Hedberg
h5_peer_reset(struct hci_uart * hu)192b509c02dSLoic Poulain static void h5_peer_reset(struct hci_uart *hu)
193b509c02dSLoic Poulain {
194b509c02dSLoic Poulain struct h5 *h5 = hu->priv;
195b509c02dSLoic Poulain
196bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Peer device has reset");
197b509c02dSLoic Poulain
198b509c02dSLoic Poulain h5->state = H5_UNINITIALIZED;
199b509c02dSLoic Poulain
200b509c02dSLoic Poulain del_timer(&h5->timer);
201b509c02dSLoic Poulain
202b509c02dSLoic Poulain skb_queue_purge(&h5->rel);
203b509c02dSLoic Poulain skb_queue_purge(&h5->unrel);
204b509c02dSLoic Poulain skb_queue_purge(&h5->unack);
205b509c02dSLoic Poulain
206b509c02dSLoic Poulain h5->tx_seq = 0;
207b509c02dSLoic Poulain h5->tx_ack = 0;
208b509c02dSLoic Poulain
209882809fbSMarcel Holtmann /* Send reset request to upper stack */
210882809fbSMarcel Holtmann hci_reset_dev(hu->hdev);
211b509c02dSLoic Poulain }
212b509c02dSLoic Poulain
h5_open(struct hci_uart * hu)2137dec65c8SJohan Hedberg static int h5_open(struct hci_uart *hu)
2147dec65c8SJohan Hedberg {
2157d664fbaSJohan Hedberg struct h5 *h5;
21640f10224SJohan Hedberg const unsigned char sync[] = { 0x01, 0x7e };
2177d664fbaSJohan Hedberg
2187d664fbaSJohan Hedberg BT_DBG("hu %p", hu);
2197d664fbaSJohan Hedberg
220ce945552SHans de Goede if (hu->serdev) {
221ce945552SHans de Goede h5 = serdev_device_get_drvdata(hu->serdev);
222ce945552SHans de Goede } else {
2237d664fbaSJohan Hedberg h5 = kzalloc(sizeof(*h5), GFP_KERNEL);
2247d664fbaSJohan Hedberg if (!h5)
2257d664fbaSJohan Hedberg return -ENOMEM;
226ce945552SHans de Goede }
2277d664fbaSJohan Hedberg
2287d664fbaSJohan Hedberg hu->priv = h5;
22904356052SKees Cook h5->hu = hu;
2307d664fbaSJohan Hedberg
2317d664fbaSJohan Hedberg skb_queue_head_init(&h5->unack);
2327d664fbaSJohan Hedberg skb_queue_head_init(&h5->rel);
2337d664fbaSJohan Hedberg skb_queue_head_init(&h5->unrel);
2347d664fbaSJohan Hedberg
235bc1f35b9SJohan Hedberg h5_reset_rx(h5);
236bc1f35b9SJohan Hedberg
23704356052SKees Cook timer_setup(&h5->timer, h5_timed_event, 0);
2383f27e95bSJohan Hedberg
239afdc944cSJohan Hedberg h5->tx_win = H5_TX_WIN_MAX;
240afdc944cSJohan Hedberg
2414eb3cbc4SJeremy Cline if (h5->vnd && h5->vnd->open)
2424eb3cbc4SJeremy Cline h5->vnd->open(h5);
2434eb3cbc4SJeremy Cline
244cd1b4425SJohan Hedberg set_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags);
245cd1b4425SJohan Hedberg
24640f10224SJohan Hedberg /* Send initial sync request */
24740f10224SJohan Hedberg h5_link_control(hu, sync, sizeof(sync));
24840f10224SJohan Hedberg mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT);
24940f10224SJohan Hedberg
2507d664fbaSJohan Hedberg return 0;
2517dec65c8SJohan Hedberg }
2527dec65c8SJohan Hedberg
h5_close(struct hci_uart * hu)2537dec65c8SJohan Hedberg static int h5_close(struct hci_uart *hu)
2547dec65c8SJohan Hedberg {
2557d664fbaSJohan Hedberg struct h5 *h5 = hu->priv;
2567d664fbaSJohan Hedberg
257c327cdddSMichael Knudsen del_timer_sync(&h5->timer);
258c327cdddSMichael Knudsen
2597d664fbaSJohan Hedberg skb_queue_purge(&h5->unack);
2607d664fbaSJohan Hedberg skb_queue_purge(&h5->rel);
2617d664fbaSJohan Hedberg skb_queue_purge(&h5->unrel);
2627d664fbaSJohan Hedberg
263855af2d7SAnant Thazhemadam kfree_skb(h5->rx_skb);
264855af2d7SAnant Thazhemadam h5->rx_skb = NULL;
265855af2d7SAnant Thazhemadam
2664eb3cbc4SJeremy Cline if (h5->vnd && h5->vnd->close)
2674eb3cbc4SJeremy Cline h5->vnd->close(h5);
2684eb3cbc4SJeremy Cline
2695c3b5796SHans de Goede if (!hu->serdev)
2707d664fbaSJohan Hedberg kfree(h5);
2717d664fbaSJohan Hedberg
2727d664fbaSJohan Hedberg return 0;
2737dec65c8SJohan Hedberg }
2747dec65c8SJohan Hedberg
h5_setup(struct hci_uart * hu)2754eb3cbc4SJeremy Cline static int h5_setup(struct hci_uart *hu)
2764eb3cbc4SJeremy Cline {
2774eb3cbc4SJeremy Cline struct h5 *h5 = hu->priv;
2784eb3cbc4SJeremy Cline
2794eb3cbc4SJeremy Cline if (h5->vnd && h5->vnd->setup)
2804eb3cbc4SJeremy Cline return h5->vnd->setup(h5);
2814eb3cbc4SJeremy Cline
2824eb3cbc4SJeremy Cline return 0;
2834eb3cbc4SJeremy Cline }
2844eb3cbc4SJeremy Cline
h5_pkt_cull(struct h5 * h5)28543eb12d7SJohan Hedberg static void h5_pkt_cull(struct h5 *h5)
28643eb12d7SJohan Hedberg {
28743eb12d7SJohan Hedberg struct sk_buff *skb, *tmp;
28843eb12d7SJohan Hedberg unsigned long flags;
28943eb12d7SJohan Hedberg int i, to_remove;
29043eb12d7SJohan Hedberg u8 seq;
29143eb12d7SJohan Hedberg
29243eb12d7SJohan Hedberg spin_lock_irqsave(&h5->unack.lock, flags);
29343eb12d7SJohan Hedberg
29443eb12d7SJohan Hedberg to_remove = skb_queue_len(&h5->unack);
29540f10224SJohan Hedberg if (to_remove == 0)
29640f10224SJohan Hedberg goto unlock;
29743eb12d7SJohan Hedberg
29843eb12d7SJohan Hedberg seq = h5->tx_seq;
29943eb12d7SJohan Hedberg
30043eb12d7SJohan Hedberg while (to_remove > 0) {
30143eb12d7SJohan Hedberg if (h5->rx_ack == seq)
30243eb12d7SJohan Hedberg break;
30343eb12d7SJohan Hedberg
30443eb12d7SJohan Hedberg to_remove--;
3054807b518SLoic Poulain seq = (seq - 1) & 0x07;
30643eb12d7SJohan Hedberg }
30743eb12d7SJohan Hedberg
30843eb12d7SJohan Hedberg if (seq != h5->rx_ack)
30943eb12d7SJohan Hedberg BT_ERR("Controller acked invalid packet");
31043eb12d7SJohan Hedberg
31143eb12d7SJohan Hedberg i = 0;
31243eb12d7SJohan Hedberg skb_queue_walk_safe(&h5->unack, skb, tmp) {
31343eb12d7SJohan Hedberg if (i++ >= to_remove)
31443eb12d7SJohan Hedberg break;
31543eb12d7SJohan Hedberg
31643eb12d7SJohan Hedberg __skb_unlink(skb, &h5->unack);
317383630ccSYang Yingliang dev_kfree_skb_irq(skb);
31843eb12d7SJohan Hedberg }
31943eb12d7SJohan Hedberg
32043eb12d7SJohan Hedberg if (skb_queue_empty(&h5->unack))
32143eb12d7SJohan Hedberg del_timer(&h5->timer);
32243eb12d7SJohan Hedberg
32340f10224SJohan Hedberg unlock:
32443eb12d7SJohan Hedberg spin_unlock_irqrestore(&h5->unack.lock, flags);
32543eb12d7SJohan Hedberg }
32643eb12d7SJohan Hedberg
h5_handle_internal_rx(struct hci_uart * hu)327bc1f35b9SJohan Hedberg static void h5_handle_internal_rx(struct hci_uart *hu)
328bc1f35b9SJohan Hedberg {
32940f10224SJohan Hedberg struct h5 *h5 = hu->priv;
33040f10224SJohan Hedberg const unsigned char sync_req[] = { 0x01, 0x7e };
33140f10224SJohan Hedberg const unsigned char sync_rsp[] = { 0x02, 0x7d };
33287a6b9bdSAndrei Emeltchenko unsigned char conf_req[3] = { 0x03, 0xfc };
333afdc944cSJohan Hedberg const unsigned char conf_rsp[] = { 0x04, 0x7b };
33410122d07SJohan Hedberg const unsigned char wakeup_req[] = { 0x05, 0xfa };
33510122d07SJohan Hedberg const unsigned char woken_req[] = { 0x06, 0xf9 };
33610122d07SJohan Hedberg const unsigned char sleep_req[] = { 0x07, 0x78 };
33740f10224SJohan Hedberg const unsigned char *hdr = h5->rx_skb->data;
33840f10224SJohan Hedberg const unsigned char *data = &h5->rx_skb->data[4];
33940f10224SJohan Hedberg
340bc1f35b9SJohan Hedberg BT_DBG("%s", hu->hdev->name);
34140f10224SJohan Hedberg
34240f10224SJohan Hedberg if (H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT)
34340f10224SJohan Hedberg return;
34440f10224SJohan Hedberg
34540f10224SJohan Hedberg if (H5_HDR_LEN(hdr) < 2)
34640f10224SJohan Hedberg return;
34740f10224SJohan Hedberg
348afdc944cSJohan Hedberg conf_req[2] = h5_cfg_field(h5);
349afdc944cSJohan Hedberg
35040f10224SJohan Hedberg if (memcmp(data, sync_req, 2) == 0) {
351b509c02dSLoic Poulain if (h5->state == H5_ACTIVE)
352b509c02dSLoic Poulain h5_peer_reset(hu);
35340f10224SJohan Hedberg h5_link_control(hu, sync_rsp, 2);
35440f10224SJohan Hedberg } else if (memcmp(data, sync_rsp, 2) == 0) {
355b509c02dSLoic Poulain if (h5->state == H5_ACTIVE)
356b509c02dSLoic Poulain h5_peer_reset(hu);
357f674a057SJohan Hedberg h5->state = H5_INITIALIZED;
35840f10224SJohan Hedberg h5_link_control(hu, conf_req, 3);
35940f10224SJohan Hedberg } else if (memcmp(data, conf_req, 2) == 0) {
36040f10224SJohan Hedberg h5_link_control(hu, conf_rsp, 2);
36140f10224SJohan Hedberg h5_link_control(hu, conf_req, 3);
36240f10224SJohan Hedberg } else if (memcmp(data, conf_rsp, 2) == 0) {
363afdc944cSJohan Hedberg if (H5_HDR_LEN(hdr) > 2)
3641d3a1e69SAndrei Emeltchenko h5->tx_win = (data[2] & 0x07);
365afdc944cSJohan Hedberg BT_DBG("Three-wire init complete. tx_win %u", h5->tx_win);
366f674a057SJohan Hedberg h5->state = H5_ACTIVE;
367cd1b4425SJohan Hedberg hci_uart_init_ready(hu);
36840f10224SJohan Hedberg return;
36910122d07SJohan Hedberg } else if (memcmp(data, sleep_req, 2) == 0) {
37010122d07SJohan Hedberg BT_DBG("Peer went to sleep");
37195c5c220SJohan Hedberg h5->sleep = H5_SLEEPING;
37295c5c220SJohan Hedberg return;
37310122d07SJohan Hedberg } else if (memcmp(data, woken_req, 2) == 0) {
37410122d07SJohan Hedberg BT_DBG("Peer woke up");
37595c5c220SJohan Hedberg h5->sleep = H5_AWAKE;
37695c5c220SJohan Hedberg } else if (memcmp(data, wakeup_req, 2) == 0) {
37795c5c220SJohan Hedberg BT_DBG("Peer requested wakeup");
37895c5c220SJohan Hedberg h5_link_control(hu, woken_req, 2);
37995c5c220SJohan Hedberg h5->sleep = H5_AWAKE;
38040f10224SJohan Hedberg } else {
38140f10224SJohan Hedberg BT_DBG("Link Control: 0x%02hhx 0x%02hhx", data[0], data[1]);
38240f10224SJohan Hedberg return;
38340f10224SJohan Hedberg }
38440f10224SJohan Hedberg
38540f10224SJohan Hedberg hci_uart_tx_wakeup(hu);
386bc1f35b9SJohan Hedberg }
387bc1f35b9SJohan Hedberg
h5_complete_rx_pkt(struct hci_uart * hu)388bc1f35b9SJohan Hedberg static void h5_complete_rx_pkt(struct hci_uart *hu)
389bc1f35b9SJohan Hedberg {
390bc1f35b9SJohan Hedberg struct h5 *h5 = hu->priv;
39143eb12d7SJohan Hedberg const unsigned char *hdr = h5->rx_skb->data;
392bc1f35b9SJohan Hedberg
39343eb12d7SJohan Hedberg if (H5_HDR_RELIABLE(hdr)) {
39440f10224SJohan Hedberg h5->tx_ack = (h5->tx_ack + 1) % 8;
395e0482103SJohan Hedberg set_bit(H5_TX_ACK_REQ, &h5->flags);
39640f10224SJohan Hedberg hci_uart_tx_wakeup(hu);
39743eb12d7SJohan Hedberg }
398bc1f35b9SJohan Hedberg
39943eb12d7SJohan Hedberg h5->rx_ack = H5_HDR_ACK(hdr);
40043eb12d7SJohan Hedberg
40143eb12d7SJohan Hedberg h5_pkt_cull(h5);
40243eb12d7SJohan Hedberg
40343eb12d7SJohan Hedberg switch (H5_HDR_PKT_TYPE(hdr)) {
404bc1f35b9SJohan Hedberg case HCI_EVENT_PKT:
405bc1f35b9SJohan Hedberg case HCI_ACLDATA_PKT:
406bc1f35b9SJohan Hedberg case HCI_SCODATA_PKT:
4071cc3c10cSLuiz Augusto von Dentz case HCI_ISODATA_PKT:
408618e8bc2SMarcel Holtmann hci_skb_pkt_type(h5->rx_skb) = H5_HDR_PKT_TYPE(hdr);
409bc1f35b9SJohan Hedberg
410bc1f35b9SJohan Hedberg /* Remove Three-wire header */
411bc1f35b9SJohan Hedberg skb_pull(h5->rx_skb, 4);
412bc1f35b9SJohan Hedberg
413e1a26170SMarcel Holtmann hci_recv_frame(hu->hdev, h5->rx_skb);
414bc1f35b9SJohan Hedberg h5->rx_skb = NULL;
415bc1f35b9SJohan Hedberg
416bc1f35b9SJohan Hedberg break;
417bc1f35b9SJohan Hedberg
418bc1f35b9SJohan Hedberg default:
419bc1f35b9SJohan Hedberg h5_handle_internal_rx(hu);
420bc1f35b9SJohan Hedberg break;
421bc1f35b9SJohan Hedberg }
422bc1f35b9SJohan Hedberg
423bc1f35b9SJohan Hedberg h5_reset_rx(h5);
424bc1f35b9SJohan Hedberg }
425bc1f35b9SJohan Hedberg
h5_rx_crc(struct hci_uart * hu,unsigned char c)426bc1f35b9SJohan Hedberg static int h5_rx_crc(struct hci_uart *hu, unsigned char c)
427bc1f35b9SJohan Hedberg {
428bc1f35b9SJohan Hedberg h5_complete_rx_pkt(hu);
429bc1f35b9SJohan Hedberg
430bc1f35b9SJohan Hedberg return 0;
431bc1f35b9SJohan Hedberg }
432bc1f35b9SJohan Hedberg
h5_rx_payload(struct hci_uart * hu,unsigned char c)433bc1f35b9SJohan Hedberg static int h5_rx_payload(struct hci_uart *hu, unsigned char c)
434bc1f35b9SJohan Hedberg {
435bc1f35b9SJohan Hedberg struct h5 *h5 = hu->priv;
436bc1f35b9SJohan Hedberg const unsigned char *hdr = h5->rx_skb->data;
437bc1f35b9SJohan Hedberg
43843eb12d7SJohan Hedberg if (H5_HDR_CRC(hdr)) {
439bc1f35b9SJohan Hedberg h5->rx_func = h5_rx_crc;
440bc1f35b9SJohan Hedberg h5->rx_pending = 2;
441bc1f35b9SJohan Hedberg } else {
442bc1f35b9SJohan Hedberg h5_complete_rx_pkt(hu);
443bc1f35b9SJohan Hedberg }
444bc1f35b9SJohan Hedberg
445bc1f35b9SJohan Hedberg return 0;
446bc1f35b9SJohan Hedberg }
447bc1f35b9SJohan Hedberg
h5_rx_3wire_hdr(struct hci_uart * hu,unsigned char c)448bc1f35b9SJohan Hedberg static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c)
449bc1f35b9SJohan Hedberg {
450bc1f35b9SJohan Hedberg struct h5 *h5 = hu->priv;
451bc1f35b9SJohan Hedberg const unsigned char *hdr = h5->rx_skb->data;
452bc1f35b9SJohan Hedberg
45340f10224SJohan Hedberg BT_DBG("%s rx: seq %u ack %u crc %u rel %u type %u len %u",
45440f10224SJohan Hedberg hu->hdev->name, H5_HDR_SEQ(hdr), H5_HDR_ACK(hdr),
45540f10224SJohan Hedberg H5_HDR_CRC(hdr), H5_HDR_RELIABLE(hdr), H5_HDR_PKT_TYPE(hdr),
45640f10224SJohan Hedberg H5_HDR_LEN(hdr));
45740f10224SJohan Hedberg
458bc1f35b9SJohan Hedberg if (((hdr[0] + hdr[1] + hdr[2] + hdr[3]) & 0xff) != 0xff) {
459bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Invalid header checksum");
460bc1f35b9SJohan Hedberg h5_reset_rx(h5);
461bc1f35b9SJohan Hedberg return 0;
462bc1f35b9SJohan Hedberg }
463bc1f35b9SJohan Hedberg
46440f10224SJohan Hedberg if (H5_HDR_RELIABLE(hdr) && H5_HDR_SEQ(hdr) != h5->tx_ack) {
465bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Out-of-order packet arrived (%u != %u)",
46640f10224SJohan Hedberg H5_HDR_SEQ(hdr), h5->tx_ack);
4673c0d41f1SQiqi Zhang set_bit(H5_TX_ACK_REQ, &h5->flags);
4683c0d41f1SQiqi Zhang hci_uart_tx_wakeup(hu);
46943eb12d7SJohan Hedberg h5_reset_rx(h5);
47043eb12d7SJohan Hedberg return 0;
47143eb12d7SJohan Hedberg }
47243eb12d7SJohan Hedberg
473f674a057SJohan Hedberg if (h5->state != H5_ACTIVE &&
474f674a057SJohan Hedberg H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT) {
475bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Non-link packet received in non-active state");
476f674a057SJohan Hedberg h5_reset_rx(h5);
47748439d50SLoic Poulain return 0;
478f674a057SJohan Hedberg }
479f674a057SJohan Hedberg
480bc1f35b9SJohan Hedberg h5->rx_func = h5_rx_payload;
48143eb12d7SJohan Hedberg h5->rx_pending = H5_HDR_LEN(hdr);
482bc1f35b9SJohan Hedberg
483bc1f35b9SJohan Hedberg return 0;
484bc1f35b9SJohan Hedberg }
485bc1f35b9SJohan Hedberg
h5_rx_pkt_start(struct hci_uart * hu,unsigned char c)486bc1f35b9SJohan Hedberg static int h5_rx_pkt_start(struct hci_uart *hu, unsigned char c)
487bc1f35b9SJohan Hedberg {
488bc1f35b9SJohan Hedberg struct h5 *h5 = hu->priv;
489bc1f35b9SJohan Hedberg
490bc1f35b9SJohan Hedberg if (c == SLIP_DELIMITER)
491bc1f35b9SJohan Hedberg return 1;
492bc1f35b9SJohan Hedberg
493bc1f35b9SJohan Hedberg h5->rx_func = h5_rx_3wire_hdr;
494bc1f35b9SJohan Hedberg h5->rx_pending = 4;
495bc1f35b9SJohan Hedberg
496bc1f35b9SJohan Hedberg h5->rx_skb = bt_skb_alloc(H5_MAX_LEN, GFP_ATOMIC);
497bc1f35b9SJohan Hedberg if (!h5->rx_skb) {
498bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Can't allocate mem for new packet");
499bc1f35b9SJohan Hedberg h5_reset_rx(h5);
500bc1f35b9SJohan Hedberg return -ENOMEM;
501bc1f35b9SJohan Hedberg }
502bc1f35b9SJohan Hedberg
503bc1f35b9SJohan Hedberg h5->rx_skb->dev = (void *)hu->hdev;
504bc1f35b9SJohan Hedberg
505bc1f35b9SJohan Hedberg return 0;
506bc1f35b9SJohan Hedberg }
507bc1f35b9SJohan Hedberg
h5_rx_delimiter(struct hci_uart * hu,unsigned char c)508bc1f35b9SJohan Hedberg static int h5_rx_delimiter(struct hci_uart *hu, unsigned char c)
509bc1f35b9SJohan Hedberg {
510bc1f35b9SJohan Hedberg struct h5 *h5 = hu->priv;
511bc1f35b9SJohan Hedberg
512bc1f35b9SJohan Hedberg if (c == SLIP_DELIMITER)
513bc1f35b9SJohan Hedberg h5->rx_func = h5_rx_pkt_start;
514bc1f35b9SJohan Hedberg
515bc1f35b9SJohan Hedberg return 1;
516bc1f35b9SJohan Hedberg }
517bc1f35b9SJohan Hedberg
h5_unslip_one_byte(struct h5 * h5,unsigned char c)518bc1f35b9SJohan Hedberg static void h5_unslip_one_byte(struct h5 *h5, unsigned char c)
519bc1f35b9SJohan Hedberg {
520bc1f35b9SJohan Hedberg const u8 delim = SLIP_DELIMITER, esc = SLIP_ESC;
521bc1f35b9SJohan Hedberg const u8 *byte = &c;
522bc1f35b9SJohan Hedberg
523e0482103SJohan Hedberg if (!test_bit(H5_RX_ESC, &h5->flags) && c == SLIP_ESC) {
524e0482103SJohan Hedberg set_bit(H5_RX_ESC, &h5->flags);
525bc1f35b9SJohan Hedberg return;
526bc1f35b9SJohan Hedberg }
527bc1f35b9SJohan Hedberg
528e0482103SJohan Hedberg if (test_and_clear_bit(H5_RX_ESC, &h5->flags)) {
529bc1f35b9SJohan Hedberg switch (c) {
530bc1f35b9SJohan Hedberg case SLIP_ESC_DELIM:
531bc1f35b9SJohan Hedberg byte = &delim;
532bc1f35b9SJohan Hedberg break;
533bc1f35b9SJohan Hedberg case SLIP_ESC_ESC:
534bc1f35b9SJohan Hedberg byte = &esc;
535bc1f35b9SJohan Hedberg break;
536bc1f35b9SJohan Hedberg default:
537bc1f35b9SJohan Hedberg BT_ERR("Invalid esc byte 0x%02hhx", c);
538bc1f35b9SJohan Hedberg h5_reset_rx(h5);
539bc1f35b9SJohan Hedberg return;
540bc1f35b9SJohan Hedberg }
541bc1f35b9SJohan Hedberg }
542bc1f35b9SJohan Hedberg
54359ae1d12SJohannes Berg skb_put_data(h5->rx_skb, byte, 1);
544bc1f35b9SJohan Hedberg h5->rx_pending--;
545bc1f35b9SJohan Hedberg
54698df7446SColin Ian King BT_DBG("unslipped 0x%02hhx, rx_pending %zu", *byte, h5->rx_pending);
547bc1f35b9SJohan Hedberg }
548bc1f35b9SJohan Hedberg
h5_reset_rx(struct h5 * h5)549bc1f35b9SJohan Hedberg static void h5_reset_rx(struct h5 *h5)
550bc1f35b9SJohan Hedberg {
551bc1f35b9SJohan Hedberg if (h5->rx_skb) {
552bc1f35b9SJohan Hedberg kfree_skb(h5->rx_skb);
553bc1f35b9SJohan Hedberg h5->rx_skb = NULL;
554bc1f35b9SJohan Hedberg }
555bc1f35b9SJohan Hedberg
556bc1f35b9SJohan Hedberg h5->rx_func = h5_rx_delimiter;
557bc1f35b9SJohan Hedberg h5->rx_pending = 0;
558e0482103SJohan Hedberg clear_bit(H5_RX_ESC, &h5->flags);
559bc1f35b9SJohan Hedberg }
560bc1f35b9SJohan Hedberg
h5_recv(struct hci_uart * hu,const void * data,int count)5619d1c40ebSMarcel Holtmann static int h5_recv(struct hci_uart *hu, const void *data, int count)
5627dec65c8SJohan Hedberg {
563bc1f35b9SJohan Hedberg struct h5 *h5 = hu->priv;
5649d1c40ebSMarcel Holtmann const unsigned char *ptr = data;
565bc1f35b9SJohan Hedberg
566255a68e0SJohan Hedberg BT_DBG("%s pending %zu count %d", hu->hdev->name, h5->rx_pending,
567255a68e0SJohan Hedberg count);
568bc1f35b9SJohan Hedberg
569bc1f35b9SJohan Hedberg while (count > 0) {
570bc1f35b9SJohan Hedberg int processed;
571bc1f35b9SJohan Hedberg
572bc1f35b9SJohan Hedberg if (h5->rx_pending > 0) {
573bc1f35b9SJohan Hedberg if (*ptr == SLIP_DELIMITER) {
574bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Too short H5 packet");
575bc1f35b9SJohan Hedberg h5_reset_rx(h5);
576bc1f35b9SJohan Hedberg continue;
577bc1f35b9SJohan Hedberg }
578bc1f35b9SJohan Hedberg
579bc1f35b9SJohan Hedberg h5_unslip_one_byte(h5, *ptr);
580bc1f35b9SJohan Hedberg
581bc1f35b9SJohan Hedberg ptr++; count--;
582bc1f35b9SJohan Hedberg continue;
583bc1f35b9SJohan Hedberg }
584bc1f35b9SJohan Hedberg
585bc1f35b9SJohan Hedberg processed = h5->rx_func(hu, *ptr);
586bc1f35b9SJohan Hedberg if (processed < 0)
587bc1f35b9SJohan Hedberg return processed;
588bc1f35b9SJohan Hedberg
589bc1f35b9SJohan Hedberg ptr += processed;
590bc1f35b9SJohan Hedberg count -= processed;
591bc1f35b9SJohan Hedberg }
592bc1f35b9SJohan Hedberg
5932fc7acb6SPavel Skripkin if (hu->serdev) {
594d9dd833cSArchie Pusaka pm_runtime_get(&hu->serdev->dev);
595d9dd833cSArchie Pusaka pm_runtime_mark_last_busy(&hu->serdev->dev);
596d9dd833cSArchie Pusaka pm_runtime_put_autosuspend(&hu->serdev->dev);
5972fc7acb6SPavel Skripkin }
598d9dd833cSArchie Pusaka
599bc1f35b9SJohan Hedberg return 0;
6007dec65c8SJohan Hedberg }
6017dec65c8SJohan Hedberg
h5_enqueue(struct hci_uart * hu,struct sk_buff * skb)6027dec65c8SJohan Hedberg static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb)
6037dec65c8SJohan Hedberg {
6047d664fbaSJohan Hedberg struct h5 *h5 = hu->priv;
6057d664fbaSJohan Hedberg
6067d664fbaSJohan Hedberg if (skb->len > 0xfff) {
607bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Packet too long (%u bytes)", skb->len);
6087d664fbaSJohan Hedberg kfree_skb(skb);
6097d664fbaSJohan Hedberg return 0;
6107d664fbaSJohan Hedberg }
6117d664fbaSJohan Hedberg
612f674a057SJohan Hedberg if (h5->state != H5_ACTIVE) {
613bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Ignoring HCI data in non-active state");
614f674a057SJohan Hedberg kfree_skb(skb);
615f674a057SJohan Hedberg return 0;
616f674a057SJohan Hedberg }
617f674a057SJohan Hedberg
618618e8bc2SMarcel Holtmann switch (hci_skb_pkt_type(skb)) {
6197d664fbaSJohan Hedberg case HCI_ACLDATA_PKT:
6207d664fbaSJohan Hedberg case HCI_COMMAND_PKT:
6217d664fbaSJohan Hedberg skb_queue_tail(&h5->rel, skb);
6227d664fbaSJohan Hedberg break;
6237d664fbaSJohan Hedberg
6247d664fbaSJohan Hedberg case HCI_SCODATA_PKT:
6251cc3c10cSLuiz Augusto von Dentz case HCI_ISODATA_PKT:
6267d664fbaSJohan Hedberg skb_queue_tail(&h5->unrel, skb);
6277d664fbaSJohan Hedberg break;
6287d664fbaSJohan Hedberg
6297d664fbaSJohan Hedberg default:
630bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Unknown packet type %u", hci_skb_pkt_type(skb));
6317d664fbaSJohan Hedberg kfree_skb(skb);
6327d664fbaSJohan Hedberg break;
6337d664fbaSJohan Hedberg }
6347d664fbaSJohan Hedberg
63532cb08e9SPavel Skripkin if (hu->serdev) {
636d9dd833cSArchie Pusaka pm_runtime_get_sync(&hu->serdev->dev);
637d9dd833cSArchie Pusaka pm_runtime_mark_last_busy(&hu->serdev->dev);
638d9dd833cSArchie Pusaka pm_runtime_put_autosuspend(&hu->serdev->dev);
63932cb08e9SPavel Skripkin }
640d9dd833cSArchie Pusaka
6417d664fbaSJohan Hedberg return 0;
6427d664fbaSJohan Hedberg }
6437d664fbaSJohan Hedberg
h5_slip_delim(struct sk_buff * skb)644c0a1b73cSJohan Hedberg static void h5_slip_delim(struct sk_buff *skb)
6457d664fbaSJohan Hedberg {
646c0a1b73cSJohan Hedberg const char delim = SLIP_DELIMITER;
647c0a1b73cSJohan Hedberg
64859ae1d12SJohannes Berg skb_put_data(skb, &delim, 1);
649c0a1b73cSJohan Hedberg }
650c0a1b73cSJohan Hedberg
h5_slip_one_byte(struct sk_buff * skb,u8 c)651c0a1b73cSJohan Hedberg static void h5_slip_one_byte(struct sk_buff *skb, u8 c)
652c0a1b73cSJohan Hedberg {
653c0a1b73cSJohan Hedberg const char esc_delim[2] = { SLIP_ESC, SLIP_ESC_DELIM };
654c0a1b73cSJohan Hedberg const char esc_esc[2] = { SLIP_ESC, SLIP_ESC_ESC };
655c0a1b73cSJohan Hedberg
656c0a1b73cSJohan Hedberg switch (c) {
657c0a1b73cSJohan Hedberg case SLIP_DELIMITER:
65859ae1d12SJohannes Berg skb_put_data(skb, &esc_delim, 2);
659c0a1b73cSJohan Hedberg break;
660c0a1b73cSJohan Hedberg case SLIP_ESC:
66159ae1d12SJohannes Berg skb_put_data(skb, &esc_esc, 2);
662c0a1b73cSJohan Hedberg break;
663c0a1b73cSJohan Hedberg default:
66459ae1d12SJohannes Berg skb_put_data(skb, &c, 1);
665c0a1b73cSJohan Hedberg }
666c0a1b73cSJohan Hedberg }
667c0a1b73cSJohan Hedberg
valid_packet_type(u8 type)668c826ed09SJohan Hedberg static bool valid_packet_type(u8 type)
669c826ed09SJohan Hedberg {
670c826ed09SJohan Hedberg switch (type) {
671c826ed09SJohan Hedberg case HCI_ACLDATA_PKT:
672c826ed09SJohan Hedberg case HCI_COMMAND_PKT:
673c826ed09SJohan Hedberg case HCI_SCODATA_PKT:
6741cc3c10cSLuiz Augusto von Dentz case HCI_ISODATA_PKT:
675c826ed09SJohan Hedberg case HCI_3WIRE_LINK_PKT:
676c826ed09SJohan Hedberg case HCI_3WIRE_ACK_PKT:
677c826ed09SJohan Hedberg return true;
678c826ed09SJohan Hedberg default:
679c826ed09SJohan Hedberg return false;
680c826ed09SJohan Hedberg }
681c826ed09SJohan Hedberg }
682c826ed09SJohan Hedberg
h5_prepare_pkt(struct hci_uart * hu,u8 pkt_type,const u8 * data,size_t len)683c826ed09SJohan Hedberg static struct sk_buff *h5_prepare_pkt(struct hci_uart *hu, u8 pkt_type,
684c0a1b73cSJohan Hedberg const u8 *data, size_t len)
685c0a1b73cSJohan Hedberg {
68640f10224SJohan Hedberg struct h5 *h5 = hu->priv;
687c0a1b73cSJohan Hedberg struct sk_buff *nskb;
688c0a1b73cSJohan Hedberg u8 hdr[4];
689c0a1b73cSJohan Hedberg int i;
690c0a1b73cSJohan Hedberg
691c826ed09SJohan Hedberg if (!valid_packet_type(pkt_type)) {
692bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Unknown packet type %u", pkt_type);
693c826ed09SJohan Hedberg return NULL;
694c826ed09SJohan Hedberg }
695c826ed09SJohan Hedberg
696c0a1b73cSJohan Hedberg /*
697c0a1b73cSJohan Hedberg * Max len of packet: (original len + 4 (H5 hdr) + 2 (crc)) * 2
698c0a1b73cSJohan Hedberg * (because bytes 0xc0 and 0xdb are escaped, worst case is when
699c0a1b73cSJohan Hedberg * the packet is all made of 0xc0 and 0xdb) + 2 (0xc0
700c0a1b73cSJohan Hedberg * delimiters at start and end).
701c0a1b73cSJohan Hedberg */
702c0a1b73cSJohan Hedberg nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC);
703c0a1b73cSJohan Hedberg if (!nskb)
7047d664fbaSJohan Hedberg return NULL;
705c0a1b73cSJohan Hedberg
706618e8bc2SMarcel Holtmann hci_skb_pkt_type(nskb) = pkt_type;
707c0a1b73cSJohan Hedberg
708c0a1b73cSJohan Hedberg h5_slip_delim(nskb);
709c0a1b73cSJohan Hedberg
71040f10224SJohan Hedberg hdr[0] = h5->tx_ack << 3;
711e0482103SJohan Hedberg clear_bit(H5_TX_ACK_REQ, &h5->flags);
712c0a1b73cSJohan Hedberg
713c826ed09SJohan Hedberg /* Reliable packet? */
714c826ed09SJohan Hedberg if (pkt_type == HCI_ACLDATA_PKT || pkt_type == HCI_COMMAND_PKT) {
715c0a1b73cSJohan Hedberg hdr[0] |= 1 << 7;
71643eb12d7SJohan Hedberg hdr[0] |= h5->tx_seq;
71743eb12d7SJohan Hedberg h5->tx_seq = (h5->tx_seq + 1) % 8;
718c0a1b73cSJohan Hedberg }
719c0a1b73cSJohan Hedberg
720c0a1b73cSJohan Hedberg hdr[1] = pkt_type | ((len & 0x0f) << 4);
721c0a1b73cSJohan Hedberg hdr[2] = len >> 4;
722c0a1b73cSJohan Hedberg hdr[3] = ~((hdr[0] + hdr[1] + hdr[2]) & 0xff);
723c0a1b73cSJohan Hedberg
72440f10224SJohan Hedberg BT_DBG("%s tx: seq %u ack %u crc %u rel %u type %u len %u",
72540f10224SJohan Hedberg hu->hdev->name, H5_HDR_SEQ(hdr), H5_HDR_ACK(hdr),
72640f10224SJohan Hedberg H5_HDR_CRC(hdr), H5_HDR_RELIABLE(hdr), H5_HDR_PKT_TYPE(hdr),
72740f10224SJohan Hedberg H5_HDR_LEN(hdr));
72840f10224SJohan Hedberg
729c0a1b73cSJohan Hedberg for (i = 0; i < 4; i++)
730c0a1b73cSJohan Hedberg h5_slip_one_byte(nskb, hdr[i]);
731c0a1b73cSJohan Hedberg
732c0a1b73cSJohan Hedberg for (i = 0; i < len; i++)
733c0a1b73cSJohan Hedberg h5_slip_one_byte(nskb, data[i]);
734c0a1b73cSJohan Hedberg
735c0a1b73cSJohan Hedberg h5_slip_delim(nskb);
736c0a1b73cSJohan Hedberg
737c0a1b73cSJohan Hedberg return nskb;
738c0a1b73cSJohan Hedberg }
739c0a1b73cSJohan Hedberg
h5_dequeue(struct hci_uart * hu)7407dec65c8SJohan Hedberg static struct sk_buff *h5_dequeue(struct hci_uart *hu)
7417dec65c8SJohan Hedberg {
7427d664fbaSJohan Hedberg struct h5 *h5 = hu->priv;
7433f27e95bSJohan Hedberg unsigned long flags;
7447d664fbaSJohan Hedberg struct sk_buff *skb, *nskb;
7457d664fbaSJohan Hedberg
74695c5c220SJohan Hedberg if (h5->sleep != H5_AWAKE) {
74795c5c220SJohan Hedberg const unsigned char wakeup_req[] = { 0x05, 0xfa };
74895c5c220SJohan Hedberg
74995c5c220SJohan Hedberg if (h5->sleep == H5_WAKING_UP)
75095c5c220SJohan Hedberg return NULL;
75195c5c220SJohan Hedberg
75295c5c220SJohan Hedberg h5->sleep = H5_WAKING_UP;
75395c5c220SJohan Hedberg BT_DBG("Sending wakeup request");
75495c5c220SJohan Hedberg
75595c5c220SJohan Hedberg mod_timer(&h5->timer, jiffies + HZ / 100);
75695c5c220SJohan Hedberg return h5_prepare_pkt(hu, HCI_3WIRE_LINK_PKT, wakeup_req, 2);
75795c5c220SJohan Hedberg }
75895c5c220SJohan Hedberg
759a08b15e6SValentin Ilie skb = skb_dequeue(&h5->unrel);
7604a2fa2b8SPrasanna Karthik if (skb) {
761618e8bc2SMarcel Holtmann nskb = h5_prepare_pkt(hu, hci_skb_pkt_type(skb),
762c0a1b73cSJohan Hedberg skb->data, skb->len);
7637d664fbaSJohan Hedberg if (nskb) {
7647d664fbaSJohan Hedberg kfree_skb(skb);
7657d664fbaSJohan Hedberg return nskb;
7667d664fbaSJohan Hedberg }
7677d664fbaSJohan Hedberg
7687d664fbaSJohan Hedberg skb_queue_head(&h5->unrel, skb);
769bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Could not dequeue pkt because alloc_skb failed");
7707d664fbaSJohan Hedberg }
7717d664fbaSJohan Hedberg
7723f27e95bSJohan Hedberg spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING);
7733f27e95bSJohan Hedberg
774afdc944cSJohan Hedberg if (h5->unack.qlen >= h5->tx_win)
7753f27e95bSJohan Hedberg goto unlock;
7763f27e95bSJohan Hedberg
777a08b15e6SValentin Ilie skb = skb_dequeue(&h5->rel);
7784a2fa2b8SPrasanna Karthik if (skb) {
779618e8bc2SMarcel Holtmann nskb = h5_prepare_pkt(hu, hci_skb_pkt_type(skb),
780c0a1b73cSJohan Hedberg skb->data, skb->len);
7813f27e95bSJohan Hedberg if (nskb) {
7823f27e95bSJohan Hedberg __skb_queue_tail(&h5->unack, skb);
7833f27e95bSJohan Hedberg mod_timer(&h5->timer, jiffies + H5_ACK_TIMEOUT);
7843f27e95bSJohan Hedberg spin_unlock_irqrestore(&h5->unack.lock, flags);
7853f27e95bSJohan Hedberg return nskb;
7863f27e95bSJohan Hedberg }
7873f27e95bSJohan Hedberg
7883f27e95bSJohan Hedberg skb_queue_head(&h5->rel, skb);
789bb0084ecSMarcel Holtmann bt_dev_err(hu->hdev, "Could not dequeue pkt because alloc_skb failed");
7903f27e95bSJohan Hedberg }
7913f27e95bSJohan Hedberg
7923f27e95bSJohan Hedberg unlock:
7933f27e95bSJohan Hedberg spin_unlock_irqrestore(&h5->unack.lock, flags);
7943f27e95bSJohan Hedberg
795e0482103SJohan Hedberg if (test_bit(H5_TX_ACK_REQ, &h5->flags))
79640f10224SJohan Hedberg return h5_prepare_pkt(hu, HCI_3WIRE_ACK_PKT, NULL, 0);
7977d664fbaSJohan Hedberg
7987dec65c8SJohan Hedberg return NULL;
7997dec65c8SJohan Hedberg }
8007dec65c8SJohan Hedberg
h5_flush(struct hci_uart * hu)8017dec65c8SJohan Hedberg static int h5_flush(struct hci_uart *hu)
8027dec65c8SJohan Hedberg {
8037d664fbaSJohan Hedberg BT_DBG("hu %p", hu);
8047d664fbaSJohan Hedberg return 0;
8057dec65c8SJohan Hedberg }
8067dec65c8SJohan Hedberg
8074ee7ef19SMarcel Holtmann static const struct hci_uart_proto h5p = {
8087dec65c8SJohan Hedberg .id = HCI_UART_3WIRE,
8097c40fb8dSMarcel Holtmann .name = "Three-wire (H5)",
8107dec65c8SJohan Hedberg .open = h5_open,
8117dec65c8SJohan Hedberg .close = h5_close,
8124eb3cbc4SJeremy Cline .setup = h5_setup,
8137dec65c8SJohan Hedberg .recv = h5_recv,
8147dec65c8SJohan Hedberg .enqueue = h5_enqueue,
8157dec65c8SJohan Hedberg .dequeue = h5_dequeue,
8167dec65c8SJohan Hedberg .flush = h5_flush,
8177dec65c8SJohan Hedberg };
8187dec65c8SJohan Hedberg
h5_serdev_probe(struct serdev_device * serdev)819ce945552SHans de Goede static int h5_serdev_probe(struct serdev_device *serdev)
820ce945552SHans de Goede {
821ce945552SHans de Goede struct device *dev = &serdev->dev;
822ce945552SHans de Goede struct h5 *h5;
82366f077ddSArchie Pusaka const struct h5_device_data *data;
824ce945552SHans de Goede
825ce945552SHans de Goede h5 = devm_kzalloc(dev, sizeof(*h5), GFP_KERNEL);
826ce945552SHans de Goede if (!h5)
827ce945552SHans de Goede return -ENOMEM;
828ce945552SHans de Goede
829ce945552SHans de Goede h5->hu = &h5->serdev_hu;
830ce945552SHans de Goede h5->serdev_hu.serdev = serdev;
831ce945552SHans de Goede serdev_device_set_drvdata(serdev, h5);
832ce945552SHans de Goede
8334eb3cbc4SJeremy Cline if (has_acpi_companion(dev)) {
8340830c0a4SMarcel Holtmann const struct acpi_device_id *match;
8350830c0a4SMarcel Holtmann
8364eb3cbc4SJeremy Cline match = acpi_match_device(dev->driver->acpi_match_table, dev);
8374eb3cbc4SJeremy Cline if (!match)
8384eb3cbc4SJeremy Cline return -ENODEV;
8394eb3cbc4SJeremy Cline
84066f077ddSArchie Pusaka data = (const struct h5_device_data *)match->driver_data;
84166f077ddSArchie Pusaka h5->vnd = data->vnd;
8424eb3cbc4SJeremy Cline h5->id = (char *)match->id;
8434c791489SHans de Goede
8444c791489SHans de Goede if (h5->vnd->acpi_gpio_map)
8454c791489SHans de Goede devm_acpi_dev_add_driver_gpios(dev,
8464c791489SHans de Goede h5->vnd->acpi_gpio_map);
847848fc616SMax Chou } else {
848848fc616SMax Chou data = of_device_get_match_data(dev);
849848fc616SMax Chou if (!data)
850848fc616SMax Chou return -ENODEV;
851848fc616SMax Chou
85266f077ddSArchie Pusaka h5->vnd = data->vnd;
8534eb3cbc4SJeremy Cline }
8544eb3cbc4SJeremy Cline
8559a9023f3SHans de Goede if (data->driver_info & H5_INFO_WAKEUP_DISABLE)
8569a9023f3SHans de Goede set_bit(H5_WAKEUP_DISABLE, &h5->flags);
857848fc616SMax Chou
8584c791489SHans de Goede h5->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
8594c791489SHans de Goede if (IS_ERR(h5->enable_gpio))
8604c791489SHans de Goede return PTR_ERR(h5->enable_gpio);
8614c791489SHans de Goede
8624c791489SHans de Goede h5->device_wake_gpio = devm_gpiod_get_optional(dev, "device-wake",
8634c791489SHans de Goede GPIOD_OUT_LOW);
8644c791489SHans de Goede if (IS_ERR(h5->device_wake_gpio))
8654c791489SHans de Goede return PTR_ERR(h5->device_wake_gpio);
8664c791489SHans de Goede
8675939db19SAndrey Skvortsov return hci_uart_register_device_priv(&h5->serdev_hu, &h5p,
8685939db19SAndrey Skvortsov h5->vnd->sizeof_priv);
869ce945552SHans de Goede }
870ce945552SHans de Goede
h5_serdev_remove(struct serdev_device * serdev)871ce945552SHans de Goede static void h5_serdev_remove(struct serdev_device *serdev)
872ce945552SHans de Goede {
873ce945552SHans de Goede struct h5 *h5 = serdev_device_get_drvdata(serdev);
874ce945552SHans de Goede
875ce945552SHans de Goede hci_uart_unregister_device(&h5->serdev_hu);
876ce945552SHans de Goede }
877ce945552SHans de Goede
h5_serdev_suspend(struct device * dev)87828a75e4cSHans de Goede static int __maybe_unused h5_serdev_suspend(struct device *dev)
87928a75e4cSHans de Goede {
88028a75e4cSHans de Goede struct h5 *h5 = dev_get_drvdata(dev);
88128a75e4cSHans de Goede int ret = 0;
88228a75e4cSHans de Goede
88328a75e4cSHans de Goede if (h5->vnd && h5->vnd->suspend)
88428a75e4cSHans de Goede ret = h5->vnd->suspend(h5);
88528a75e4cSHans de Goede
88628a75e4cSHans de Goede return ret;
88728a75e4cSHans de Goede }
88828a75e4cSHans de Goede
h5_serdev_resume(struct device * dev)88928a75e4cSHans de Goede static int __maybe_unused h5_serdev_resume(struct device *dev)
89028a75e4cSHans de Goede {
89128a75e4cSHans de Goede struct h5 *h5 = dev_get_drvdata(dev);
89228a75e4cSHans de Goede int ret = 0;
89328a75e4cSHans de Goede
89428a75e4cSHans de Goede if (h5->vnd && h5->vnd->resume)
89528a75e4cSHans de Goede ret = h5->vnd->resume(h5);
89628a75e4cSHans de Goede
89728a75e4cSHans de Goede return ret;
89828a75e4cSHans de Goede }
89928a75e4cSHans de Goede
900b9763cdfSMarcel Holtmann #ifdef CONFIG_BT_HCIUART_RTL
h5_btrtl_setup(struct h5 * h5)901b825d7c4SJeremy Cline static int h5_btrtl_setup(struct h5 *h5)
902b825d7c4SJeremy Cline {
903b825d7c4SJeremy Cline struct btrtl_device_info *btrtl_dev;
904b825d7c4SJeremy Cline struct sk_buff *skb;
905b825d7c4SJeremy Cline __le32 baudrate_data;
906b825d7c4SJeremy Cline u32 device_baudrate;
907b825d7c4SJeremy Cline unsigned int controller_baudrate;
908b825d7c4SJeremy Cline bool flow_control;
909b825d7c4SJeremy Cline int err;
910b825d7c4SJeremy Cline
911b825d7c4SJeremy Cline btrtl_dev = btrtl_initialize(h5->hu->hdev, h5->id);
912b825d7c4SJeremy Cline if (IS_ERR(btrtl_dev))
913b825d7c4SJeremy Cline return PTR_ERR(btrtl_dev);
914b825d7c4SJeremy Cline
915b825d7c4SJeremy Cline err = btrtl_get_uart_settings(h5->hu->hdev, btrtl_dev,
916b825d7c4SJeremy Cline &controller_baudrate, &device_baudrate,
917b825d7c4SJeremy Cline &flow_control);
918b825d7c4SJeremy Cline if (err)
919b825d7c4SJeremy Cline goto out_free;
920b825d7c4SJeremy Cline
921b825d7c4SJeremy Cline baudrate_data = cpu_to_le32(device_baudrate);
922b825d7c4SJeremy Cline skb = __hci_cmd_sync(h5->hu->hdev, 0xfc17, sizeof(baudrate_data),
923b825d7c4SJeremy Cline &baudrate_data, HCI_INIT_TIMEOUT);
924b825d7c4SJeremy Cline if (IS_ERR(skb)) {
925b825d7c4SJeremy Cline rtl_dev_err(h5->hu->hdev, "set baud rate command failed\n");
926b825d7c4SJeremy Cline err = PTR_ERR(skb);
927b825d7c4SJeremy Cline goto out_free;
928b825d7c4SJeremy Cline } else {
929b825d7c4SJeremy Cline kfree_skb(skb);
930b825d7c4SJeremy Cline }
931b825d7c4SJeremy Cline /* Give the device some time to set up the new baudrate. */
932b825d7c4SJeremy Cline usleep_range(10000, 20000);
933b825d7c4SJeremy Cline
934b825d7c4SJeremy Cline serdev_device_set_baudrate(h5->hu->serdev, controller_baudrate);
935b825d7c4SJeremy Cline serdev_device_set_flow_control(h5->hu->serdev, flow_control);
936b825d7c4SJeremy Cline
93730f11ddaSArchie Pusaka if (flow_control)
93830f11ddaSArchie Pusaka set_bit(H5_HW_FLOW_CONTROL, &h5->flags);
93930f11ddaSArchie Pusaka
940b825d7c4SJeremy Cline err = btrtl_download_firmware(h5->hu->hdev, btrtl_dev);
941b825d7c4SJeremy Cline /* Give the device some time before the hci-core sends it a reset */
942b825d7c4SJeremy Cline usleep_range(10000, 20000);
943c0123cb6SVasily Khoruzhick if (err)
944c0123cb6SVasily Khoruzhick goto out_free;
945b825d7c4SJeremy Cline
9463011faa2SArchie Pusaka btrtl_set_quirks(h5->hu->hdev, btrtl_dev);
9477f9f2c3fSClaire Chang
948b825d7c4SJeremy Cline out_free:
949b825d7c4SJeremy Cline btrtl_free(btrtl_dev);
950b825d7c4SJeremy Cline
951b825d7c4SJeremy Cline return err;
952b825d7c4SJeremy Cline }
953b825d7c4SJeremy Cline
h5_btrtl_open(struct h5 * h5)954b825d7c4SJeremy Cline static void h5_btrtl_open(struct h5 *h5)
955b825d7c4SJeremy Cline {
956b4a46996SHans de Goede /*
957b4a46996SHans de Goede * Since h5_btrtl_resume() does a device_reprobe() the suspend handling
958b4a46996SHans de Goede * done by the hci_suspend_notifier is not necessary; it actually causes
959b4a46996SHans de Goede * delays and a bunch of errors to get logged, so disable it.
960b4a46996SHans de Goede */
96166f077ddSArchie Pusaka if (test_bit(H5_WAKEUP_DISABLE, &h5->flags))
962b4a46996SHans de Goede set_bit(HCI_UART_NO_SUSPEND_NOTIFIER, &h5->hu->flags);
963b4a46996SHans de Goede
964b825d7c4SJeremy Cline /* Devices always start with these fixed parameters */
965b825d7c4SJeremy Cline serdev_device_set_flow_control(h5->hu->serdev, false);
966b825d7c4SJeremy Cline serdev_device_set_parity(h5->hu->serdev, SERDEV_PARITY_EVEN);
967b825d7c4SJeremy Cline serdev_device_set_baudrate(h5->hu->serdev, 115200);
9684c791489SHans de Goede
9699a9023f3SHans de Goede if (!test_bit(H5_WAKEUP_DISABLE, &h5->flags)) {
970d9dd833cSArchie Pusaka pm_runtime_set_active(&h5->hu->serdev->dev);
971d9dd833cSArchie Pusaka pm_runtime_use_autosuspend(&h5->hu->serdev->dev);
972d9dd833cSArchie Pusaka pm_runtime_set_autosuspend_delay(&h5->hu->serdev->dev,
973d9dd833cSArchie Pusaka SUSPEND_TIMEOUT_MS);
974d9dd833cSArchie Pusaka pm_runtime_enable(&h5->hu->serdev->dev);
9759a9023f3SHans de Goede }
976d9dd833cSArchie Pusaka
977adce573bSVyacheslav Bocharov /* The controller needs reset to startup */
978adce573bSVyacheslav Bocharov gpiod_set_value_cansleep(h5->enable_gpio, 0);
979adce573bSVyacheslav Bocharov gpiod_set_value_cansleep(h5->device_wake_gpio, 0);
980adce573bSVyacheslav Bocharov msleep(100);
981adce573bSVyacheslav Bocharov
9824c791489SHans de Goede /* The controller needs up to 500ms to wakeup */
9834c791489SHans de Goede gpiod_set_value_cansleep(h5->enable_gpio, 1);
9844c791489SHans de Goede gpiod_set_value_cansleep(h5->device_wake_gpio, 1);
9854c791489SHans de Goede msleep(500);
986b825d7c4SJeremy Cline }
987b825d7c4SJeremy Cline
h5_btrtl_close(struct h5 * h5)9884c791489SHans de Goede static void h5_btrtl_close(struct h5 *h5)
9894c791489SHans de Goede {
9909a9023f3SHans de Goede if (!test_bit(H5_WAKEUP_DISABLE, &h5->flags))
991d9dd833cSArchie Pusaka pm_runtime_disable(&h5->hu->serdev->dev);
992d9dd833cSArchie Pusaka
9934c791489SHans de Goede gpiod_set_value_cansleep(h5->device_wake_gpio, 0);
9944c791489SHans de Goede gpiod_set_value_cansleep(h5->enable_gpio, 0);
9954c791489SHans de Goede }
9964c791489SHans de Goede
9978589086fSHans de Goede /* Suspend/resume support. On many devices the RTL BT device loses power during
9988589086fSHans de Goede * suspend/resume, causing it to lose its firmware and all state. So we simply
9998589086fSHans de Goede * turn it off on suspend and reprobe on resume. This mirrors how RTL devices
100066f077ddSArchie Pusaka * are handled in the USB driver, where the BTUSB_WAKEUP_DISABLE is used which
10018589086fSHans de Goede * also causes a reprobe on resume.
10028589086fSHans de Goede */
h5_btrtl_suspend(struct h5 * h5)10038589086fSHans de Goede static int h5_btrtl_suspend(struct h5 *h5)
10048589086fSHans de Goede {
10058589086fSHans de Goede serdev_device_set_flow_control(h5->hu->serdev, false);
10068589086fSHans de Goede gpiod_set_value_cansleep(h5->device_wake_gpio, 0);
100766f077ddSArchie Pusaka
100866f077ddSArchie Pusaka if (test_bit(H5_WAKEUP_DISABLE, &h5->flags))
10098589086fSHans de Goede gpiod_set_value_cansleep(h5->enable_gpio, 0);
101066f077ddSArchie Pusaka
10118589086fSHans de Goede return 0;
10128589086fSHans de Goede }
10138589086fSHans de Goede
10148589086fSHans de Goede struct h5_btrtl_reprobe {
10158589086fSHans de Goede struct device *dev;
10168589086fSHans de Goede struct work_struct work;
10178589086fSHans de Goede };
10188589086fSHans de Goede
h5_btrtl_reprobe_worker(struct work_struct * work)10198589086fSHans de Goede static void h5_btrtl_reprobe_worker(struct work_struct *work)
10208589086fSHans de Goede {
10218589086fSHans de Goede struct h5_btrtl_reprobe *reprobe =
10228589086fSHans de Goede container_of(work, struct h5_btrtl_reprobe, work);
10238589086fSHans de Goede int ret;
10248589086fSHans de Goede
10258589086fSHans de Goede ret = device_reprobe(reprobe->dev);
10268589086fSHans de Goede if (ret && ret != -EPROBE_DEFER)
10278589086fSHans de Goede dev_err(reprobe->dev, "Reprobe error %d\n", ret);
10288589086fSHans de Goede
10298589086fSHans de Goede put_device(reprobe->dev);
10308589086fSHans de Goede kfree(reprobe);
10318589086fSHans de Goede module_put(THIS_MODULE);
10328589086fSHans de Goede }
10338589086fSHans de Goede
h5_btrtl_resume(struct h5 * h5)10348589086fSHans de Goede static int h5_btrtl_resume(struct h5 *h5)
10358589086fSHans de Goede {
103666f077ddSArchie Pusaka if (test_bit(H5_WAKEUP_DISABLE, &h5->flags)) {
10378589086fSHans de Goede struct h5_btrtl_reprobe *reprobe;
10388589086fSHans de Goede
10398589086fSHans de Goede reprobe = kzalloc(sizeof(*reprobe), GFP_KERNEL);
10408589086fSHans de Goede if (!reprobe)
10418589086fSHans de Goede return -ENOMEM;
10428589086fSHans de Goede
10438589086fSHans de Goede __module_get(THIS_MODULE);
10448589086fSHans de Goede
10458589086fSHans de Goede INIT_WORK(&reprobe->work, h5_btrtl_reprobe_worker);
10468589086fSHans de Goede reprobe->dev = get_device(&h5->hu->serdev->dev);
10478589086fSHans de Goede queue_work(system_long_wq, &reprobe->work);
104866f077ddSArchie Pusaka } else {
104966f077ddSArchie Pusaka gpiod_set_value_cansleep(h5->device_wake_gpio, 1);
105030f11ddaSArchie Pusaka
105130f11ddaSArchie Pusaka if (test_bit(H5_HW_FLOW_CONTROL, &h5->flags))
105230f11ddaSArchie Pusaka serdev_device_set_flow_control(h5->hu->serdev, true);
105366f077ddSArchie Pusaka }
105430f11ddaSArchie Pusaka
10558589086fSHans de Goede return 0;
10568589086fSHans de Goede }
10578589086fSHans de Goede
10584c791489SHans de Goede static const struct acpi_gpio_params btrtl_device_wake_gpios = { 0, 0, false };
10594c791489SHans de Goede static const struct acpi_gpio_params btrtl_enable_gpios = { 1, 0, false };
10604c791489SHans de Goede static const struct acpi_gpio_params btrtl_host_wake_gpios = { 2, 0, false };
10614c791489SHans de Goede static const struct acpi_gpio_mapping acpi_btrtl_gpios[] = {
10624c791489SHans de Goede { "device-wake-gpios", &btrtl_device_wake_gpios, 1 },
10634c791489SHans de Goede { "enable-gpios", &btrtl_enable_gpios, 1 },
10644c791489SHans de Goede { "host-wake-gpios", &btrtl_host_wake_gpios, 1 },
10654c791489SHans de Goede {},
10664c791489SHans de Goede };
10674c791489SHans de Goede
1068b825d7c4SJeremy Cline static struct h5_vnd rtl_vnd = {
1069b825d7c4SJeremy Cline .setup = h5_btrtl_setup,
1070b825d7c4SJeremy Cline .open = h5_btrtl_open,
10714c791489SHans de Goede .close = h5_btrtl_close,
10728589086fSHans de Goede .suspend = h5_btrtl_suspend,
10738589086fSHans de Goede .resume = h5_btrtl_resume,
10744c791489SHans de Goede .acpi_gpio_map = acpi_btrtl_gpios,
1075*dd163fa3SAndrey Skvortsov .sizeof_priv = sizeof(struct btrealtek_data),
1076b825d7c4SJeremy Cline };
107766f077ddSArchie Pusaka
107866f077ddSArchie Pusaka static const struct h5_device_data h5_data_rtl8822cs = {
107966f077ddSArchie Pusaka .vnd = &rtl_vnd,
108066f077ddSArchie Pusaka };
108166f077ddSArchie Pusaka
108266f077ddSArchie Pusaka static const struct h5_device_data h5_data_rtl8723bs = {
108366f077ddSArchie Pusaka .driver_info = H5_INFO_WAKEUP_DISABLE,
108466f077ddSArchie Pusaka .vnd = &rtl_vnd,
108566f077ddSArchie Pusaka };
1086b9763cdfSMarcel Holtmann #endif
1087b825d7c4SJeremy Cline
1088b825d7c4SJeremy Cline #ifdef CONFIG_ACPI
1089b825d7c4SJeremy Cline static const struct acpi_device_id h5_acpi_match[] = {
1090b9763cdfSMarcel Holtmann #ifdef CONFIG_BT_HCIUART_RTL
109166f077ddSArchie Pusaka { "OBDA0623", (kernel_ulong_t)&h5_data_rtl8723bs },
109266f077ddSArchie Pusaka { "OBDA8723", (kernel_ulong_t)&h5_data_rtl8723bs },
1093b9763cdfSMarcel Holtmann #endif
1094b825d7c4SJeremy Cline { },
1095b825d7c4SJeremy Cline };
1096b825d7c4SJeremy Cline MODULE_DEVICE_TABLE(acpi, h5_acpi_match);
1097b825d7c4SJeremy Cline #endif
1098b825d7c4SJeremy Cline
109928a75e4cSHans de Goede static const struct dev_pm_ops h5_serdev_pm_ops = {
110028a75e4cSHans de Goede SET_SYSTEM_SLEEP_PM_OPS(h5_serdev_suspend, h5_serdev_resume)
1101d9dd833cSArchie Pusaka SET_RUNTIME_PM_OPS(h5_serdev_suspend, h5_serdev_resume, NULL)
110228a75e4cSHans de Goede };
110328a75e4cSHans de Goede
1104848fc616SMax Chou static const struct of_device_id rtl_bluetooth_of_match[] = {
1105848fc616SMax Chou #ifdef CONFIG_BT_HCIUART_RTL
1106848fc616SMax Chou { .compatible = "realtek,rtl8822cs-bt",
110766f077ddSArchie Pusaka .data = (const void *)&h5_data_rtl8822cs },
11084765db37SVasily Khoruzhick { .compatible = "realtek,rtl8723bs-bt",
110966f077ddSArchie Pusaka .data = (const void *)&h5_data_rtl8723bs },
1110c0123cb6SVasily Khoruzhick { .compatible = "realtek,rtl8723cs-bt",
1111c0123cb6SVasily Khoruzhick .data = (const void *)&h5_data_rtl8723bs },
1112f272f185SJohn-Eric Kamps { .compatible = "realtek,rtl8723ds-bt",
111366f077ddSArchie Pusaka .data = (const void *)&h5_data_rtl8723bs },
1114848fc616SMax Chou #endif
1115848fc616SMax Chou { },
1116848fc616SMax Chou };
1117848fc616SMax Chou MODULE_DEVICE_TABLE(of, rtl_bluetooth_of_match);
1118848fc616SMax Chou
1119ce945552SHans de Goede static struct serdev_device_driver h5_serdev_driver = {
1120ce945552SHans de Goede .probe = h5_serdev_probe,
1121ce945552SHans de Goede .remove = h5_serdev_remove,
1122ce945552SHans de Goede .driver = {
1123ce945552SHans de Goede .name = "hci_uart_h5",
1124b825d7c4SJeremy Cline .acpi_match_table = ACPI_PTR(h5_acpi_match),
112528a75e4cSHans de Goede .pm = &h5_serdev_pm_ops,
1126848fc616SMax Chou .of_match_table = rtl_bluetooth_of_match,
1127ce945552SHans de Goede },
1128ce945552SHans de Goede };
1129ce945552SHans de Goede
h5_init(void)11307dec65c8SJohan Hedberg int __init h5_init(void)
11317dec65c8SJohan Hedberg {
1132ce945552SHans de Goede serdev_device_driver_register(&h5_serdev_driver);
113301009eecSMarcel Holtmann return hci_uart_register_proto(&h5p);
11347dec65c8SJohan Hedberg }
11357dec65c8SJohan Hedberg
h5_deinit(void)11367dec65c8SJohan Hedberg int __exit h5_deinit(void)
11377dec65c8SJohan Hedberg {
1138ce945552SHans de Goede serdev_device_driver_unregister(&h5_serdev_driver);
11397dec65c8SJohan Hedberg return hci_uart_unregister_proto(&h5p);
11407dec65c8SJohan Hedberg }
1141