xref: /openbmc/linux/drivers/bluetooth/hci_qca.c (revision ca2478a7d974f38d29d27acb42a952c7f168916e)
145051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20ff252c1SBen Young Tae Kim /*
30ff252c1SBen Young Tae Kim  *  Bluetooth Software UART Qualcomm protocol
40ff252c1SBen Young Tae Kim  *
50ff252c1SBen Young Tae Kim  *  HCI_IBS (HCI In-Band Sleep) is Qualcomm's power management
60ff252c1SBen Young Tae Kim  *  protocol extension to H4.
70ff252c1SBen Young Tae Kim  *
80ff252c1SBen Young Tae Kim  *  Copyright (C) 2007 Texas Instruments, Inc.
9fa9ad876SBalakrishna Godavarthi  *  Copyright (c) 2010, 2012, 2018 The Linux Foundation. All rights reserved.
100ff252c1SBen Young Tae Kim  *
110ff252c1SBen Young Tae Kim  *  Acknowledgements:
120ff252c1SBen Young Tae Kim  *  This file is based on hci_ll.c, which was...
130ff252c1SBen Young Tae Kim  *  Written by Ohad Ben-Cohen <ohad@bencohen.org>
140ff252c1SBen Young Tae Kim  *  which was in turn based on hci_h4.c, which was written
150ff252c1SBen Young Tae Kim  *  by Maxim Krasnyansky and Marcel Holtmann.
160ff252c1SBen Young Tae Kim  */
170ff252c1SBen Young Tae Kim 
180ff252c1SBen Young Tae Kim #include <linux/kernel.h>
1905ba533cSThierry Escande #include <linux/clk.h>
202faa3f15SMatthias Kaehlcke #include <linux/completion.h>
210ff252c1SBen Young Tae Kim #include <linux/debugfs.h>
22fa9ad876SBalakrishna Godavarthi #include <linux/delay.h>
23d841502cSBalakrishna Godavarthi #include <linux/devcoredump.h>
24fa9ad876SBalakrishna Godavarthi #include <linux/device.h>
2505ba533cSThierry Escande #include <linux/gpio/consumer.h>
2605ba533cSThierry Escande #include <linux/mod_devicetable.h>
2705ba533cSThierry Escande #include <linux/module.h>
28e15f44fbSRob Herring #include <linux/of.h>
29e5d6468fSRocky Liao #include <linux/acpi.h>
30fa9ad876SBalakrishna Godavarthi #include <linux/platform_device.h>
31fa9ad876SBalakrishna Godavarthi #include <linux/regulator/consumer.h>
3205ba533cSThierry Escande #include <linux/serdev.h>
337c2c3e63SVenkata Lakshmi Narayana Gubba #include <linux/mutex.h>
34c614ca3fSBalakrishna Godavarthi #include <asm/unaligned.h>
350ff252c1SBen Young Tae Kim 
360ff252c1SBen Young Tae Kim #include <net/bluetooth/bluetooth.h>
370ff252c1SBen Young Tae Kim #include <net/bluetooth/hci_core.h>
380ff252c1SBen Young Tae Kim 
390ff252c1SBen Young Tae Kim #include "hci_uart.h"
400ff252c1SBen Young Tae Kim #include "btqca.h"
410ff252c1SBen Young Tae Kim 
420ff252c1SBen Young Tae Kim /* HCI_IBS protocol messages */
430ff252c1SBen Young Tae Kim #define HCI_IBS_SLEEP_IND	0xFE
440ff252c1SBen Young Tae Kim #define HCI_IBS_WAKE_IND	0xFD
450ff252c1SBen Young Tae Kim #define HCI_IBS_WAKE_ACK	0xFC
460ff252c1SBen Young Tae Kim #define HCI_MAX_IBS_SIZE	10
470ff252c1SBen Young Tae Kim 
480ff252c1SBen Young Tae Kim #define IBS_WAKE_RETRANS_TIMEOUT_MS	100
492d68476cSBalakrishna Godavarthi #define IBS_BTSOC_TX_IDLE_TIMEOUT_MS	200
5041d5b25fSClaire Chang #define IBS_HOST_TX_IDLE_TIMEOUT_MS	2000
5194d66714SMatthias Kaehlcke #define CMD_TRANS_TIMEOUT_MS		100
52d841502cSBalakrishna Godavarthi #define MEMDUMP_TIMEOUT_MS		8000
53ad3a9c0eSVenkata Lakshmi Narayana Gubba #define IBS_DISABLE_SSR_TIMEOUT_MS \
54ad3a9c0eSVenkata Lakshmi Narayana Gubba 	(MEMDUMP_TIMEOUT_MS + FW_DOWNLOAD_TIMEOUT_MS)
552be43abaSVenkata Lakshmi Narayana Gubba #define FW_DOWNLOAD_TIMEOUT_MS		3000
560ff252c1SBen Young Tae Kim 
5705ba533cSThierry Escande /* susclk rate */
5805ba533cSThierry Escande #define SUSCLK_RATE_32KHZ	32768
5905ba533cSThierry Escande 
60c614ca3fSBalakrishna Godavarthi /* Controller debug log header */
61c614ca3fSBalakrishna Godavarthi #define QCA_DEBUG_HANDLE	0x2EDC
62c614ca3fSBalakrishna Godavarthi 
63bb2500abSRocky Liao /* max retry count when init fails */
64bb2500abSRocky Liao #define MAX_INIT_RETRIES 3
65bb2500abSRocky Liao 
66d841502cSBalakrishna Godavarthi /* Controller dump header */
67d841502cSBalakrishna Godavarthi #define QCA_SSR_DUMP_HANDLE		0x0108
68d841502cSBalakrishna Godavarthi #define QCA_DUMP_PACKET_SIZE		255
69d841502cSBalakrishna Godavarthi #define QCA_LAST_SEQUENCE_NUM		0xFFFF
70d841502cSBalakrishna Godavarthi #define QCA_CRASHBYTE_PACKET_LEN	1096
71d841502cSBalakrishna Godavarthi #define QCA_MEMDUMP_BYTE		0xFB
72d841502cSBalakrishna Godavarthi 
7362a91990SMatthias Kaehlcke enum qca_flags {
742be43abaSVenkata Lakshmi Narayana Gubba 	QCA_IBS_DISABLED,
752faa3f15SMatthias Kaehlcke 	QCA_DROP_VENDOR_EVENT,
7641d5b25fSClaire Chang 	QCA_SUSPENDING,
777c2c3e63SVenkata Lakshmi Narayana Gubba 	QCA_MEMDUMP_COLLECTION,
783344537fSVenkata Lakshmi Narayana Gubba 	QCA_HW_ERROR_EVENT,
792be43abaSVenkata Lakshmi Narayana Gubba 	QCA_SSR_TRIGGERED,
8055c0bd77SVenkata Lakshmi Narayana Gubba 	QCA_BT_OFF,
8147c5d829SJohan Hovold 	QCA_ROM_FW,
8247c5d829SJohan Hovold 	QCA_DEBUGFS_CREATED,
8362a91990SMatthias Kaehlcke };
8462a91990SMatthias Kaehlcke 
85a228f7a4SAbhishek Pandit-Subedi enum qca_capabilities {
86a228f7a4SAbhishek Pandit-Subedi 	QCA_CAP_WIDEBAND_SPEECH = BIT(0),
8754780138SAbhishek Pandit-Subedi 	QCA_CAP_VALID_LE_STATES = BIT(1),
88a228f7a4SAbhishek Pandit-Subedi };
89d841502cSBalakrishna Godavarthi 
900ff252c1SBen Young Tae Kim /* HCI_IBS transmit side sleep protocol states */
910ff252c1SBen Young Tae Kim enum tx_ibs_states {
920ff252c1SBen Young Tae Kim 	HCI_IBS_TX_ASLEEP,
930ff252c1SBen Young Tae Kim 	HCI_IBS_TX_WAKING,
940ff252c1SBen Young Tae Kim 	HCI_IBS_TX_AWAKE,
950ff252c1SBen Young Tae Kim };
960ff252c1SBen Young Tae Kim 
970ff252c1SBen Young Tae Kim /* HCI_IBS receive side sleep protocol states */
980ff252c1SBen Young Tae Kim enum rx_states {
990ff252c1SBen Young Tae Kim 	HCI_IBS_RX_ASLEEP,
1000ff252c1SBen Young Tae Kim 	HCI_IBS_RX_AWAKE,
1010ff252c1SBen Young Tae Kim };
1020ff252c1SBen Young Tae Kim 
1030ff252c1SBen Young Tae Kim /* HCI_IBS transmit and receive side clock state vote */
1040ff252c1SBen Young Tae Kim enum hci_ibs_clock_state_vote {
1050ff252c1SBen Young Tae Kim 	HCI_IBS_VOTE_STATS_UPDATE,
1060ff252c1SBen Young Tae Kim 	HCI_IBS_TX_VOTE_CLOCK_ON,
1070ff252c1SBen Young Tae Kim 	HCI_IBS_TX_VOTE_CLOCK_OFF,
1080ff252c1SBen Young Tae Kim 	HCI_IBS_RX_VOTE_CLOCK_ON,
1090ff252c1SBen Young Tae Kim 	HCI_IBS_RX_VOTE_CLOCK_OFF,
1100ff252c1SBen Young Tae Kim };
1110ff252c1SBen Young Tae Kim 
112d841502cSBalakrishna Godavarthi /* Controller memory dump states */
113d841502cSBalakrishna Godavarthi enum qca_memdump_states {
114d841502cSBalakrishna Godavarthi 	QCA_MEMDUMP_IDLE,
115d841502cSBalakrishna Godavarthi 	QCA_MEMDUMP_COLLECTING,
116d841502cSBalakrishna Godavarthi 	QCA_MEMDUMP_COLLECTED,
117d841502cSBalakrishna Godavarthi 	QCA_MEMDUMP_TIMEOUT,
118d841502cSBalakrishna Godavarthi };
119d841502cSBalakrishna Godavarthi 
12006d3fdfcSSai Teja Aluvala struct qca_memdump_info {
121d841502cSBalakrishna Godavarthi 	u32 current_seq_no;
122d841502cSBalakrishna Godavarthi 	u32 received_dump;
123e5aeebddSZijun Hu 	u32 ram_dump_size;
124d841502cSBalakrishna Godavarthi };
125d841502cSBalakrishna Godavarthi 
126d841502cSBalakrishna Godavarthi struct qca_memdump_event_hdr {
127d841502cSBalakrishna Godavarthi 	__u8    evt;
128d841502cSBalakrishna Godavarthi 	__u8    plen;
129d841502cSBalakrishna Godavarthi 	__u16   opcode;
130fec2972aSLuiz Augusto von Dentz 	__le16   seq_no;
131d841502cSBalakrishna Godavarthi 	__u8    reserved;
132d841502cSBalakrishna Godavarthi } __packed;
133d841502cSBalakrishna Godavarthi 
134d841502cSBalakrishna Godavarthi 
135d841502cSBalakrishna Godavarthi struct qca_dump_size {
136fec2972aSLuiz Augusto von Dentz 	__le32 dump_size;
137d841502cSBalakrishna Godavarthi } __packed;
138d841502cSBalakrishna Godavarthi 
1390ff252c1SBen Young Tae Kim struct qca_data {
1400ff252c1SBen Young Tae Kim 	struct hci_uart *hu;
1410ff252c1SBen Young Tae Kim 	struct sk_buff *rx_skb;
1420ff252c1SBen Young Tae Kim 	struct sk_buff_head txq;
1430ff252c1SBen Young Tae Kim 	struct sk_buff_head tx_wait_q;	/* HCI_IBS wait queue	*/
144d841502cSBalakrishna Godavarthi 	struct sk_buff_head rx_memdump_q;	/* Memdump wait queue	*/
1450ff252c1SBen Young Tae Kim 	spinlock_t hci_ibs_lock;	/* HCI_IBS state lock	*/
1460ff252c1SBen Young Tae Kim 	u8 tx_ibs_state;	/* HCI_IBS transmit side power state*/
1470ff252c1SBen Young Tae Kim 	u8 rx_ibs_state;	/* HCI_IBS receive side power state */
148621a5f7aSViresh Kumar 	bool tx_vote;		/* Clock must be on for TX */
149621a5f7aSViresh Kumar 	bool rx_vote;		/* Clock must be on for RX */
1500ff252c1SBen Young Tae Kim 	struct timer_list tx_idle_timer;
1510ff252c1SBen Young Tae Kim 	u32 tx_idle_delay;
1520ff252c1SBen Young Tae Kim 	struct timer_list wake_retrans_timer;
1530ff252c1SBen Young Tae Kim 	u32 wake_retrans;
1540ff252c1SBen Young Tae Kim 	struct workqueue_struct *workqueue;
1550ff252c1SBen Young Tae Kim 	struct work_struct ws_awake_rx;
1560ff252c1SBen Young Tae Kim 	struct work_struct ws_awake_device;
1570ff252c1SBen Young Tae Kim 	struct work_struct ws_rx_vote_off;
1580ff252c1SBen Young Tae Kim 	struct work_struct ws_tx_vote_off;
159d841502cSBalakrishna Godavarthi 	struct work_struct ctrl_memdump_evt;
1607c2c3e63SVenkata Lakshmi Narayana Gubba 	struct delayed_work ctrl_memdump_timeout;
16106d3fdfcSSai Teja Aluvala 	struct qca_memdump_info *qca_memdump;
1620ff252c1SBen Young Tae Kim 	unsigned long flags;
1632faa3f15SMatthias Kaehlcke 	struct completion drop_ev_comp;
16441d5b25fSClaire Chang 	wait_queue_head_t suspend_wait_q;
165d841502cSBalakrishna Godavarthi 	enum qca_memdump_states memdump_state;
1667c2c3e63SVenkata Lakshmi Narayana Gubba 	struct mutex hci_memdump_lock;
1670ff252c1SBen Young Tae Kim 
16806d3fdfcSSai Teja Aluvala 	u16 fw_version;
16906d3fdfcSSai Teja Aluvala 	u16 controller_id;
1700ff252c1SBen Young Tae Kim 	/* For debugging purpose */
1710ff252c1SBen Young Tae Kim 	u64 ibs_sent_wacks;
1720ff252c1SBen Young Tae Kim 	u64 ibs_sent_slps;
1730ff252c1SBen Young Tae Kim 	u64 ibs_sent_wakes;
1740ff252c1SBen Young Tae Kim 	u64 ibs_recv_wacks;
1750ff252c1SBen Young Tae Kim 	u64 ibs_recv_slps;
1760ff252c1SBen Young Tae Kim 	u64 ibs_recv_wakes;
1770ff252c1SBen Young Tae Kim 	u64 vote_last_jif;
1780ff252c1SBen Young Tae Kim 	u32 vote_on_ms;
1790ff252c1SBen Young Tae Kim 	u32 vote_off_ms;
1800ff252c1SBen Young Tae Kim 	u64 tx_votes_on;
1810ff252c1SBen Young Tae Kim 	u64 rx_votes_on;
1820ff252c1SBen Young Tae Kim 	u64 tx_votes_off;
1830ff252c1SBen Young Tae Kim 	u64 rx_votes_off;
1840ff252c1SBen Young Tae Kim 	u64 votes_on;
1850ff252c1SBen Young Tae Kim 	u64 votes_off;
1860ff252c1SBen Young Tae Kim };
1870ff252c1SBen Young Tae Kim 
18883d9c5e5SBalakrishna Godavarthi enum qca_speed_type {
18983d9c5e5SBalakrishna Godavarthi 	QCA_INIT_SPEED = 1,
19083d9c5e5SBalakrishna Godavarthi 	QCA_OPER_SPEED
19183d9c5e5SBalakrishna Godavarthi };
19283d9c5e5SBalakrishna Godavarthi 
193fa9ad876SBalakrishna Godavarthi /*
194fa9ad876SBalakrishna Godavarthi  * Voltage regulator information required for configuring the
195fa9ad876SBalakrishna Godavarthi  * QCA Bluetooth chipset
196fa9ad876SBalakrishna Godavarthi  */
197fa9ad876SBalakrishna Godavarthi struct qca_vreg {
198fa9ad876SBalakrishna Godavarthi 	const char *name;
199fa9ad876SBalakrishna Godavarthi 	unsigned int load_uA;
200fa9ad876SBalakrishna Godavarthi };
201fa9ad876SBalakrishna Godavarthi 
202a228f7a4SAbhishek Pandit-Subedi struct qca_device_data {
203fa9ad876SBalakrishna Godavarthi 	enum qca_btsoc_type soc_type;
204fa9ad876SBalakrishna Godavarthi 	struct qca_vreg *vregs;
205fa9ad876SBalakrishna Godavarthi 	size_t num_vregs;
206a228f7a4SAbhishek Pandit-Subedi 	uint32_t capabilities;
207fa9ad876SBalakrishna Godavarthi };
208fa9ad876SBalakrishna Godavarthi 
209fa9ad876SBalakrishna Godavarthi /*
210fa9ad876SBalakrishna Godavarthi  * Platform data for the QCA Bluetooth power driver.
211fa9ad876SBalakrishna Godavarthi  */
212fa9ad876SBalakrishna Godavarthi struct qca_power {
213fa9ad876SBalakrishna Godavarthi 	struct device *dev;
214fa9ad876SBalakrishna Godavarthi 	struct regulator_bulk_data *vreg_bulk;
215163d42faSBjorn Andersson 	int num_vregs;
216fa9ad876SBalakrishna Godavarthi 	bool vregs_on;
217fa9ad876SBalakrishna Godavarthi };
218fa9ad876SBalakrishna Godavarthi 
21905ba533cSThierry Escande struct qca_serdev {
22005ba533cSThierry Escande 	struct hci_uart	 serdev_hu;
22105ba533cSThierry Escande 	struct gpio_desc *bt_en;
222d8f97da1SVenkata Lakshmi Narayana Gubba 	struct gpio_desc *sw_ctrl;
22305ba533cSThierry Escande 	struct clk	 *susclk;
224fa9ad876SBalakrishna Godavarthi 	enum qca_btsoc_type btsoc_type;
225fa9ad876SBalakrishna Godavarthi 	struct qca_power *bt_power;
226fa9ad876SBalakrishna Godavarthi 	u32 init_speed;
227fa9ad876SBalakrishna Godavarthi 	u32 oper_speed;
2281622e563SJohan Hovold 	bool bdaddr_property_broken;
22999c905c6SRocky Liao 	const char *firmware_name;
23005ba533cSThierry Escande };
23105ba533cSThierry Escande 
232a9314e76SBjorn Andersson static int qca_regulator_enable(struct qca_serdev *qcadev);
233a9314e76SBjorn Andersson static void qca_regulator_disable(struct qca_serdev *qcadev);
234c2d78273SBalakrishna Godavarthi static void qca_power_shutdown(struct hci_uart *hu);
2353e4be65eSBalakrishna Godavarthi static int qca_power_off(struct hci_dev *hdev);
236d841502cSBalakrishna Godavarthi static void qca_controller_memdump(struct work_struct *work);
23706d3fdfcSSai Teja Aluvala static void qca_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb);
238fa9ad876SBalakrishna Godavarthi 
qca_soc_type(struct hci_uart * hu)2394fdd5a4fSMatthias Kaehlcke static enum qca_btsoc_type qca_soc_type(struct hci_uart *hu)
2404fdd5a4fSMatthias Kaehlcke {
2414fdd5a4fSMatthias Kaehlcke 	enum qca_btsoc_type soc_type;
2424fdd5a4fSMatthias Kaehlcke 
2434fdd5a4fSMatthias Kaehlcke 	if (hu->serdev) {
2444fdd5a4fSMatthias Kaehlcke 		struct qca_serdev *qsd = serdev_device_get_drvdata(hu->serdev);
2454fdd5a4fSMatthias Kaehlcke 
2464fdd5a4fSMatthias Kaehlcke 		soc_type = qsd->btsoc_type;
2474fdd5a4fSMatthias Kaehlcke 	} else {
2484fdd5a4fSMatthias Kaehlcke 		soc_type = QCA_ROME;
2494fdd5a4fSMatthias Kaehlcke 	}
2504fdd5a4fSMatthias Kaehlcke 
2514fdd5a4fSMatthias Kaehlcke 	return soc_type;
2524fdd5a4fSMatthias Kaehlcke }
2534fdd5a4fSMatthias Kaehlcke 
qca_get_firmware_name(struct hci_uart * hu)25499c905c6SRocky Liao static const char *qca_get_firmware_name(struct hci_uart *hu)
25599c905c6SRocky Liao {
25699c905c6SRocky Liao 	if (hu->serdev) {
25799c905c6SRocky Liao 		struct qca_serdev *qsd = serdev_device_get_drvdata(hu->serdev);
25899c905c6SRocky Liao 
25999c905c6SRocky Liao 		return qsd->firmware_name;
26099c905c6SRocky Liao 	} else {
26199c905c6SRocky Liao 		return NULL;
26299c905c6SRocky Liao 	}
26399c905c6SRocky Liao }
26499c905c6SRocky Liao 
__serial_clock_on(struct tty_struct * tty)2650ff252c1SBen Young Tae Kim static void __serial_clock_on(struct tty_struct *tty)
2660ff252c1SBen Young Tae Kim {
2670ff252c1SBen Young Tae Kim 	/* TODO: Some chipset requires to enable UART clock on client
2680ff252c1SBen Young Tae Kim 	 * side to save power consumption or manual work is required.
2690ff252c1SBen Young Tae Kim 	 * Please put your code to control UART clock here if needed
2700ff252c1SBen Young Tae Kim 	 */
2710ff252c1SBen Young Tae Kim }
2720ff252c1SBen Young Tae Kim 
__serial_clock_off(struct tty_struct * tty)2730ff252c1SBen Young Tae Kim static void __serial_clock_off(struct tty_struct *tty)
2740ff252c1SBen Young Tae Kim {
2750ff252c1SBen Young Tae Kim 	/* TODO: Some chipset requires to disable UART clock on client
2760ff252c1SBen Young Tae Kim 	 * side to save power consumption or manual work is required.
2770ff252c1SBen Young Tae Kim 	 * Please put your code to control UART clock off here if needed
2780ff252c1SBen Young Tae Kim 	 */
2790ff252c1SBen Young Tae Kim }
2800ff252c1SBen Young Tae Kim 
2810ff252c1SBen Young Tae Kim /* serial_clock_vote needs to be called with the ibs lock held */
serial_clock_vote(unsigned long vote,struct hci_uart * hu)2820ff252c1SBen Young Tae Kim static void serial_clock_vote(unsigned long vote, struct hci_uart *hu)
2830ff252c1SBen Young Tae Kim {
2840ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
2850ff252c1SBen Young Tae Kim 	unsigned int diff;
2860ff252c1SBen Young Tae Kim 
2870ff252c1SBen Young Tae Kim 	bool old_vote = (qca->tx_vote | qca->rx_vote);
2880ff252c1SBen Young Tae Kim 	bool new_vote;
2890ff252c1SBen Young Tae Kim 
2900ff252c1SBen Young Tae Kim 	switch (vote) {
2910ff252c1SBen Young Tae Kim 	case HCI_IBS_VOTE_STATS_UPDATE:
2920ff252c1SBen Young Tae Kim 		diff = jiffies_to_msecs(jiffies - qca->vote_last_jif);
2930ff252c1SBen Young Tae Kim 
2940ff252c1SBen Young Tae Kim 		if (old_vote)
2950ff252c1SBen Young Tae Kim 			qca->vote_off_ms += diff;
2960ff252c1SBen Young Tae Kim 		else
2970ff252c1SBen Young Tae Kim 			qca->vote_on_ms += diff;
2980ff252c1SBen Young Tae Kim 		return;
2990ff252c1SBen Young Tae Kim 
3000ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_VOTE_CLOCK_ON:
3010ff252c1SBen Young Tae Kim 		qca->tx_vote = true;
3020ff252c1SBen Young Tae Kim 		qca->tx_votes_on++;
3030ff252c1SBen Young Tae Kim 		break;
3040ff252c1SBen Young Tae Kim 
3050ff252c1SBen Young Tae Kim 	case HCI_IBS_RX_VOTE_CLOCK_ON:
3060ff252c1SBen Young Tae Kim 		qca->rx_vote = true;
3070ff252c1SBen Young Tae Kim 		qca->rx_votes_on++;
3080ff252c1SBen Young Tae Kim 		break;
3090ff252c1SBen Young Tae Kim 
3100ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_VOTE_CLOCK_OFF:
3110ff252c1SBen Young Tae Kim 		qca->tx_vote = false;
3120ff252c1SBen Young Tae Kim 		qca->tx_votes_off++;
3130ff252c1SBen Young Tae Kim 		break;
3140ff252c1SBen Young Tae Kim 
3150ff252c1SBen Young Tae Kim 	case HCI_IBS_RX_VOTE_CLOCK_OFF:
3160ff252c1SBen Young Tae Kim 		qca->rx_vote = false;
3170ff252c1SBen Young Tae Kim 		qca->rx_votes_off++;
3180ff252c1SBen Young Tae Kim 		break;
3190ff252c1SBen Young Tae Kim 
3200ff252c1SBen Young Tae Kim 	default:
3210ff252c1SBen Young Tae Kim 		BT_ERR("Voting irregularity");
3220ff252c1SBen Young Tae Kim 		return;
3230ff252c1SBen Young Tae Kim 	}
3240ff252c1SBen Young Tae Kim 
3257310dd3fSMatthias Kaehlcke 	new_vote = qca->rx_vote | qca->tx_vote;
3267310dd3fSMatthias Kaehlcke 
3270ff252c1SBen Young Tae Kim 	if (new_vote != old_vote) {
3280ff252c1SBen Young Tae Kim 		if (new_vote)
3290ff252c1SBen Young Tae Kim 			__serial_clock_on(hu->tty);
3300ff252c1SBen Young Tae Kim 		else
3310ff252c1SBen Young Tae Kim 			__serial_clock_off(hu->tty);
3320ff252c1SBen Young Tae Kim 
3330ff252c1SBen Young Tae Kim 		BT_DBG("Vote serial clock %s(%s)", new_vote ? "true" : "false",
3340ff252c1SBen Young Tae Kim 		       vote ? "true" : "false");
3350ff252c1SBen Young Tae Kim 
3360ff252c1SBen Young Tae Kim 		diff = jiffies_to_msecs(jiffies - qca->vote_last_jif);
3370ff252c1SBen Young Tae Kim 
3380ff252c1SBen Young Tae Kim 		if (new_vote) {
3390ff252c1SBen Young Tae Kim 			qca->votes_on++;
3400ff252c1SBen Young Tae Kim 			qca->vote_off_ms += diff;
3410ff252c1SBen Young Tae Kim 		} else {
3420ff252c1SBen Young Tae Kim 			qca->votes_off++;
3430ff252c1SBen Young Tae Kim 			qca->vote_on_ms += diff;
3440ff252c1SBen Young Tae Kim 		}
3450ff252c1SBen Young Tae Kim 		qca->vote_last_jif = jiffies;
3460ff252c1SBen Young Tae Kim 	}
3470ff252c1SBen Young Tae Kim }
3480ff252c1SBen Young Tae Kim 
3490ff252c1SBen Young Tae Kim /* Builds and sends an HCI_IBS command packet.
3500ff252c1SBen Young Tae Kim  * These are very simple packets with only 1 cmd byte.
3510ff252c1SBen Young Tae Kim  */
send_hci_ibs_cmd(u8 cmd,struct hci_uart * hu)3520ff252c1SBen Young Tae Kim static int send_hci_ibs_cmd(u8 cmd, struct hci_uart *hu)
3530ff252c1SBen Young Tae Kim {
3540ff252c1SBen Young Tae Kim 	int err = 0;
3550ff252c1SBen Young Tae Kim 	struct sk_buff *skb = NULL;
3560ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
3570ff252c1SBen Young Tae Kim 
3580ff252c1SBen Young Tae Kim 	BT_DBG("hu %p send hci ibs cmd 0x%x", hu, cmd);
3590ff252c1SBen Young Tae Kim 
3600ff252c1SBen Young Tae Kim 	skb = bt_skb_alloc(1, GFP_ATOMIC);
3610ff252c1SBen Young Tae Kim 	if (!skb) {
3620ff252c1SBen Young Tae Kim 		BT_ERR("Failed to allocate memory for HCI_IBS packet");
3630ff252c1SBen Young Tae Kim 		return -ENOMEM;
3640ff252c1SBen Young Tae Kim 	}
3650ff252c1SBen Young Tae Kim 
3660ff252c1SBen Young Tae Kim 	/* Assign HCI_IBS type */
367634fef61SJohannes Berg 	skb_put_u8(skb, cmd);
3680ff252c1SBen Young Tae Kim 
3690ff252c1SBen Young Tae Kim 	skb_queue_tail(&qca->txq, skb);
3700ff252c1SBen Young Tae Kim 
3710ff252c1SBen Young Tae Kim 	return err;
3720ff252c1SBen Young Tae Kim }
3730ff252c1SBen Young Tae Kim 
qca_wq_awake_device(struct work_struct * work)3740ff252c1SBen Young Tae Kim static void qca_wq_awake_device(struct work_struct *work)
3750ff252c1SBen Young Tae Kim {
3760ff252c1SBen Young Tae Kim 	struct qca_data *qca = container_of(work, struct qca_data,
3770ff252c1SBen Young Tae Kim 					    ws_awake_device);
3780ff252c1SBen Young Tae Kim 	struct hci_uart *hu = qca->hu;
3790ff252c1SBen Young Tae Kim 	unsigned long retrans_delay;
38031fb1bbdSHarish Bandi 	unsigned long flags;
3810ff252c1SBen Young Tae Kim 
3820ff252c1SBen Young Tae Kim 	BT_DBG("hu %p wq awake device", hu);
3830ff252c1SBen Young Tae Kim 
3840ff252c1SBen Young Tae Kim 	/* Vote for serial clock */
3850ff252c1SBen Young Tae Kim 	serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
3860ff252c1SBen Young Tae Kim 
38731fb1bbdSHarish Bandi 	spin_lock_irqsave(&qca->hci_ibs_lock, flags);
3880ff252c1SBen Young Tae Kim 
3890ff252c1SBen Young Tae Kim 	/* Send wake indication to device */
3900ff252c1SBen Young Tae Kim 	if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0)
3910ff252c1SBen Young Tae Kim 		BT_ERR("Failed to send WAKE to device");
3920ff252c1SBen Young Tae Kim 
3930ff252c1SBen Young Tae Kim 	qca->ibs_sent_wakes++;
3940ff252c1SBen Young Tae Kim 
3950ff252c1SBen Young Tae Kim 	/* Start retransmit timer */
3960ff252c1SBen Young Tae Kim 	retrans_delay = msecs_to_jiffies(qca->wake_retrans);
3970ff252c1SBen Young Tae Kim 	mod_timer(&qca->wake_retrans_timer, jiffies + retrans_delay);
3980ff252c1SBen Young Tae Kim 
39931fb1bbdSHarish Bandi 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
4000ff252c1SBen Young Tae Kim 
4010ff252c1SBen Young Tae Kim 	/* Actually send the packets */
4020ff252c1SBen Young Tae Kim 	hci_uart_tx_wakeup(hu);
4030ff252c1SBen Young Tae Kim }
4040ff252c1SBen Young Tae Kim 
qca_wq_awake_rx(struct work_struct * work)4050ff252c1SBen Young Tae Kim static void qca_wq_awake_rx(struct work_struct *work)
4060ff252c1SBen Young Tae Kim {
4070ff252c1SBen Young Tae Kim 	struct qca_data *qca = container_of(work, struct qca_data,
4080ff252c1SBen Young Tae Kim 					    ws_awake_rx);
4090ff252c1SBen Young Tae Kim 	struct hci_uart *hu = qca->hu;
41031fb1bbdSHarish Bandi 	unsigned long flags;
4110ff252c1SBen Young Tae Kim 
4120ff252c1SBen Young Tae Kim 	BT_DBG("hu %p wq awake rx", hu);
4130ff252c1SBen Young Tae Kim 
4140ff252c1SBen Young Tae Kim 	serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
4150ff252c1SBen Young Tae Kim 
41631fb1bbdSHarish Bandi 	spin_lock_irqsave(&qca->hci_ibs_lock, flags);
4170ff252c1SBen Young Tae Kim 	qca->rx_ibs_state = HCI_IBS_RX_AWAKE;
4180ff252c1SBen Young Tae Kim 
4190ff252c1SBen Young Tae Kim 	/* Always acknowledge device wake up,
4200ff252c1SBen Young Tae Kim 	 * sending IBS message doesn't count as TX ON.
4210ff252c1SBen Young Tae Kim 	 */
4220ff252c1SBen Young Tae Kim 	if (send_hci_ibs_cmd(HCI_IBS_WAKE_ACK, hu) < 0)
4230ff252c1SBen Young Tae Kim 		BT_ERR("Failed to acknowledge device wake up");
4240ff252c1SBen Young Tae Kim 
4250ff252c1SBen Young Tae Kim 	qca->ibs_sent_wacks++;
4260ff252c1SBen Young Tae Kim 
42731fb1bbdSHarish Bandi 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
4280ff252c1SBen Young Tae Kim 
4290ff252c1SBen Young Tae Kim 	/* Actually send the packets */
4300ff252c1SBen Young Tae Kim 	hci_uart_tx_wakeup(hu);
4310ff252c1SBen Young Tae Kim }
4320ff252c1SBen Young Tae Kim 
qca_wq_serial_rx_clock_vote_off(struct work_struct * work)4330ff252c1SBen Young Tae Kim static void qca_wq_serial_rx_clock_vote_off(struct work_struct *work)
4340ff252c1SBen Young Tae Kim {
4350ff252c1SBen Young Tae Kim 	struct qca_data *qca = container_of(work, struct qca_data,
4360ff252c1SBen Young Tae Kim 					    ws_rx_vote_off);
4370ff252c1SBen Young Tae Kim 	struct hci_uart *hu = qca->hu;
4380ff252c1SBen Young Tae Kim 
4390ff252c1SBen Young Tae Kim 	BT_DBG("hu %p rx clock vote off", hu);
4400ff252c1SBen Young Tae Kim 
4410ff252c1SBen Young Tae Kim 	serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu);
4420ff252c1SBen Young Tae Kim }
4430ff252c1SBen Young Tae Kim 
qca_wq_serial_tx_clock_vote_off(struct work_struct * work)4440ff252c1SBen Young Tae Kim static void qca_wq_serial_tx_clock_vote_off(struct work_struct *work)
4450ff252c1SBen Young Tae Kim {
4460ff252c1SBen Young Tae Kim 	struct qca_data *qca = container_of(work, struct qca_data,
4470ff252c1SBen Young Tae Kim 					    ws_tx_vote_off);
4480ff252c1SBen Young Tae Kim 	struct hci_uart *hu = qca->hu;
4490ff252c1SBen Young Tae Kim 
4500ff252c1SBen Young Tae Kim 	BT_DBG("hu %p tx clock vote off", hu);
4510ff252c1SBen Young Tae Kim 
4520ff252c1SBen Young Tae Kim 	/* Run HCI tx handling unlocked */
4530ff252c1SBen Young Tae Kim 	hci_uart_tx_wakeup(hu);
4540ff252c1SBen Young Tae Kim 
4550ff252c1SBen Young Tae Kim 	/* Now that message queued to tty driver, vote for tty clocks off.
4560ff252c1SBen Young Tae Kim 	 * It is up to the tty driver to pend the clocks off until tx done.
4570ff252c1SBen Young Tae Kim 	 */
4580ff252c1SBen Young Tae Kim 	serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
4590ff252c1SBen Young Tae Kim }
4600ff252c1SBen Young Tae Kim 
hci_ibs_tx_idle_timeout(struct timer_list * t)46104356052SKees Cook static void hci_ibs_tx_idle_timeout(struct timer_list *t)
4620ff252c1SBen Young Tae Kim {
46304356052SKees Cook 	struct qca_data *qca = from_timer(qca, t, tx_idle_timer);
46404356052SKees Cook 	struct hci_uart *hu = qca->hu;
4650ff252c1SBen Young Tae Kim 	unsigned long flags;
4660ff252c1SBen Young Tae Kim 
4670ff252c1SBen Young Tae Kim 	BT_DBG("hu %p idle timeout in %d state", hu, qca->tx_ibs_state);
4680ff252c1SBen Young Tae Kim 
4690ff252c1SBen Young Tae Kim 	spin_lock_irqsave_nested(&qca->hci_ibs_lock,
4700ff252c1SBen Young Tae Kim 				 flags, SINGLE_DEPTH_NESTING);
4710ff252c1SBen Young Tae Kim 
4720ff252c1SBen Young Tae Kim 	switch (qca->tx_ibs_state) {
4730ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_AWAKE:
4740ff252c1SBen Young Tae Kim 		/* TX_IDLE, go to SLEEP */
4750ff252c1SBen Young Tae Kim 		if (send_hci_ibs_cmd(HCI_IBS_SLEEP_IND, hu) < 0) {
4760ff252c1SBen Young Tae Kim 			BT_ERR("Failed to send SLEEP to device");
4770ff252c1SBen Young Tae Kim 			break;
4780ff252c1SBen Young Tae Kim 		}
4790ff252c1SBen Young Tae Kim 		qca->tx_ibs_state = HCI_IBS_TX_ASLEEP;
4800ff252c1SBen Young Tae Kim 		qca->ibs_sent_slps++;
4810ff252c1SBen Young Tae Kim 		queue_work(qca->workqueue, &qca->ws_tx_vote_off);
4820ff252c1SBen Young Tae Kim 		break;
4830ff252c1SBen Young Tae Kim 
4840ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_ASLEEP:
4850ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_WAKING:
4860ff252c1SBen Young Tae Kim 	default:
487e059a465SColin Ian King 		BT_ERR("Spurious timeout tx state %d", qca->tx_ibs_state);
4880ff252c1SBen Young Tae Kim 		break;
4890ff252c1SBen Young Tae Kim 	}
4900ff252c1SBen Young Tae Kim 
4910ff252c1SBen Young Tae Kim 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
4920ff252c1SBen Young Tae Kim }
4930ff252c1SBen Young Tae Kim 
hci_ibs_wake_retrans_timeout(struct timer_list * t)49404356052SKees Cook static void hci_ibs_wake_retrans_timeout(struct timer_list *t)
4950ff252c1SBen Young Tae Kim {
49604356052SKees Cook 	struct qca_data *qca = from_timer(qca, t, wake_retrans_timer);
49704356052SKees Cook 	struct hci_uart *hu = qca->hu;
4980ff252c1SBen Young Tae Kim 	unsigned long flags, retrans_delay;
499a9137188SPrasanna Karthik 	bool retransmit = false;
5000ff252c1SBen Young Tae Kim 
5010ff252c1SBen Young Tae Kim 	BT_DBG("hu %p wake retransmit timeout in %d state",
5020ff252c1SBen Young Tae Kim 		hu, qca->tx_ibs_state);
5030ff252c1SBen Young Tae Kim 
5040ff252c1SBen Young Tae Kim 	spin_lock_irqsave_nested(&qca->hci_ibs_lock,
5050ff252c1SBen Young Tae Kim 				 flags, SINGLE_DEPTH_NESTING);
5060ff252c1SBen Young Tae Kim 
50741d5b25fSClaire Chang 	/* Don't retransmit the HCI_IBS_WAKE_IND when suspending. */
50841d5b25fSClaire Chang 	if (test_bit(QCA_SUSPENDING, &qca->flags)) {
50941d5b25fSClaire Chang 		spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
51041d5b25fSClaire Chang 		return;
51141d5b25fSClaire Chang 	}
51241d5b25fSClaire Chang 
5130ff252c1SBen Young Tae Kim 	switch (qca->tx_ibs_state) {
5140ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_WAKING:
5150ff252c1SBen Young Tae Kim 		/* No WAKE_ACK, retransmit WAKE */
516a9137188SPrasanna Karthik 		retransmit = true;
5170ff252c1SBen Young Tae Kim 		if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) {
5180ff252c1SBen Young Tae Kim 			BT_ERR("Failed to acknowledge device wake up");
5190ff252c1SBen Young Tae Kim 			break;
5200ff252c1SBen Young Tae Kim 		}
5210ff252c1SBen Young Tae Kim 		qca->ibs_sent_wakes++;
5220ff252c1SBen Young Tae Kim 		retrans_delay = msecs_to_jiffies(qca->wake_retrans);
5230ff252c1SBen Young Tae Kim 		mod_timer(&qca->wake_retrans_timer, jiffies + retrans_delay);
5240ff252c1SBen Young Tae Kim 		break;
5250ff252c1SBen Young Tae Kim 
5260ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_ASLEEP:
5270ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_AWAKE:
5280ff252c1SBen Young Tae Kim 	default:
529e059a465SColin Ian King 		BT_ERR("Spurious timeout tx state %d", qca->tx_ibs_state);
5300ff252c1SBen Young Tae Kim 		break;
5310ff252c1SBen Young Tae Kim 	}
5320ff252c1SBen Young Tae Kim 
5330ff252c1SBen Young Tae Kim 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
5340ff252c1SBen Young Tae Kim 
5350ff252c1SBen Young Tae Kim 	if (retransmit)
5360ff252c1SBen Young Tae Kim 		hci_uart_tx_wakeup(hu);
5370ff252c1SBen Young Tae Kim }
5380ff252c1SBen Young Tae Kim 
539d841502cSBalakrishna Godavarthi 
qca_controller_memdump_timeout(struct work_struct * work)5407c2c3e63SVenkata Lakshmi Narayana Gubba static void qca_controller_memdump_timeout(struct work_struct *work)
5417c2c3e63SVenkata Lakshmi Narayana Gubba {
5427c2c3e63SVenkata Lakshmi Narayana Gubba 	struct qca_data *qca = container_of(work, struct qca_data,
5437c2c3e63SVenkata Lakshmi Narayana Gubba 					ctrl_memdump_timeout.work);
5447c2c3e63SVenkata Lakshmi Narayana Gubba 	struct hci_uart *hu = qca->hu;
5457c2c3e63SVenkata Lakshmi Narayana Gubba 
5467c2c3e63SVenkata Lakshmi Narayana Gubba 	mutex_lock(&qca->hci_memdump_lock);
5477c2c3e63SVenkata Lakshmi Narayana Gubba 	if (test_bit(QCA_MEMDUMP_COLLECTION, &qca->flags)) {
548d841502cSBalakrishna Godavarthi 		qca->memdump_state = QCA_MEMDUMP_TIMEOUT;
5497c2c3e63SVenkata Lakshmi Narayana Gubba 		if (!test_bit(QCA_HW_ERROR_EVENT, &qca->flags)) {
5507c2c3e63SVenkata Lakshmi Narayana Gubba 			/* Inject hw error event to reset the device
5517c2c3e63SVenkata Lakshmi Narayana Gubba 			 * and driver.
5527c2c3e63SVenkata Lakshmi Narayana Gubba 			 */
5537c2c3e63SVenkata Lakshmi Narayana Gubba 			hci_reset_dev(hu->hdev);
554d841502cSBalakrishna Godavarthi 		}
5557c2c3e63SVenkata Lakshmi Narayana Gubba 	}
5567c2c3e63SVenkata Lakshmi Narayana Gubba 
5577c2c3e63SVenkata Lakshmi Narayana Gubba 	mutex_unlock(&qca->hci_memdump_lock);
5587c2c3e63SVenkata Lakshmi Narayana Gubba }
5597c2c3e63SVenkata Lakshmi Narayana Gubba 
560d841502cSBalakrishna Godavarthi 
5610ff252c1SBen Young Tae Kim /* Initialize protocol */
qca_open(struct hci_uart * hu)5620ff252c1SBen Young Tae Kim static int qca_open(struct hci_uart *hu)
5630ff252c1SBen Young Tae Kim {
56405ba533cSThierry Escande 	struct qca_serdev *qcadev;
5650ff252c1SBen Young Tae Kim 	struct qca_data *qca;
5660ff252c1SBen Young Tae Kim 
5670ff252c1SBen Young Tae Kim 	BT_DBG("hu %p qca_open", hu);
5680ff252c1SBen Young Tae Kim 
569b36a1552SVladis Dronov 	if (!hci_uart_has_flow_control(hu))
570b36a1552SVladis Dronov 		return -EOPNOTSUPP;
571b36a1552SVladis Dronov 
57225a13e38SJia-Ju Bai 	qca = kzalloc(sizeof(struct qca_data), GFP_KERNEL);
5730ff252c1SBen Young Tae Kim 	if (!qca)
5740ff252c1SBen Young Tae Kim 		return -ENOMEM;
5750ff252c1SBen Young Tae Kim 
5760ff252c1SBen Young Tae Kim 	skb_queue_head_init(&qca->txq);
5770ff252c1SBen Young Tae Kim 	skb_queue_head_init(&qca->tx_wait_q);
578d841502cSBalakrishna Godavarthi 	skb_queue_head_init(&qca->rx_memdump_q);
5790ff252c1SBen Young Tae Kim 	spin_lock_init(&qca->hci_ibs_lock);
5807c2c3e63SVenkata Lakshmi Narayana Gubba 	mutex_init(&qca->hci_memdump_lock);
581fac9a602SBhaktipriya Shridhar 	qca->workqueue = alloc_ordered_workqueue("qca_wq", 0);
5820ff252c1SBen Young Tae Kim 	if (!qca->workqueue) {
5830ff252c1SBen Young Tae Kim 		BT_ERR("QCA Workqueue not initialized properly");
5840ff252c1SBen Young Tae Kim 		kfree(qca);
5850ff252c1SBen Young Tae Kim 		return -ENOMEM;
5860ff252c1SBen Young Tae Kim 	}
5870ff252c1SBen Young Tae Kim 
5880ff252c1SBen Young Tae Kim 	INIT_WORK(&qca->ws_awake_rx, qca_wq_awake_rx);
5890ff252c1SBen Young Tae Kim 	INIT_WORK(&qca->ws_awake_device, qca_wq_awake_device);
5900ff252c1SBen Young Tae Kim 	INIT_WORK(&qca->ws_rx_vote_off, qca_wq_serial_rx_clock_vote_off);
5910ff252c1SBen Young Tae Kim 	INIT_WORK(&qca->ws_tx_vote_off, qca_wq_serial_tx_clock_vote_off);
592d841502cSBalakrishna Godavarthi 	INIT_WORK(&qca->ctrl_memdump_evt, qca_controller_memdump);
5937c2c3e63SVenkata Lakshmi Narayana Gubba 	INIT_DELAYED_WORK(&qca->ctrl_memdump_timeout,
5947c2c3e63SVenkata Lakshmi Narayana Gubba 			  qca_controller_memdump_timeout);
59541d5b25fSClaire Chang 	init_waitqueue_head(&qca->suspend_wait_q);
59641d5b25fSClaire Chang 
5970ff252c1SBen Young Tae Kim 	qca->hu = hu;
5982faa3f15SMatthias Kaehlcke 	init_completion(&qca->drop_ev_comp);
5990ff252c1SBen Young Tae Kim 
6000ff252c1SBen Young Tae Kim 	/* Assume we start with both sides asleep -- extra wakes OK */
6010ff252c1SBen Young Tae Kim 	qca->tx_ibs_state = HCI_IBS_TX_ASLEEP;
6020ff252c1SBen Young Tae Kim 	qca->rx_ibs_state = HCI_IBS_RX_ASLEEP;
6030ff252c1SBen Young Tae Kim 
6040ff252c1SBen Young Tae Kim 	qca->vote_last_jif = jiffies;
6050ff252c1SBen Young Tae Kim 
6060ff252c1SBen Young Tae Kim 	hu->priv = qca;
6070ff252c1SBen Young Tae Kim 
608fa9ad876SBalakrishna Godavarthi 	if (hu->serdev) {
609fa9ad876SBalakrishna Godavarthi 		qcadev = serdev_device_get_drvdata(hu->serdev);
61037aee136SChristian Hewitt 
611691d54d0SNeil Armstrong 		switch (qcadev->btsoc_type) {
612691d54d0SNeil Armstrong 		case QCA_WCN3988:
613691d54d0SNeil Armstrong 		case QCA_WCN3990:
614691d54d0SNeil Armstrong 		case QCA_WCN3991:
615691d54d0SNeil Armstrong 		case QCA_WCN3998:
616691d54d0SNeil Armstrong 		case QCA_WCN6750:
617fa9ad876SBalakrishna Godavarthi 			hu->init_speed = qcadev->init_speed;
618691d54d0SNeil Armstrong 			break;
619691d54d0SNeil Armstrong 
620691d54d0SNeil Armstrong 		default:
621691d54d0SNeil Armstrong 			break;
622691d54d0SNeil Armstrong 		}
62337aee136SChristian Hewitt 
62437aee136SChristian Hewitt 		if (qcadev->oper_speed)
625fa9ad876SBalakrishna Godavarthi 			hu->oper_speed = qcadev->oper_speed;
626fa9ad876SBalakrishna Godavarthi 	}
627fa9ad876SBalakrishna Godavarthi 
62804356052SKees Cook 	timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 0);
6290ff252c1SBen Young Tae Kim 	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
6300ff252c1SBen Young Tae Kim 
63104356052SKees Cook 	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
63241d5b25fSClaire Chang 	qca->tx_idle_delay = IBS_HOST_TX_IDLE_TIMEOUT_MS;
6330ff252c1SBen Young Tae Kim 
6340ff252c1SBen Young Tae Kim 	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
6350ff252c1SBen Young Tae Kim 	       qca->tx_idle_delay, qca->wake_retrans);
6360ff252c1SBen Young Tae Kim 
6370ff252c1SBen Young Tae Kim 	return 0;
6380ff252c1SBen Young Tae Kim }
6390ff252c1SBen Young Tae Kim 
qca_debugfs_init(struct hci_dev * hdev)6400ff252c1SBen Young Tae Kim static void qca_debugfs_init(struct hci_dev *hdev)
6410ff252c1SBen Young Tae Kim {
6420ff252c1SBen Young Tae Kim 	struct hci_uart *hu = hci_get_drvdata(hdev);
6430ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
6440ff252c1SBen Young Tae Kim 	struct dentry *ibs_dir;
6450ff252c1SBen Young Tae Kim 	umode_t mode;
6460ff252c1SBen Young Tae Kim 
6470ff252c1SBen Young Tae Kim 	if (!hdev->debugfs)
6480ff252c1SBen Young Tae Kim 		return;
6490ff252c1SBen Young Tae Kim 
65047c5d829SJohan Hovold 	if (test_and_set_bit(QCA_DEBUGFS_CREATED, &qca->flags))
65147c5d829SJohan Hovold 		return;
65247c5d829SJohan Hovold 
6530ff252c1SBen Young Tae Kim 	ibs_dir = debugfs_create_dir("ibs", hdev->debugfs);
6540ff252c1SBen Young Tae Kim 
6550ff252c1SBen Young Tae Kim 	/* read only */
65699719449SNigel Christian 	mode = 0444;
6570ff252c1SBen Young Tae Kim 	debugfs_create_u8("tx_ibs_state", mode, ibs_dir, &qca->tx_ibs_state);
6580ff252c1SBen Young Tae Kim 	debugfs_create_u8("rx_ibs_state", mode, ibs_dir, &qca->rx_ibs_state);
6590ff252c1SBen Young Tae Kim 	debugfs_create_u64("ibs_sent_sleeps", mode, ibs_dir,
6600ff252c1SBen Young Tae Kim 			   &qca->ibs_sent_slps);
6610ff252c1SBen Young Tae Kim 	debugfs_create_u64("ibs_sent_wakes", mode, ibs_dir,
6620ff252c1SBen Young Tae Kim 			   &qca->ibs_sent_wakes);
6630ff252c1SBen Young Tae Kim 	debugfs_create_u64("ibs_sent_wake_acks", mode, ibs_dir,
6640ff252c1SBen Young Tae Kim 			   &qca->ibs_sent_wacks);
6650ff252c1SBen Young Tae Kim 	debugfs_create_u64("ibs_recv_sleeps", mode, ibs_dir,
6660ff252c1SBen Young Tae Kim 			   &qca->ibs_recv_slps);
6670ff252c1SBen Young Tae Kim 	debugfs_create_u64("ibs_recv_wakes", mode, ibs_dir,
6680ff252c1SBen Young Tae Kim 			   &qca->ibs_recv_wakes);
6690ff252c1SBen Young Tae Kim 	debugfs_create_u64("ibs_recv_wake_acks", mode, ibs_dir,
6700ff252c1SBen Young Tae Kim 			   &qca->ibs_recv_wacks);
67110be6c0fSBen YoungTae Kim 	debugfs_create_bool("tx_vote", mode, ibs_dir, &qca->tx_vote);
6720ff252c1SBen Young Tae Kim 	debugfs_create_u64("tx_votes_on", mode, ibs_dir, &qca->tx_votes_on);
6730ff252c1SBen Young Tae Kim 	debugfs_create_u64("tx_votes_off", mode, ibs_dir, &qca->tx_votes_off);
67410be6c0fSBen YoungTae Kim 	debugfs_create_bool("rx_vote", mode, ibs_dir, &qca->rx_vote);
6750ff252c1SBen Young Tae Kim 	debugfs_create_u64("rx_votes_on", mode, ibs_dir, &qca->rx_votes_on);
6760ff252c1SBen Young Tae Kim 	debugfs_create_u64("rx_votes_off", mode, ibs_dir, &qca->rx_votes_off);
6770ff252c1SBen Young Tae Kim 	debugfs_create_u64("votes_on", mode, ibs_dir, &qca->votes_on);
6780ff252c1SBen Young Tae Kim 	debugfs_create_u64("votes_off", mode, ibs_dir, &qca->votes_off);
6790ff252c1SBen Young Tae Kim 	debugfs_create_u32("vote_on_ms", mode, ibs_dir, &qca->vote_on_ms);
6800ff252c1SBen Young Tae Kim 	debugfs_create_u32("vote_off_ms", mode, ibs_dir, &qca->vote_off_ms);
6810ff252c1SBen Young Tae Kim 
6820ff252c1SBen Young Tae Kim 	/* read/write */
68399719449SNigel Christian 	mode = 0644;
6840ff252c1SBen Young Tae Kim 	debugfs_create_u32("wake_retrans", mode, ibs_dir, &qca->wake_retrans);
6850ff252c1SBen Young Tae Kim 	debugfs_create_u32("tx_idle_delay", mode, ibs_dir,
6860ff252c1SBen Young Tae Kim 			   &qca->tx_idle_delay);
6870ff252c1SBen Young Tae Kim }
6880ff252c1SBen Young Tae Kim 
6890ff252c1SBen Young Tae Kim /* Flush protocol data */
qca_flush(struct hci_uart * hu)6900ff252c1SBen Young Tae Kim static int qca_flush(struct hci_uart *hu)
6910ff252c1SBen Young Tae Kim {
6920ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
6930ff252c1SBen Young Tae Kim 
6940ff252c1SBen Young Tae Kim 	BT_DBG("hu %p qca flush", hu);
6950ff252c1SBen Young Tae Kim 
6960ff252c1SBen Young Tae Kim 	skb_queue_purge(&qca->tx_wait_q);
6970ff252c1SBen Young Tae Kim 	skb_queue_purge(&qca->txq);
6980ff252c1SBen Young Tae Kim 
6990ff252c1SBen Young Tae Kim 	return 0;
7000ff252c1SBen Young Tae Kim }
7010ff252c1SBen Young Tae Kim 
7020ff252c1SBen Young Tae Kim /* Close protocol */
qca_close(struct hci_uart * hu)7030ff252c1SBen Young Tae Kim static int qca_close(struct hci_uart *hu)
7040ff252c1SBen Young Tae Kim {
7050ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
7060ff252c1SBen Young Tae Kim 
7070ff252c1SBen Young Tae Kim 	BT_DBG("hu %p qca close", hu);
7080ff252c1SBen Young Tae Kim 
7090ff252c1SBen Young Tae Kim 	serial_clock_vote(HCI_IBS_VOTE_STATS_UPDATE, hu);
7100ff252c1SBen Young Tae Kim 
7110ff252c1SBen Young Tae Kim 	skb_queue_purge(&qca->tx_wait_q);
7120ff252c1SBen Young Tae Kim 	skb_queue_purge(&qca->txq);
713d841502cSBalakrishna Godavarthi 	skb_queue_purge(&qca->rx_memdump_q);
714e0d3da98SThomas Gleixner 	/*
715e0d3da98SThomas Gleixner 	 * Shut the timers down so they can't be rearmed when
716e0d3da98SThomas Gleixner 	 * destroy_workqueue() drains pending work which in turn might try
717e0d3da98SThomas Gleixner 	 * to arm a timer.  After shutdown rearm attempts are silently
718e0d3da98SThomas Gleixner 	 * ignored by the timer core code.
719e0d3da98SThomas Gleixner 	 */
720e0d3da98SThomas Gleixner 	timer_shutdown_sync(&qca->tx_idle_timer);
721e0d3da98SThomas Gleixner 	timer_shutdown_sync(&qca->wake_retrans_timer);
7220ff252c1SBen Young Tae Kim 	destroy_workqueue(qca->workqueue);
7230ff252c1SBen Young Tae Kim 	qca->hu = NULL;
7240ff252c1SBen Young Tae Kim 
7250ff252c1SBen Young Tae Kim 	kfree_skb(qca->rx_skb);
7260ff252c1SBen Young Tae Kim 
7270ff252c1SBen Young Tae Kim 	hu->priv = NULL;
7280ff252c1SBen Young Tae Kim 
7290ff252c1SBen Young Tae Kim 	kfree(qca);
7300ff252c1SBen Young Tae Kim 
7310ff252c1SBen Young Tae Kim 	return 0;
7320ff252c1SBen Young Tae Kim }
7330ff252c1SBen Young Tae Kim 
7340ff252c1SBen Young Tae Kim /* Called upon a wake-up-indication from the device.
7350ff252c1SBen Young Tae Kim  */
device_want_to_wakeup(struct hci_uart * hu)7360ff252c1SBen Young Tae Kim static void device_want_to_wakeup(struct hci_uart *hu)
7370ff252c1SBen Young Tae Kim {
7380ff252c1SBen Young Tae Kim 	unsigned long flags;
7390ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
7400ff252c1SBen Young Tae Kim 
7410ff252c1SBen Young Tae Kim 	BT_DBG("hu %p want to wake up", hu);
7420ff252c1SBen Young Tae Kim 
7430ff252c1SBen Young Tae Kim 	spin_lock_irqsave(&qca->hci_ibs_lock, flags);
7440ff252c1SBen Young Tae Kim 
7450ff252c1SBen Young Tae Kim 	qca->ibs_recv_wakes++;
7460ff252c1SBen Young Tae Kim 
74741d5b25fSClaire Chang 	/* Don't wake the rx up when suspending. */
74841d5b25fSClaire Chang 	if (test_bit(QCA_SUSPENDING, &qca->flags)) {
74941d5b25fSClaire Chang 		spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
75041d5b25fSClaire Chang 		return;
75141d5b25fSClaire Chang 	}
75241d5b25fSClaire Chang 
7530ff252c1SBen Young Tae Kim 	switch (qca->rx_ibs_state) {
7540ff252c1SBen Young Tae Kim 	case HCI_IBS_RX_ASLEEP:
7550ff252c1SBen Young Tae Kim 		/* Make sure clock is on - we may have turned clock off since
7560ff252c1SBen Young Tae Kim 		 * receiving the wake up indicator awake rx clock.
7570ff252c1SBen Young Tae Kim 		 */
7580ff252c1SBen Young Tae Kim 		queue_work(qca->workqueue, &qca->ws_awake_rx);
7590ff252c1SBen Young Tae Kim 		spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
7600ff252c1SBen Young Tae Kim 		return;
7610ff252c1SBen Young Tae Kim 
7620ff252c1SBen Young Tae Kim 	case HCI_IBS_RX_AWAKE:
7630ff252c1SBen Young Tae Kim 		/* Always acknowledge device wake up,
7640ff252c1SBen Young Tae Kim 		 * sending IBS message doesn't count as TX ON.
7650ff252c1SBen Young Tae Kim 		 */
7660ff252c1SBen Young Tae Kim 		if (send_hci_ibs_cmd(HCI_IBS_WAKE_ACK, hu) < 0) {
7670ff252c1SBen Young Tae Kim 			BT_ERR("Failed to acknowledge device wake up");
7680ff252c1SBen Young Tae Kim 			break;
7690ff252c1SBen Young Tae Kim 		}
7700ff252c1SBen Young Tae Kim 		qca->ibs_sent_wacks++;
7710ff252c1SBen Young Tae Kim 		break;
7720ff252c1SBen Young Tae Kim 
7730ff252c1SBen Young Tae Kim 	default:
7740ff252c1SBen Young Tae Kim 		/* Any other state is illegal */
7750ff252c1SBen Young Tae Kim 		BT_ERR("Received HCI_IBS_WAKE_IND in rx state %d",
7760ff252c1SBen Young Tae Kim 		       qca->rx_ibs_state);
7770ff252c1SBen Young Tae Kim 		break;
7780ff252c1SBen Young Tae Kim 	}
7790ff252c1SBen Young Tae Kim 
7800ff252c1SBen Young Tae Kim 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
7810ff252c1SBen Young Tae Kim 
7820ff252c1SBen Young Tae Kim 	/* Actually send the packets */
7830ff252c1SBen Young Tae Kim 	hci_uart_tx_wakeup(hu);
7840ff252c1SBen Young Tae Kim }
7850ff252c1SBen Young Tae Kim 
7860ff252c1SBen Young Tae Kim /* Called upon a sleep-indication from the device.
7870ff252c1SBen Young Tae Kim  */
device_want_to_sleep(struct hci_uart * hu)7880ff252c1SBen Young Tae Kim static void device_want_to_sleep(struct hci_uart *hu)
7890ff252c1SBen Young Tae Kim {
7900ff252c1SBen Young Tae Kim 	unsigned long flags;
7910ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
7920ff252c1SBen Young Tae Kim 
7936600c080SRocky Liao 	BT_DBG("hu %p want to sleep in %d state", hu, qca->rx_ibs_state);
7940ff252c1SBen Young Tae Kim 
7950ff252c1SBen Young Tae Kim 	spin_lock_irqsave(&qca->hci_ibs_lock, flags);
7960ff252c1SBen Young Tae Kim 
7970ff252c1SBen Young Tae Kim 	qca->ibs_recv_slps++;
7980ff252c1SBen Young Tae Kim 
7990ff252c1SBen Young Tae Kim 	switch (qca->rx_ibs_state) {
8000ff252c1SBen Young Tae Kim 	case HCI_IBS_RX_AWAKE:
8010ff252c1SBen Young Tae Kim 		/* Update state */
8020ff252c1SBen Young Tae Kim 		qca->rx_ibs_state = HCI_IBS_RX_ASLEEP;
8030ff252c1SBen Young Tae Kim 		/* Vote off rx clock under workqueue */
8040ff252c1SBen Young Tae Kim 		queue_work(qca->workqueue, &qca->ws_rx_vote_off);
8050ff252c1SBen Young Tae Kim 		break;
8060ff252c1SBen Young Tae Kim 
8070ff252c1SBen Young Tae Kim 	case HCI_IBS_RX_ASLEEP:
8086600c080SRocky Liao 		break;
8090ff252c1SBen Young Tae Kim 
8100ff252c1SBen Young Tae Kim 	default:
8110ff252c1SBen Young Tae Kim 		/* Any other state is illegal */
8120ff252c1SBen Young Tae Kim 		BT_ERR("Received HCI_IBS_SLEEP_IND in rx state %d",
8130ff252c1SBen Young Tae Kim 		       qca->rx_ibs_state);
8140ff252c1SBen Young Tae Kim 		break;
8150ff252c1SBen Young Tae Kim 	}
8160ff252c1SBen Young Tae Kim 
81741d5b25fSClaire Chang 	wake_up_interruptible(&qca->suspend_wait_q);
81841d5b25fSClaire Chang 
8190ff252c1SBen Young Tae Kim 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
8200ff252c1SBen Young Tae Kim }
8210ff252c1SBen Young Tae Kim 
8220ff252c1SBen Young Tae Kim /* Called upon wake-up-acknowledgement from the device
8230ff252c1SBen Young Tae Kim  */
device_woke_up(struct hci_uart * hu)8240ff252c1SBen Young Tae Kim static void device_woke_up(struct hci_uart *hu)
8250ff252c1SBen Young Tae Kim {
8260ff252c1SBen Young Tae Kim 	unsigned long flags, idle_delay;
8270ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
8280ff252c1SBen Young Tae Kim 	struct sk_buff *skb = NULL;
8290ff252c1SBen Young Tae Kim 
8300ff252c1SBen Young Tae Kim 	BT_DBG("hu %p woke up", hu);
8310ff252c1SBen Young Tae Kim 
8320ff252c1SBen Young Tae Kim 	spin_lock_irqsave(&qca->hci_ibs_lock, flags);
8330ff252c1SBen Young Tae Kim 
8340ff252c1SBen Young Tae Kim 	qca->ibs_recv_wacks++;
8350ff252c1SBen Young Tae Kim 
83641d5b25fSClaire Chang 	/* Don't react to the wake-up-acknowledgment when suspending. */
83741d5b25fSClaire Chang 	if (test_bit(QCA_SUSPENDING, &qca->flags)) {
83841d5b25fSClaire Chang 		spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
83941d5b25fSClaire Chang 		return;
84041d5b25fSClaire Chang 	}
84141d5b25fSClaire Chang 
8420ff252c1SBen Young Tae Kim 	switch (qca->tx_ibs_state) {
8430ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_AWAKE:
8440ff252c1SBen Young Tae Kim 		/* Expect one if we send 2 WAKEs */
8450ff252c1SBen Young Tae Kim 		BT_DBG("Received HCI_IBS_WAKE_ACK in tx state %d",
8460ff252c1SBen Young Tae Kim 		       qca->tx_ibs_state);
8470ff252c1SBen Young Tae Kim 		break;
8480ff252c1SBen Young Tae Kim 
8490ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_WAKING:
8500ff252c1SBen Young Tae Kim 		/* Send pending packets */
8510ff252c1SBen Young Tae Kim 		while ((skb = skb_dequeue(&qca->tx_wait_q)))
8520ff252c1SBen Young Tae Kim 			skb_queue_tail(&qca->txq, skb);
8530ff252c1SBen Young Tae Kim 
8540ff252c1SBen Young Tae Kim 		/* Switch timers and change state to HCI_IBS_TX_AWAKE */
8550ff252c1SBen Young Tae Kim 		del_timer(&qca->wake_retrans_timer);
8560ff252c1SBen Young Tae Kim 		idle_delay = msecs_to_jiffies(qca->tx_idle_delay);
8570ff252c1SBen Young Tae Kim 		mod_timer(&qca->tx_idle_timer, jiffies + idle_delay);
8580ff252c1SBen Young Tae Kim 		qca->tx_ibs_state = HCI_IBS_TX_AWAKE;
8590ff252c1SBen Young Tae Kim 		break;
8600ff252c1SBen Young Tae Kim 
8610ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_ASLEEP:
8620ff252c1SBen Young Tae Kim 	default:
8630ff252c1SBen Young Tae Kim 		BT_ERR("Received HCI_IBS_WAKE_ACK in tx state %d",
8640ff252c1SBen Young Tae Kim 		       qca->tx_ibs_state);
8650ff252c1SBen Young Tae Kim 		break;
8660ff252c1SBen Young Tae Kim 	}
8670ff252c1SBen Young Tae Kim 
8680ff252c1SBen Young Tae Kim 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
8690ff252c1SBen Young Tae Kim 
8700ff252c1SBen Young Tae Kim 	/* Actually send the packets */
8710ff252c1SBen Young Tae Kim 	hci_uart_tx_wakeup(hu);
8720ff252c1SBen Young Tae Kim }
8730ff252c1SBen Young Tae Kim 
8740ff252c1SBen Young Tae Kim /* Enqueue frame for transmittion (padding, crc, etc) may be called from
8750ff252c1SBen Young Tae Kim  * two simultaneous tasklets.
8760ff252c1SBen Young Tae Kim  */
qca_enqueue(struct hci_uart * hu,struct sk_buff * skb)8770ff252c1SBen Young Tae Kim static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb)
8780ff252c1SBen Young Tae Kim {
8790ff252c1SBen Young Tae Kim 	unsigned long flags = 0, idle_delay;
8800ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
8810ff252c1SBen Young Tae Kim 
8820ff252c1SBen Young Tae Kim 	BT_DBG("hu %p qca enq skb %p tx_ibs_state %d", hu, skb,
8830ff252c1SBen Young Tae Kim 	       qca->tx_ibs_state);
8840ff252c1SBen Young Tae Kim 
8853344537fSVenkata Lakshmi Narayana Gubba 	if (test_bit(QCA_SSR_TRIGGERED, &qca->flags)) {
8863344537fSVenkata Lakshmi Narayana Gubba 		/* As SSR is in progress, ignore the packets */
8873344537fSVenkata Lakshmi Narayana Gubba 		bt_dev_dbg(hu->hdev, "SSR is in progress");
8883344537fSVenkata Lakshmi Narayana Gubba 		kfree_skb(skb);
8893344537fSVenkata Lakshmi Narayana Gubba 		return 0;
8903344537fSVenkata Lakshmi Narayana Gubba 	}
8913344537fSVenkata Lakshmi Narayana Gubba 
8920ff252c1SBen Young Tae Kim 	/* Prepend skb with frame type */
893618e8bc2SMarcel Holtmann 	memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
8940ff252c1SBen Young Tae Kim 
895035a960eSBalakrishna Godavarthi 	spin_lock_irqsave(&qca->hci_ibs_lock, flags);
896035a960eSBalakrishna Godavarthi 
8970ff252c1SBen Young Tae Kim 	/* Don't go to sleep in middle of patch download or
8980ff252c1SBen Young Tae Kim 	 * Out-Of-Band(GPIOs control) sleep is selected.
89941d5b25fSClaire Chang 	 * Don't wake the device up when suspending.
9000ff252c1SBen Young Tae Kim 	 */
9012be43abaSVenkata Lakshmi Narayana Gubba 	if (test_bit(QCA_IBS_DISABLED, &qca->flags) ||
90241d5b25fSClaire Chang 	    test_bit(QCA_SUSPENDING, &qca->flags)) {
9030ff252c1SBen Young Tae Kim 		skb_queue_tail(&qca->txq, skb);
904035a960eSBalakrishna Godavarthi 		spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
9050ff252c1SBen Young Tae Kim 		return 0;
9060ff252c1SBen Young Tae Kim 	}
9070ff252c1SBen Young Tae Kim 
9080ff252c1SBen Young Tae Kim 	/* Act according to current state */
9090ff252c1SBen Young Tae Kim 	switch (qca->tx_ibs_state) {
9100ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_AWAKE:
9110ff252c1SBen Young Tae Kim 		BT_DBG("Device awake, sending normally");
9120ff252c1SBen Young Tae Kim 		skb_queue_tail(&qca->txq, skb);
9130ff252c1SBen Young Tae Kim 		idle_delay = msecs_to_jiffies(qca->tx_idle_delay);
9140ff252c1SBen Young Tae Kim 		mod_timer(&qca->tx_idle_timer, jiffies + idle_delay);
9150ff252c1SBen Young Tae Kim 		break;
9160ff252c1SBen Young Tae Kim 
9170ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_ASLEEP:
9180ff252c1SBen Young Tae Kim 		BT_DBG("Device asleep, waking up and queueing packet");
9190ff252c1SBen Young Tae Kim 		/* Save packet for later */
9200ff252c1SBen Young Tae Kim 		skb_queue_tail(&qca->tx_wait_q, skb);
9210ff252c1SBen Young Tae Kim 
9220ff252c1SBen Young Tae Kim 		qca->tx_ibs_state = HCI_IBS_TX_WAKING;
9230ff252c1SBen Young Tae Kim 		/* Schedule a work queue to wake up device */
9240ff252c1SBen Young Tae Kim 		queue_work(qca->workqueue, &qca->ws_awake_device);
9250ff252c1SBen Young Tae Kim 		break;
9260ff252c1SBen Young Tae Kim 
9270ff252c1SBen Young Tae Kim 	case HCI_IBS_TX_WAKING:
9280ff252c1SBen Young Tae Kim 		BT_DBG("Device waking up, queueing packet");
9290ff252c1SBen Young Tae Kim 		/* Transient state; just keep packet for later */
9300ff252c1SBen Young Tae Kim 		skb_queue_tail(&qca->tx_wait_q, skb);
9310ff252c1SBen Young Tae Kim 		break;
9320ff252c1SBen Young Tae Kim 
9330ff252c1SBen Young Tae Kim 	default:
9340ff252c1SBen Young Tae Kim 		BT_ERR("Illegal tx state: %d (losing packet)",
9350ff252c1SBen Young Tae Kim 		       qca->tx_ibs_state);
936df4cfc91SYang Yingliang 		dev_kfree_skb_irq(skb);
9370ff252c1SBen Young Tae Kim 		break;
9380ff252c1SBen Young Tae Kim 	}
9390ff252c1SBen Young Tae Kim 
9400ff252c1SBen Young Tae Kim 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
9410ff252c1SBen Young Tae Kim 
9420ff252c1SBen Young Tae Kim 	return 0;
9430ff252c1SBen Young Tae Kim }
9440ff252c1SBen Young Tae Kim 
qca_ibs_sleep_ind(struct hci_dev * hdev,struct sk_buff * skb)9450ff252c1SBen Young Tae Kim static int qca_ibs_sleep_ind(struct hci_dev *hdev, struct sk_buff *skb)
9460ff252c1SBen Young Tae Kim {
9470ff252c1SBen Young Tae Kim 	struct hci_uart *hu = hci_get_drvdata(hdev);
9480ff252c1SBen Young Tae Kim 
9490ff252c1SBen Young Tae Kim 	BT_DBG("hu %p recv hci ibs cmd 0x%x", hu, HCI_IBS_SLEEP_IND);
9500ff252c1SBen Young Tae Kim 
9510ff252c1SBen Young Tae Kim 	device_want_to_sleep(hu);
9520ff252c1SBen Young Tae Kim 
9530ff252c1SBen Young Tae Kim 	kfree_skb(skb);
9540ff252c1SBen Young Tae Kim 	return 0;
9550ff252c1SBen Young Tae Kim }
9560ff252c1SBen Young Tae Kim 
qca_ibs_wake_ind(struct hci_dev * hdev,struct sk_buff * skb)9570ff252c1SBen Young Tae Kim static int qca_ibs_wake_ind(struct hci_dev *hdev, struct sk_buff *skb)
9580ff252c1SBen Young Tae Kim {
9590ff252c1SBen Young Tae Kim 	struct hci_uart *hu = hci_get_drvdata(hdev);
9600ff252c1SBen Young Tae Kim 
9610ff252c1SBen Young Tae Kim 	BT_DBG("hu %p recv hci ibs cmd 0x%x", hu, HCI_IBS_WAKE_IND);
9620ff252c1SBen Young Tae Kim 
9630ff252c1SBen Young Tae Kim 	device_want_to_wakeup(hu);
9640ff252c1SBen Young Tae Kim 
9650ff252c1SBen Young Tae Kim 	kfree_skb(skb);
9660ff252c1SBen Young Tae Kim 	return 0;
9670ff252c1SBen Young Tae Kim }
9680ff252c1SBen Young Tae Kim 
qca_ibs_wake_ack(struct hci_dev * hdev,struct sk_buff * skb)9690ff252c1SBen Young Tae Kim static int qca_ibs_wake_ack(struct hci_dev *hdev, struct sk_buff *skb)
9700ff252c1SBen Young Tae Kim {
9710ff252c1SBen Young Tae Kim 	struct hci_uart *hu = hci_get_drvdata(hdev);
9720ff252c1SBen Young Tae Kim 
9730ff252c1SBen Young Tae Kim 	BT_DBG("hu %p recv hci ibs cmd 0x%x", hu, HCI_IBS_WAKE_ACK);
9740ff252c1SBen Young Tae Kim 
9750ff252c1SBen Young Tae Kim 	device_woke_up(hu);
9760ff252c1SBen Young Tae Kim 
9770ff252c1SBen Young Tae Kim 	kfree_skb(skb);
9780ff252c1SBen Young Tae Kim 	return 0;
9790ff252c1SBen Young Tae Kim }
9800ff252c1SBen Young Tae Kim 
qca_recv_acl_data(struct hci_dev * hdev,struct sk_buff * skb)981c614ca3fSBalakrishna Godavarthi static int qca_recv_acl_data(struct hci_dev *hdev, struct sk_buff *skb)
982c614ca3fSBalakrishna Godavarthi {
983c614ca3fSBalakrishna Godavarthi 	/* We receive debug logs from chip as an ACL packets.
984c614ca3fSBalakrishna Godavarthi 	 * Instead of sending the data to ACL to decode the
985c614ca3fSBalakrishna Godavarthi 	 * received data, we are pushing them to the above layers
986c614ca3fSBalakrishna Godavarthi 	 * as a diagnostic packet.
987c614ca3fSBalakrishna Godavarthi 	 */
988c614ca3fSBalakrishna Godavarthi 	if (get_unaligned_le16(skb->data) == QCA_DEBUG_HANDLE)
989c614ca3fSBalakrishna Godavarthi 		return hci_recv_diag(hdev, skb);
990c614ca3fSBalakrishna Godavarthi 
991c614ca3fSBalakrishna Godavarthi 	return hci_recv_frame(hdev, skb);
992c614ca3fSBalakrishna Godavarthi }
993c614ca3fSBalakrishna Godavarthi 
qca_dmp_hdr(struct hci_dev * hdev,struct sk_buff * skb)99406d3fdfcSSai Teja Aluvala static void qca_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)
99506d3fdfcSSai Teja Aluvala {
99606d3fdfcSSai Teja Aluvala 	struct hci_uart *hu = hci_get_drvdata(hdev);
99706d3fdfcSSai Teja Aluvala 	struct qca_data *qca = hu->priv;
99806d3fdfcSSai Teja Aluvala 	char buf[80];
99906d3fdfcSSai Teja Aluvala 
100006d3fdfcSSai Teja Aluvala 	snprintf(buf, sizeof(buf), "Controller Name: 0x%x\n",
100106d3fdfcSSai Teja Aluvala 		qca->controller_id);
100206d3fdfcSSai Teja Aluvala 	skb_put_data(skb, buf, strlen(buf));
100306d3fdfcSSai Teja Aluvala 
100406d3fdfcSSai Teja Aluvala 	snprintf(buf, sizeof(buf), "Firmware Version: 0x%x\n",
100506d3fdfcSSai Teja Aluvala 		qca->fw_version);
100606d3fdfcSSai Teja Aluvala 	skb_put_data(skb, buf, strlen(buf));
100706d3fdfcSSai Teja Aluvala 
100806d3fdfcSSai Teja Aluvala 	snprintf(buf, sizeof(buf), "Vendor:Qualcomm\n");
100906d3fdfcSSai Teja Aluvala 	skb_put_data(skb, buf, strlen(buf));
101006d3fdfcSSai Teja Aluvala 
101106d3fdfcSSai Teja Aluvala 	snprintf(buf, sizeof(buf), "Driver: %s\n",
101206d3fdfcSSai Teja Aluvala 		hu->serdev->dev.driver->name);
101306d3fdfcSSai Teja Aluvala 	skb_put_data(skb, buf, strlen(buf));
101406d3fdfcSSai Teja Aluvala }
101506d3fdfcSSai Teja Aluvala 
qca_controller_memdump(struct work_struct * work)1016d841502cSBalakrishna Godavarthi static void qca_controller_memdump(struct work_struct *work)
1017d841502cSBalakrishna Godavarthi {
1018d841502cSBalakrishna Godavarthi 	struct qca_data *qca = container_of(work, struct qca_data,
1019d841502cSBalakrishna Godavarthi 					    ctrl_memdump_evt);
1020d841502cSBalakrishna Godavarthi 	struct hci_uart *hu = qca->hu;
1021d841502cSBalakrishna Godavarthi 	struct sk_buff *skb;
1022d841502cSBalakrishna Godavarthi 	struct qca_memdump_event_hdr *cmd_hdr;
102306d3fdfcSSai Teja Aluvala 	struct qca_memdump_info *qca_memdump = qca->qca_memdump;
1024d841502cSBalakrishna Godavarthi 	struct qca_dump_size *dump;
102556b084edSYueHaibing 	u16 seq_no;
1026e5aeebddSZijun Hu 	u32 rx_size;
102706d3fdfcSSai Teja Aluvala 	int ret = 0;
1028e5aeebddSZijun Hu 	enum qca_btsoc_type soc_type = qca_soc_type(hu);
1029d841502cSBalakrishna Godavarthi 
1030d841502cSBalakrishna Godavarthi 	while ((skb = skb_dequeue(&qca->rx_memdump_q))) {
1031d841502cSBalakrishna Godavarthi 
10327c2c3e63SVenkata Lakshmi Narayana Gubba 		mutex_lock(&qca->hci_memdump_lock);
1033f98aa80fSVenkata Lakshmi Narayana Gubba 		/* Skip processing the received packets if timeout detected
1034f98aa80fSVenkata Lakshmi Narayana Gubba 		 * or memdump collection completed.
1035f98aa80fSVenkata Lakshmi Narayana Gubba 		 */
1036f98aa80fSVenkata Lakshmi Narayana Gubba 		if (qca->memdump_state == QCA_MEMDUMP_TIMEOUT ||
1037f98aa80fSVenkata Lakshmi Narayana Gubba 		    qca->memdump_state == QCA_MEMDUMP_COLLECTED) {
10387c2c3e63SVenkata Lakshmi Narayana Gubba 			mutex_unlock(&qca->hci_memdump_lock);
10397c2c3e63SVenkata Lakshmi Narayana Gubba 			return;
10407c2c3e63SVenkata Lakshmi Narayana Gubba 		}
10417c2c3e63SVenkata Lakshmi Narayana Gubba 
1042d841502cSBalakrishna Godavarthi 		if (!qca_memdump) {
104306d3fdfcSSai Teja Aluvala 			qca_memdump = kzalloc(sizeof(struct qca_memdump_info),
1044d841502cSBalakrishna Godavarthi 					      GFP_ATOMIC);
10457c2c3e63SVenkata Lakshmi Narayana Gubba 			if (!qca_memdump) {
10467c2c3e63SVenkata Lakshmi Narayana Gubba 				mutex_unlock(&qca->hci_memdump_lock);
1047d841502cSBalakrishna Godavarthi 				return;
10487c2c3e63SVenkata Lakshmi Narayana Gubba 			}
1049d841502cSBalakrishna Godavarthi 
1050d841502cSBalakrishna Godavarthi 			qca->qca_memdump = qca_memdump;
1051d841502cSBalakrishna Godavarthi 		}
1052d841502cSBalakrishna Godavarthi 
1053d841502cSBalakrishna Godavarthi 		qca->memdump_state = QCA_MEMDUMP_COLLECTING;
1054d841502cSBalakrishna Godavarthi 		cmd_hdr = (void *) skb->data;
1055d841502cSBalakrishna Godavarthi 		seq_no = __le16_to_cpu(cmd_hdr->seq_no);
1056d841502cSBalakrishna Godavarthi 		skb_pull(skb, sizeof(struct qca_memdump_event_hdr));
1057d841502cSBalakrishna Godavarthi 
1058d841502cSBalakrishna Godavarthi 		if (!seq_no) {
1059d841502cSBalakrishna Godavarthi 
1060d841502cSBalakrishna Godavarthi 			/* This is the first frame of memdump packet from
1061d841502cSBalakrishna Godavarthi 			 * the controller, Disable IBS to recevie dump
1062d841502cSBalakrishna Godavarthi 			 * with out any interruption, ideally time required for
1063d841502cSBalakrishna Godavarthi 			 * the controller to send the dump is 8 seconds. let us
1064d841502cSBalakrishna Godavarthi 			 * start timer to handle this asynchronous activity.
1065d841502cSBalakrishna Godavarthi 			 */
10662be43abaSVenkata Lakshmi Narayana Gubba 			set_bit(QCA_IBS_DISABLED, &qca->flags);
1067d841502cSBalakrishna Godavarthi 			set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
1068d841502cSBalakrishna Godavarthi 			dump = (void *) skb->data;
106906d3fdfcSSai Teja Aluvala 			qca_memdump->ram_dump_size = __le32_to_cpu(dump->dump_size);
107006d3fdfcSSai Teja Aluvala 			if (!(qca_memdump->ram_dump_size)) {
1071d841502cSBalakrishna Godavarthi 				bt_dev_err(hu->hdev, "Rx invalid memdump size");
107271f8e707SDinghao Liu 				kfree(qca_memdump);
1073d841502cSBalakrishna Godavarthi 				kfree_skb(skb);
107406d3fdfcSSai Teja Aluvala 				mutex_unlock(&qca->hci_memdump_lock);
107506d3fdfcSSai Teja Aluvala 				return;
107606d3fdfcSSai Teja Aluvala 			}
107706d3fdfcSSai Teja Aluvala 
107806d3fdfcSSai Teja Aluvala 			queue_delayed_work(qca->workqueue,
107906d3fdfcSSai Teja Aluvala 					   &qca->ctrl_memdump_timeout,
108006d3fdfcSSai Teja Aluvala 					   msecs_to_jiffies(MEMDUMP_TIMEOUT_MS));
108106d3fdfcSSai Teja Aluvala 			skb_pull(skb, sizeof(qca_memdump->ram_dump_size));
108206d3fdfcSSai Teja Aluvala 			qca_memdump->current_seq_no = 0;
108306d3fdfcSSai Teja Aluvala 			qca_memdump->received_dump = 0;
108406d3fdfcSSai Teja Aluvala 			ret = hci_devcd_init(hu->hdev, qca_memdump->ram_dump_size);
108506d3fdfcSSai Teja Aluvala 			bt_dev_info(hu->hdev, "hci_devcd_init Return:%d",
108606d3fdfcSSai Teja Aluvala 				    ret);
108706d3fdfcSSai Teja Aluvala 			if (ret < 0) {
108806d3fdfcSSai Teja Aluvala 				kfree(qca->qca_memdump);
108971f8e707SDinghao Liu 				qca->qca_memdump = NULL;
109006d3fdfcSSai Teja Aluvala 				qca->memdump_state = QCA_MEMDUMP_COLLECTED;
109106d3fdfcSSai Teja Aluvala 				cancel_delayed_work(&qca->ctrl_memdump_timeout);
109206d3fdfcSSai Teja Aluvala 				clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
1093*a22cbf1eSDouglas Anderson 				clear_bit(QCA_IBS_DISABLED, &qca->flags);
10947c2c3e63SVenkata Lakshmi Narayana Gubba 				mutex_unlock(&qca->hci_memdump_lock);
1095d841502cSBalakrishna Godavarthi 				return;
1096d841502cSBalakrishna Godavarthi 			}
1097d841502cSBalakrishna Godavarthi 
1098d841502cSBalakrishna Godavarthi 			bt_dev_info(hu->hdev, "QCA collecting dump of size:%u",
109906d3fdfcSSai Teja Aluvala 				    qca_memdump->ram_dump_size);
1100d841502cSBalakrishna Godavarthi 
1101d841502cSBalakrishna Godavarthi 		}
1102d841502cSBalakrishna Godavarthi 
1103d841502cSBalakrishna Godavarthi 		/* If sequence no 0 is missed then there is no point in
1104d841502cSBalakrishna Godavarthi 		 * accepting the other sequences.
1105d841502cSBalakrishna Godavarthi 		 */
110606d3fdfcSSai Teja Aluvala 		if (!test_bit(QCA_MEMDUMP_COLLECTION, &qca->flags)) {
1107d841502cSBalakrishna Godavarthi 			bt_dev_err(hu->hdev, "QCA: Discarding other packets");
1108d841502cSBalakrishna Godavarthi 			kfree(qca_memdump);
1109d841502cSBalakrishna Godavarthi 			kfree_skb(skb);
11107c2c3e63SVenkata Lakshmi Narayana Gubba 			mutex_unlock(&qca->hci_memdump_lock);
1111d841502cSBalakrishna Godavarthi 			return;
1112d841502cSBalakrishna Godavarthi 		}
1113d841502cSBalakrishna Godavarthi 		/* There could be chance of missing some packets from
1114d841502cSBalakrishna Godavarthi 		 * the controller. In such cases let us store the dummy
1115d841502cSBalakrishna Godavarthi 		 * packets in the buffer.
1116d841502cSBalakrishna Godavarthi 		 */
1117e5aeebddSZijun Hu 		/* For QCA6390, controller does not lost packets but
111807528783SBhaskar Chowdhury 		 * sequence number field of packet sometimes has error
1119e5aeebddSZijun Hu 		 * bits, so skip this checking for missing packet.
1120e5aeebddSZijun Hu 		 */
1121d841502cSBalakrishna Godavarthi 		while ((seq_no > qca_memdump->current_seq_no + 1) &&
1122e5aeebddSZijun Hu 			(soc_type != QCA_QCA6390) &&
1123d841502cSBalakrishna Godavarthi 			seq_no != QCA_LAST_SEQUENCE_NUM) {
1124d841502cSBalakrishna Godavarthi 			bt_dev_err(hu->hdev, "QCA controller missed packet:%d",
1125d841502cSBalakrishna Godavarthi 				   qca_memdump->current_seq_no);
1126e5aeebddSZijun Hu 			rx_size = qca_memdump->received_dump;
1127e5aeebddSZijun Hu 			rx_size += QCA_DUMP_PACKET_SIZE;
1128e5aeebddSZijun Hu 			if (rx_size > qca_memdump->ram_dump_size) {
1129e5aeebddSZijun Hu 				bt_dev_err(hu->hdev,
1130e5aeebddSZijun Hu 					   "QCA memdump received %d, no space for missed packet",
1131e5aeebddSZijun Hu 					   qca_memdump->received_dump);
1132e5aeebddSZijun Hu 				break;
1133e5aeebddSZijun Hu 			}
113406d3fdfcSSai Teja Aluvala 			hci_devcd_append_pattern(hu->hdev, 0x00,
113506d3fdfcSSai Teja Aluvala 				QCA_DUMP_PACKET_SIZE);
1136d841502cSBalakrishna Godavarthi 			qca_memdump->received_dump += QCA_DUMP_PACKET_SIZE;
1137d841502cSBalakrishna Godavarthi 			qca_memdump->current_seq_no++;
1138d841502cSBalakrishna Godavarthi 		}
1139d841502cSBalakrishna Godavarthi 
1140e5aeebddSZijun Hu 		rx_size = qca_memdump->received_dump  + skb->len;
1141e5aeebddSZijun Hu 		if (rx_size <= qca_memdump->ram_dump_size) {
1142e5aeebddSZijun Hu 			if ((seq_no != QCA_LAST_SEQUENCE_NUM) &&
114306d3fdfcSSai Teja Aluvala 			    (seq_no != qca_memdump->current_seq_no)) {
1144e5aeebddSZijun Hu 				bt_dev_err(hu->hdev,
1145e5aeebddSZijun Hu 					   "QCA memdump unexpected packet %d",
1146e5aeebddSZijun Hu 					   seq_no);
114706d3fdfcSSai Teja Aluvala 			}
1148e5aeebddSZijun Hu 			bt_dev_dbg(hu->hdev,
1149e5aeebddSZijun Hu 				   "QCA memdump packet %d with length %d",
1150e5aeebddSZijun Hu 				   seq_no, skb->len);
115106d3fdfcSSai Teja Aluvala 			hci_devcd_append(hu->hdev, skb);
115206d3fdfcSSai Teja Aluvala 			qca_memdump->current_seq_no += 1;
115306d3fdfcSSai Teja Aluvala 			qca_memdump->received_dump = rx_size;
1154e5aeebddSZijun Hu 		} else {
1155e5aeebddSZijun Hu 			bt_dev_err(hu->hdev,
115606d3fdfcSSai Teja Aluvala 				   "QCA memdump received no space for packet %d",
115706d3fdfcSSai Teja Aluvala 				    qca_memdump->current_seq_no);
1158e5aeebddSZijun Hu 		}
115906d3fdfcSSai Teja Aluvala 
1160d841502cSBalakrishna Godavarthi 		if (seq_no == QCA_LAST_SEQUENCE_NUM) {
1161e5aeebddSZijun Hu 			bt_dev_info(hu->hdev,
1162e5aeebddSZijun Hu 				"QCA memdump Done, received %d, total %d",
1163e5aeebddSZijun Hu 				qca_memdump->received_dump,
1164e5aeebddSZijun Hu 				qca_memdump->ram_dump_size);
116506d3fdfcSSai Teja Aluvala 			hci_devcd_complete(hu->hdev);
11667c2c3e63SVenkata Lakshmi Narayana Gubba 			cancel_delayed_work(&qca->ctrl_memdump_timeout);
1167d841502cSBalakrishna Godavarthi 			kfree(qca->qca_memdump);
1168d841502cSBalakrishna Godavarthi 			qca->qca_memdump = NULL;
1169d841502cSBalakrishna Godavarthi 			qca->memdump_state = QCA_MEMDUMP_COLLECTED;
11707c2c3e63SVenkata Lakshmi Narayana Gubba 			clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
1171d841502cSBalakrishna Godavarthi 		}
11727c2c3e63SVenkata Lakshmi Narayana Gubba 
11737c2c3e63SVenkata Lakshmi Narayana Gubba 		mutex_unlock(&qca->hci_memdump_lock);
1174d841502cSBalakrishna Godavarthi 	}
1175d841502cSBalakrishna Godavarthi 
1176d841502cSBalakrishna Godavarthi }
1177d841502cSBalakrishna Godavarthi 
qca_controller_memdump_event(struct hci_dev * hdev,struct sk_buff * skb)11787c2c3e63SVenkata Lakshmi Narayana Gubba static int qca_controller_memdump_event(struct hci_dev *hdev,
11797c2c3e63SVenkata Lakshmi Narayana Gubba 					struct sk_buff *skb)
1180d841502cSBalakrishna Godavarthi {
1181d841502cSBalakrishna Godavarthi 	struct hci_uart *hu = hci_get_drvdata(hdev);
1182d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
1183d841502cSBalakrishna Godavarthi 
11843344537fSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_SSR_TRIGGERED, &qca->flags);
1185d841502cSBalakrishna Godavarthi 	skb_queue_tail(&qca->rx_memdump_q, skb);
1186d841502cSBalakrishna Godavarthi 	queue_work(qca->workqueue, &qca->ctrl_memdump_evt);
1187d841502cSBalakrishna Godavarthi 
1188d841502cSBalakrishna Godavarthi 	return 0;
1189d841502cSBalakrishna Godavarthi }
1190d841502cSBalakrishna Godavarthi 
qca_recv_event(struct hci_dev * hdev,struct sk_buff * skb)11912faa3f15SMatthias Kaehlcke static int qca_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
11922faa3f15SMatthias Kaehlcke {
11932faa3f15SMatthias Kaehlcke 	struct hci_uart *hu = hci_get_drvdata(hdev);
11942faa3f15SMatthias Kaehlcke 	struct qca_data *qca = hu->priv;
11952faa3f15SMatthias Kaehlcke 
11962faa3f15SMatthias Kaehlcke 	if (test_bit(QCA_DROP_VENDOR_EVENT, &qca->flags)) {
11972faa3f15SMatthias Kaehlcke 		struct hci_event_hdr *hdr = (void *)skb->data;
11982faa3f15SMatthias Kaehlcke 
11992faa3f15SMatthias Kaehlcke 		/* For the WCN3990 the vendor command for a baudrate change
12002faa3f15SMatthias Kaehlcke 		 * isn't sent as synchronous HCI command, because the
12012faa3f15SMatthias Kaehlcke 		 * controller sends the corresponding vendor event with the
12022faa3f15SMatthias Kaehlcke 		 * new baudrate. The event is received and properly decoded
12032faa3f15SMatthias Kaehlcke 		 * after changing the baudrate of the host port. It needs to
12042faa3f15SMatthias Kaehlcke 		 * be dropped, otherwise it can be misinterpreted as
12052faa3f15SMatthias Kaehlcke 		 * response to a later firmware download command (also a
12062faa3f15SMatthias Kaehlcke 		 * vendor command).
12072faa3f15SMatthias Kaehlcke 		 */
12082faa3f15SMatthias Kaehlcke 
12092faa3f15SMatthias Kaehlcke 		if (hdr->evt == HCI_EV_VENDOR)
12102faa3f15SMatthias Kaehlcke 			complete(&qca->drop_ev_comp);
12112faa3f15SMatthias Kaehlcke 
12124974c839SWei Yongjun 		kfree_skb(skb);
12132faa3f15SMatthias Kaehlcke 
12142faa3f15SMatthias Kaehlcke 		return 0;
12152faa3f15SMatthias Kaehlcke 	}
1216d841502cSBalakrishna Godavarthi 	/* We receive chip memory dump as an event packet, With a dedicated
1217d841502cSBalakrishna Godavarthi 	 * handler followed by a hardware error event. When this event is
1218d841502cSBalakrishna Godavarthi 	 * received we store dump into a file before closing hci. This
1219d841502cSBalakrishna Godavarthi 	 * dump will help in triaging the issues.
1220d841502cSBalakrishna Godavarthi 	 */
1221d841502cSBalakrishna Godavarthi 	if ((skb->data[0] == HCI_VENDOR_PKT) &&
1222d841502cSBalakrishna Godavarthi 	    (get_unaligned_be16(skb->data + 2) == QCA_SSR_DUMP_HANDLE))
1223d841502cSBalakrishna Godavarthi 		return qca_controller_memdump_event(hdev, skb);
12242faa3f15SMatthias Kaehlcke 
12252faa3f15SMatthias Kaehlcke 	return hci_recv_frame(hdev, skb);
12262faa3f15SMatthias Kaehlcke }
12272faa3f15SMatthias Kaehlcke 
12280ff252c1SBen Young Tae Kim #define QCA_IBS_SLEEP_IND_EVENT \
12290ff252c1SBen Young Tae Kim 	.type = HCI_IBS_SLEEP_IND, \
12300ff252c1SBen Young Tae Kim 	.hlen = 0, \
12310ff252c1SBen Young Tae Kim 	.loff = 0, \
12320ff252c1SBen Young Tae Kim 	.lsize = 0, \
12330ff252c1SBen Young Tae Kim 	.maxlen = HCI_MAX_IBS_SIZE
12340ff252c1SBen Young Tae Kim 
12350ff252c1SBen Young Tae Kim #define QCA_IBS_WAKE_IND_EVENT \
12360ff252c1SBen Young Tae Kim 	.type = HCI_IBS_WAKE_IND, \
12370ff252c1SBen Young Tae Kim 	.hlen = 0, \
12380ff252c1SBen Young Tae Kim 	.loff = 0, \
12390ff252c1SBen Young Tae Kim 	.lsize = 0, \
12400ff252c1SBen Young Tae Kim 	.maxlen = HCI_MAX_IBS_SIZE
12410ff252c1SBen Young Tae Kim 
12420ff252c1SBen Young Tae Kim #define QCA_IBS_WAKE_ACK_EVENT \
12430ff252c1SBen Young Tae Kim 	.type = HCI_IBS_WAKE_ACK, \
12440ff252c1SBen Young Tae Kim 	.hlen = 0, \
12450ff252c1SBen Young Tae Kim 	.loff = 0, \
12460ff252c1SBen Young Tae Kim 	.lsize = 0, \
12470ff252c1SBen Young Tae Kim 	.maxlen = HCI_MAX_IBS_SIZE
12480ff252c1SBen Young Tae Kim 
12490ff252c1SBen Young Tae Kim static const struct h4_recv_pkt qca_recv_pkts[] = {
1250c614ca3fSBalakrishna Godavarthi 	{ H4_RECV_ACL,             .recv = qca_recv_acl_data },
12510ff252c1SBen Young Tae Kim 	{ H4_RECV_SCO,             .recv = hci_recv_frame    },
12522faa3f15SMatthias Kaehlcke 	{ H4_RECV_EVENT,           .recv = qca_recv_event    },
12530ff252c1SBen Young Tae Kim 	{ QCA_IBS_WAKE_IND_EVENT,  .recv = qca_ibs_wake_ind  },
12540ff252c1SBen Young Tae Kim 	{ QCA_IBS_WAKE_ACK_EVENT,  .recv = qca_ibs_wake_ack  },
12550ff252c1SBen Young Tae Kim 	{ QCA_IBS_SLEEP_IND_EVENT, .recv = qca_ibs_sleep_ind },
12560ff252c1SBen Young Tae Kim };
12570ff252c1SBen Young Tae Kim 
qca_recv(struct hci_uart * hu,const void * data,int count)12580ff252c1SBen Young Tae Kim static int qca_recv(struct hci_uart *hu, const void *data, int count)
12590ff252c1SBen Young Tae Kim {
12600ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
12610ff252c1SBen Young Tae Kim 
12620ff252c1SBen Young Tae Kim 	if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
12630ff252c1SBen Young Tae Kim 		return -EUNATCH;
12640ff252c1SBen Young Tae Kim 
12650ff252c1SBen Young Tae Kim 	qca->rx_skb = h4_recv_buf(hu->hdev, qca->rx_skb, data, count,
12660ff252c1SBen Young Tae Kim 				  qca_recv_pkts, ARRAY_SIZE(qca_recv_pkts));
12670ff252c1SBen Young Tae Kim 	if (IS_ERR(qca->rx_skb)) {
12680ff252c1SBen Young Tae Kim 		int err = PTR_ERR(qca->rx_skb);
12692064ee33SMarcel Holtmann 		bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
12700ff252c1SBen Young Tae Kim 		qca->rx_skb = NULL;
12710ff252c1SBen Young Tae Kim 		return err;
12720ff252c1SBen Young Tae Kim 	}
12730ff252c1SBen Young Tae Kim 
12740ff252c1SBen Young Tae Kim 	return count;
12750ff252c1SBen Young Tae Kim }
12760ff252c1SBen Young Tae Kim 
qca_dequeue(struct hci_uart * hu)12770ff252c1SBen Young Tae Kim static struct sk_buff *qca_dequeue(struct hci_uart *hu)
12780ff252c1SBen Young Tae Kim {
12790ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
12800ff252c1SBen Young Tae Kim 
12810ff252c1SBen Young Tae Kim 	return skb_dequeue(&qca->txq);
12820ff252c1SBen Young Tae Kim }
12830ff252c1SBen Young Tae Kim 
qca_get_baudrate_value(int speed)12840ff252c1SBen Young Tae Kim static uint8_t qca_get_baudrate_value(int speed)
12850ff252c1SBen Young Tae Kim {
12860ff252c1SBen Young Tae Kim 	switch (speed) {
12870ff252c1SBen Young Tae Kim 	case 9600:
12880ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_9600;
12890ff252c1SBen Young Tae Kim 	case 19200:
12900ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_19200;
12910ff252c1SBen Young Tae Kim 	case 38400:
12920ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_38400;
12930ff252c1SBen Young Tae Kim 	case 57600:
12940ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_57600;
12950ff252c1SBen Young Tae Kim 	case 115200:
12960ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_115200;
12970ff252c1SBen Young Tae Kim 	case 230400:
12980ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_230400;
12990ff252c1SBen Young Tae Kim 	case 460800:
13000ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_460800;
13010ff252c1SBen Young Tae Kim 	case 500000:
13020ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_500000;
13030ff252c1SBen Young Tae Kim 	case 921600:
13040ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_921600;
13050ff252c1SBen Young Tae Kim 	case 1000000:
13060ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_1000000;
13070ff252c1SBen Young Tae Kim 	case 2000000:
13080ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_2000000;
13090ff252c1SBen Young Tae Kim 	case 3000000:
13100ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_3000000;
1311be93a497SBalakrishna Godavarthi 	case 3200000:
1312be93a497SBalakrishna Godavarthi 		return QCA_BAUDRATE_3200000;
13130ff252c1SBen Young Tae Kim 	case 3500000:
13140ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_3500000;
13150ff252c1SBen Young Tae Kim 	default:
13160ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_115200;
13170ff252c1SBen Young Tae Kim 	}
13180ff252c1SBen Young Tae Kim }
13190ff252c1SBen Young Tae Kim 
qca_set_baudrate(struct hci_dev * hdev,uint8_t baudrate)13200ff252c1SBen Young Tae Kim static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
13210ff252c1SBen Young Tae Kim {
13220ff252c1SBen Young Tae Kim 	struct hci_uart *hu = hci_get_drvdata(hdev);
13230ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
13240ff252c1SBen Young Tae Kim 	struct sk_buff *skb;
13250ff252c1SBen Young Tae Kim 	u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
13260ff252c1SBen Young Tae Kim 
1327be93a497SBalakrishna Godavarthi 	if (baudrate > QCA_BAUDRATE_3200000)
13280ff252c1SBen Young Tae Kim 		return -EINVAL;
13290ff252c1SBen Young Tae Kim 
13300ff252c1SBen Young Tae Kim 	cmd[4] = baudrate;
13310ff252c1SBen Young Tae Kim 
133225a13e38SJia-Ju Bai 	skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
13330ff252c1SBen Young Tae Kim 	if (!skb) {
13342064ee33SMarcel Holtmann 		bt_dev_err(hdev, "Failed to allocate baudrate packet");
13350ff252c1SBen Young Tae Kim 		return -ENOMEM;
13360ff252c1SBen Young Tae Kim 	}
13370ff252c1SBen Young Tae Kim 
13380ff252c1SBen Young Tae Kim 	/* Assign commands to change baudrate and packet type. */
133959ae1d12SJohannes Berg 	skb_put_data(skb, cmd, sizeof(cmd));
1340618e8bc2SMarcel Holtmann 	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
13410ff252c1SBen Young Tae Kim 
13420ff252c1SBen Young Tae Kim 	skb_queue_tail(&qca->txq, skb);
13430ff252c1SBen Young Tae Kim 	hci_uart_tx_wakeup(hu);
13440ff252c1SBen Young Tae Kim 
134594d66714SMatthias Kaehlcke 	/* Wait for the baudrate change request to be sent */
134694d66714SMatthias Kaehlcke 
134794d66714SMatthias Kaehlcke 	while (!skb_queue_empty(&qca->txq))
134894d66714SMatthias Kaehlcke 		usleep_range(100, 200);
134994d66714SMatthias Kaehlcke 
1350ecf2b768SMatthias Kaehlcke 	if (hu->serdev)
135194d66714SMatthias Kaehlcke 		serdev_device_wait_until_sent(hu->serdev,
135294d66714SMatthias Kaehlcke 		      msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
135394d66714SMatthias Kaehlcke 
135494d66714SMatthias Kaehlcke 	/* Give the controller time to process the request */
1355691d54d0SNeil Armstrong 	switch (qca_soc_type(hu)) {
1356691d54d0SNeil Armstrong 	case QCA_WCN3988:
1357691d54d0SNeil Armstrong 	case QCA_WCN3990:
1358691d54d0SNeil Armstrong 	case QCA_WCN3991:
1359691d54d0SNeil Armstrong 	case QCA_WCN3998:
1360691d54d0SNeil Armstrong 	case QCA_WCN6750:
1361691d54d0SNeil Armstrong 	case QCA_WCN6855:
1362e0c1278aSNeil Armstrong 	case QCA_WCN7850:
136399719449SNigel Christian 		usleep_range(1000, 10000);
1364691d54d0SNeil Armstrong 		break;
1365691d54d0SNeil Armstrong 
1366691d54d0SNeil Armstrong 	default:
136794d66714SMatthias Kaehlcke 		msleep(300);
1368691d54d0SNeil Armstrong 	}
13690ff252c1SBen Young Tae Kim 
13700ff252c1SBen Young Tae Kim 	return 0;
13710ff252c1SBen Young Tae Kim }
13720ff252c1SBen Young Tae Kim 
host_set_baudrate(struct hci_uart * hu,unsigned int speed)137305ba533cSThierry Escande static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed)
137405ba533cSThierry Escande {
137505ba533cSThierry Escande 	if (hu->serdev)
137605ba533cSThierry Escande 		serdev_device_set_baudrate(hu->serdev, speed);
137705ba533cSThierry Escande 	else
137805ba533cSThierry Escande 		hci_uart_set_baudrate(hu, speed);
137905ba533cSThierry Escande }
138005ba533cSThierry Escande 
qca_send_power_pulse(struct hci_uart * hu,bool on)13819836b802SMatthias Kaehlcke static int qca_send_power_pulse(struct hci_uart *hu, bool on)
1382fa9ad876SBalakrishna Godavarthi {
1383f9558270SBalakrishna Godavarthi 	int ret;
138494d66714SMatthias Kaehlcke 	int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
13859836b802SMatthias Kaehlcke 	u8 cmd = on ? QCA_WCN3990_POWERON_PULSE : QCA_WCN3990_POWEROFF_PULSE;
1386fa9ad876SBalakrishna Godavarthi 
1387fa9ad876SBalakrishna Godavarthi 	/* These power pulses are single byte command which are sent
1388fa9ad876SBalakrishna Godavarthi 	 * at required baudrate to wcn3990. On wcn3990, we have an external
1389fa9ad876SBalakrishna Godavarthi 	 * circuit at Tx pin which decodes the pulse sent at specific baudrate.
1390fa9ad876SBalakrishna Godavarthi 	 * For example, wcn3990 supports RF COEX antenna for both Wi-Fi/BT
1391fa9ad876SBalakrishna Godavarthi 	 * and also we use the same power inputs to turn on and off for
1392fa9ad876SBalakrishna Godavarthi 	 * Wi-Fi/BT. Powering up the power sources will not enable BT, until
1393fa9ad876SBalakrishna Godavarthi 	 * we send a power on pulse at 115200 bps. This algorithm will help to
1394fa9ad876SBalakrishna Godavarthi 	 * save power. Disabling hardware flow control is mandatory while
1395fa9ad876SBalakrishna Godavarthi 	 * sending power pulses to SoC.
1396fa9ad876SBalakrishna Godavarthi 	 */
1397f9558270SBalakrishna Godavarthi 	bt_dev_dbg(hu->hdev, "sending power pulse %02x to controller", cmd);
1398fa9ad876SBalakrishna Godavarthi 
1399f9558270SBalakrishna Godavarthi 	serdev_device_write_flush(hu->serdev);
1400fa9ad876SBalakrishna Godavarthi 	hci_uart_set_flow_control(hu, true);
1401f9558270SBalakrishna Godavarthi 	ret = serdev_device_write_buf(hu->serdev, &cmd, sizeof(cmd));
1402f9558270SBalakrishna Godavarthi 	if (ret < 0) {
1403f9558270SBalakrishna Godavarthi 		bt_dev_err(hu->hdev, "failed to send power pulse %02x", cmd);
1404f9558270SBalakrishna Godavarthi 		return ret;
1405f9558270SBalakrishna Godavarthi 	}
1406fa9ad876SBalakrishna Godavarthi 
1407f9558270SBalakrishna Godavarthi 	serdev_device_wait_until_sent(hu->serdev, timeout);
1408fa9ad876SBalakrishna Godavarthi 	hci_uart_set_flow_control(hu, false);
1409fa9ad876SBalakrishna Godavarthi 
14100ebcddd8SMatthias Kaehlcke 	/* Give to controller time to boot/shutdown */
1411ad571d72SMatthias Kaehlcke 	if (on)
1412ad571d72SMatthias Kaehlcke 		msleep(100);
14130ebcddd8SMatthias Kaehlcke 	else
141499719449SNigel Christian 		usleep_range(1000, 10000);
1415ad571d72SMatthias Kaehlcke 
1416fa9ad876SBalakrishna Godavarthi 	return 0;
1417fa9ad876SBalakrishna Godavarthi }
1418fa9ad876SBalakrishna Godavarthi 
qca_get_speed(struct hci_uart * hu,enum qca_speed_type speed_type)141983d9c5e5SBalakrishna Godavarthi static unsigned int qca_get_speed(struct hci_uart *hu,
142083d9c5e5SBalakrishna Godavarthi 				  enum qca_speed_type speed_type)
142183d9c5e5SBalakrishna Godavarthi {
142283d9c5e5SBalakrishna Godavarthi 	unsigned int speed = 0;
142383d9c5e5SBalakrishna Godavarthi 
142483d9c5e5SBalakrishna Godavarthi 	if (speed_type == QCA_INIT_SPEED) {
142583d9c5e5SBalakrishna Godavarthi 		if (hu->init_speed)
142683d9c5e5SBalakrishna Godavarthi 			speed = hu->init_speed;
142783d9c5e5SBalakrishna Godavarthi 		else if (hu->proto->init_speed)
142883d9c5e5SBalakrishna Godavarthi 			speed = hu->proto->init_speed;
142983d9c5e5SBalakrishna Godavarthi 	} else {
143083d9c5e5SBalakrishna Godavarthi 		if (hu->oper_speed)
143183d9c5e5SBalakrishna Godavarthi 			speed = hu->oper_speed;
143283d9c5e5SBalakrishna Godavarthi 		else if (hu->proto->oper_speed)
143383d9c5e5SBalakrishna Godavarthi 			speed = hu->proto->oper_speed;
143483d9c5e5SBalakrishna Godavarthi 	}
143583d9c5e5SBalakrishna Godavarthi 
143683d9c5e5SBalakrishna Godavarthi 	return speed;
143783d9c5e5SBalakrishna Godavarthi }
143883d9c5e5SBalakrishna Godavarthi 
qca_check_speeds(struct hci_uart * hu)143983d9c5e5SBalakrishna Godavarthi static int qca_check_speeds(struct hci_uart *hu)
144083d9c5e5SBalakrishna Godavarthi {
1441691d54d0SNeil Armstrong 	switch (qca_soc_type(hu)) {
1442691d54d0SNeil Armstrong 	case QCA_WCN3988:
1443691d54d0SNeil Armstrong 	case QCA_WCN3990:
1444691d54d0SNeil Armstrong 	case QCA_WCN3991:
1445691d54d0SNeil Armstrong 	case QCA_WCN3998:
1446691d54d0SNeil Armstrong 	case QCA_WCN6750:
1447691d54d0SNeil Armstrong 	case QCA_WCN6855:
1448e0c1278aSNeil Armstrong 	case QCA_WCN7850:
1449fa9ad876SBalakrishna Godavarthi 		if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
1450fa9ad876SBalakrishna Godavarthi 		    !qca_get_speed(hu, QCA_OPER_SPEED))
1451fa9ad876SBalakrishna Godavarthi 			return -EINVAL;
1452691d54d0SNeil Armstrong 		break;
1453691d54d0SNeil Armstrong 
1454691d54d0SNeil Armstrong 	default:
145583d9c5e5SBalakrishna Godavarthi 		if (!qca_get_speed(hu, QCA_INIT_SPEED) ||
145683d9c5e5SBalakrishna Godavarthi 		    !qca_get_speed(hu, QCA_OPER_SPEED))
145783d9c5e5SBalakrishna Godavarthi 			return -EINVAL;
1458fa9ad876SBalakrishna Godavarthi 	}
145983d9c5e5SBalakrishna Godavarthi 
146083d9c5e5SBalakrishna Godavarthi 	return 0;
146183d9c5e5SBalakrishna Godavarthi }
146283d9c5e5SBalakrishna Godavarthi 
qca_set_speed(struct hci_uart * hu,enum qca_speed_type speed_type)146383d9c5e5SBalakrishna Godavarthi static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
146483d9c5e5SBalakrishna Godavarthi {
146583d9c5e5SBalakrishna Godavarthi 	unsigned int speed, qca_baudrate;
14662faa3f15SMatthias Kaehlcke 	struct qca_data *qca = hu->priv;
146778e8fa29SBalakrishna Godavarthi 	int ret = 0;
146883d9c5e5SBalakrishna Godavarthi 
146983d9c5e5SBalakrishna Godavarthi 	if (speed_type == QCA_INIT_SPEED) {
147083d9c5e5SBalakrishna Godavarthi 		speed = qca_get_speed(hu, QCA_INIT_SPEED);
147183d9c5e5SBalakrishna Godavarthi 		if (speed)
147283d9c5e5SBalakrishna Godavarthi 			host_set_baudrate(hu, speed);
147383d9c5e5SBalakrishna Godavarthi 	} else {
14744fdd5a4fSMatthias Kaehlcke 		enum qca_btsoc_type soc_type = qca_soc_type(hu);
14754fdd5a4fSMatthias Kaehlcke 
147683d9c5e5SBalakrishna Godavarthi 		speed = qca_get_speed(hu, QCA_OPER_SPEED);
147783d9c5e5SBalakrishna Godavarthi 		if (!speed)
147883d9c5e5SBalakrishna Godavarthi 			return 0;
147983d9c5e5SBalakrishna Godavarthi 
148078e8fa29SBalakrishna Godavarthi 		/* Disable flow control for wcn3990 to deassert RTS while
148178e8fa29SBalakrishna Godavarthi 		 * changing the baudrate of chip and host.
148278e8fa29SBalakrishna Godavarthi 		 */
1483691d54d0SNeil Armstrong 		switch (soc_type) {
1484691d54d0SNeil Armstrong 		case QCA_WCN3988:
1485691d54d0SNeil Armstrong 		case QCA_WCN3990:
1486691d54d0SNeil Armstrong 		case QCA_WCN3991:
1487691d54d0SNeil Armstrong 		case QCA_WCN3998:
1488691d54d0SNeil Armstrong 		case QCA_WCN6750:
1489691d54d0SNeil Armstrong 		case QCA_WCN6855:
1490e0c1278aSNeil Armstrong 		case QCA_WCN7850:
149178e8fa29SBalakrishna Godavarthi 			hci_uart_set_flow_control(hu, true);
1492691d54d0SNeil Armstrong 			break;
149378e8fa29SBalakrishna Godavarthi 
1494691d54d0SNeil Armstrong 		default:
1495691d54d0SNeil Armstrong 			break;
1496691d54d0SNeil Armstrong 		}
1497691d54d0SNeil Armstrong 
1498691d54d0SNeil Armstrong 		switch (soc_type) {
1499691d54d0SNeil Armstrong 		case QCA_WCN3990:
15002faa3f15SMatthias Kaehlcke 			reinit_completion(&qca->drop_ev_comp);
15012faa3f15SMatthias Kaehlcke 			set_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
1502691d54d0SNeil Armstrong 			break;
1503691d54d0SNeil Armstrong 
1504691d54d0SNeil Armstrong 		default:
1505691d54d0SNeil Armstrong 			break;
15062faa3f15SMatthias Kaehlcke 		}
15072faa3f15SMatthias Kaehlcke 
150883d9c5e5SBalakrishna Godavarthi 		qca_baudrate = qca_get_baudrate_value(speed);
1509fa9ad876SBalakrishna Godavarthi 		bt_dev_dbg(hu->hdev, "Set UART speed to %d", speed);
151083d9c5e5SBalakrishna Godavarthi 		ret = qca_set_baudrate(hu->hdev, qca_baudrate);
151183d9c5e5SBalakrishna Godavarthi 		if (ret)
151278e8fa29SBalakrishna Godavarthi 			goto error;
151383d9c5e5SBalakrishna Godavarthi 
151483d9c5e5SBalakrishna Godavarthi 		host_set_baudrate(hu, speed);
151578e8fa29SBalakrishna Godavarthi 
151678e8fa29SBalakrishna Godavarthi error:
1517691d54d0SNeil Armstrong 		switch (soc_type) {
1518691d54d0SNeil Armstrong 		case QCA_WCN3988:
1519691d54d0SNeil Armstrong 		case QCA_WCN3990:
1520691d54d0SNeil Armstrong 		case QCA_WCN3991:
1521691d54d0SNeil Armstrong 		case QCA_WCN3998:
1522691d54d0SNeil Armstrong 		case QCA_WCN6750:
1523691d54d0SNeil Armstrong 		case QCA_WCN6855:
1524e0c1278aSNeil Armstrong 		case QCA_WCN7850:
152578e8fa29SBalakrishna Godavarthi 			hci_uart_set_flow_control(hu, false);
1526691d54d0SNeil Armstrong 			break;
15272faa3f15SMatthias Kaehlcke 
1528691d54d0SNeil Armstrong 		default:
1529691d54d0SNeil Armstrong 			break;
1530691d54d0SNeil Armstrong 		}
1531691d54d0SNeil Armstrong 
1532691d54d0SNeil Armstrong 		switch (soc_type) {
1533691d54d0SNeil Armstrong 		case QCA_WCN3990:
15342faa3f15SMatthias Kaehlcke 			/* Wait for the controller to send the vendor event
15352faa3f15SMatthias Kaehlcke 			 * for the baudrate change command.
15362faa3f15SMatthias Kaehlcke 			 */
15372faa3f15SMatthias Kaehlcke 			if (!wait_for_completion_timeout(&qca->drop_ev_comp,
15382faa3f15SMatthias Kaehlcke 						 msecs_to_jiffies(100))) {
15392faa3f15SMatthias Kaehlcke 				bt_dev_err(hu->hdev,
15402faa3f15SMatthias Kaehlcke 					   "Failed to change controller baudrate\n");
15412faa3f15SMatthias Kaehlcke 				ret = -ETIMEDOUT;
15422faa3f15SMatthias Kaehlcke 			}
15432faa3f15SMatthias Kaehlcke 
15442faa3f15SMatthias Kaehlcke 			clear_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
1545691d54d0SNeil Armstrong 			break;
1546691d54d0SNeil Armstrong 
1547691d54d0SNeil Armstrong 		default:
1548691d54d0SNeil Armstrong 			break;
15492faa3f15SMatthias Kaehlcke 		}
155083d9c5e5SBalakrishna Godavarthi 	}
155183d9c5e5SBalakrishna Godavarthi 
155278e8fa29SBalakrishna Godavarthi 	return ret;
155383d9c5e5SBalakrishna Godavarthi }
155483d9c5e5SBalakrishna Godavarthi 
qca_send_crashbuffer(struct hci_uart * hu)1555d841502cSBalakrishna Godavarthi static int qca_send_crashbuffer(struct hci_uart *hu)
1556d841502cSBalakrishna Godavarthi {
1557d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
1558d841502cSBalakrishna Godavarthi 	struct sk_buff *skb;
1559d841502cSBalakrishna Godavarthi 
1560d841502cSBalakrishna Godavarthi 	skb = bt_skb_alloc(QCA_CRASHBYTE_PACKET_LEN, GFP_KERNEL);
1561d841502cSBalakrishna Godavarthi 	if (!skb) {
1562d841502cSBalakrishna Godavarthi 		bt_dev_err(hu->hdev, "Failed to allocate memory for skb packet");
1563d841502cSBalakrishna Godavarthi 		return -ENOMEM;
1564d841502cSBalakrishna Godavarthi 	}
1565d841502cSBalakrishna Godavarthi 
1566d841502cSBalakrishna Godavarthi 	/* We forcefully crash the controller, by sending 0xfb byte for
1567d841502cSBalakrishna Godavarthi 	 * 1024 times. We also might have chance of losing data, To be
1568d841502cSBalakrishna Godavarthi 	 * on safer side we send 1096 bytes to the SoC.
1569d841502cSBalakrishna Godavarthi 	 */
1570d841502cSBalakrishna Godavarthi 	memset(skb_put(skb, QCA_CRASHBYTE_PACKET_LEN), QCA_MEMDUMP_BYTE,
1571d841502cSBalakrishna Godavarthi 	       QCA_CRASHBYTE_PACKET_LEN);
1572d841502cSBalakrishna Godavarthi 	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
1573d841502cSBalakrishna Godavarthi 	bt_dev_info(hu->hdev, "crash the soc to collect controller dump");
1574d841502cSBalakrishna Godavarthi 	skb_queue_tail(&qca->txq, skb);
1575d841502cSBalakrishna Godavarthi 	hci_uart_tx_wakeup(hu);
1576d841502cSBalakrishna Godavarthi 
1577d841502cSBalakrishna Godavarthi 	return 0;
1578d841502cSBalakrishna Godavarthi }
1579d841502cSBalakrishna Godavarthi 
qca_wait_for_dump_collection(struct hci_dev * hdev)1580d841502cSBalakrishna Godavarthi static void qca_wait_for_dump_collection(struct hci_dev *hdev)
1581d841502cSBalakrishna Godavarthi {
1582d841502cSBalakrishna Godavarthi 	struct hci_uart *hu = hci_get_drvdata(hdev);
1583d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
1584d841502cSBalakrishna Godavarthi 
1585d841502cSBalakrishna Godavarthi 	wait_on_bit_timeout(&qca->flags, QCA_MEMDUMP_COLLECTION,
1586d841502cSBalakrishna Godavarthi 			    TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT_MS);
1587d841502cSBalakrishna Godavarthi 
1588d841502cSBalakrishna Godavarthi 	clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
1589d841502cSBalakrishna Godavarthi }
1590d841502cSBalakrishna Godavarthi 
qca_hw_error(struct hci_dev * hdev,u8 code)1591d841502cSBalakrishna Godavarthi static void qca_hw_error(struct hci_dev *hdev, u8 code)
1592d841502cSBalakrishna Godavarthi {
1593d841502cSBalakrishna Godavarthi 	struct hci_uart *hu = hci_get_drvdata(hdev);
1594d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
1595d841502cSBalakrishna Godavarthi 
15963344537fSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_SSR_TRIGGERED, &qca->flags);
15977c2c3e63SVenkata Lakshmi Narayana Gubba 	set_bit(QCA_HW_ERROR_EVENT, &qca->flags);
1598d841502cSBalakrishna Godavarthi 	bt_dev_info(hdev, "mem_dump_status: %d", qca->memdump_state);
1599d841502cSBalakrishna Godavarthi 
1600d841502cSBalakrishna Godavarthi 	if (qca->memdump_state == QCA_MEMDUMP_IDLE) {
1601d841502cSBalakrishna Godavarthi 		/* If hardware error event received for other than QCA
1602d841502cSBalakrishna Godavarthi 		 * soc memory dump event, then we need to crash the SOC
1603d841502cSBalakrishna Godavarthi 		 * and wait here for 8 seconds to get the dump packets.
1604d841502cSBalakrishna Godavarthi 		 * This will block main thread to be on hold until we
1605d841502cSBalakrishna Godavarthi 		 * collect dump.
1606d841502cSBalakrishna Godavarthi 		 */
1607d841502cSBalakrishna Godavarthi 		set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
1608d841502cSBalakrishna Godavarthi 		qca_send_crashbuffer(hu);
1609d841502cSBalakrishna Godavarthi 		qca_wait_for_dump_collection(hdev);
1610d841502cSBalakrishna Godavarthi 	} else if (qca->memdump_state == QCA_MEMDUMP_COLLECTING) {
1611d841502cSBalakrishna Godavarthi 		/* Let us wait here until memory dump collected or
1612d841502cSBalakrishna Godavarthi 		 * memory dump timer expired.
1613d841502cSBalakrishna Godavarthi 		 */
1614d841502cSBalakrishna Godavarthi 		bt_dev_info(hdev, "waiting for dump to complete");
1615d841502cSBalakrishna Godavarthi 		qca_wait_for_dump_collection(hdev);
1616d841502cSBalakrishna Godavarthi 	}
16177c2c3e63SVenkata Lakshmi Narayana Gubba 
1618f98aa80fSVenkata Lakshmi Narayana Gubba 	mutex_lock(&qca->hci_memdump_lock);
16197c2c3e63SVenkata Lakshmi Narayana Gubba 	if (qca->memdump_state != QCA_MEMDUMP_COLLECTED) {
16207c2c3e63SVenkata Lakshmi Narayana Gubba 		bt_dev_err(hu->hdev, "clearing allocated memory due to memdump timeout");
162106d3fdfcSSai Teja Aluvala 		hci_devcd_abort(hu->hdev);
1622f98aa80fSVenkata Lakshmi Narayana Gubba 		if (qca->qca_memdump) {
1623f98aa80fSVenkata Lakshmi Narayana Gubba 			kfree(qca->qca_memdump);
16247c2c3e63SVenkata Lakshmi Narayana Gubba 			qca->qca_memdump = NULL;
1625f98aa80fSVenkata Lakshmi Narayana Gubba 		}
16267c2c3e63SVenkata Lakshmi Narayana Gubba 		qca->memdump_state = QCA_MEMDUMP_TIMEOUT;
16277c2c3e63SVenkata Lakshmi Narayana Gubba 		cancel_delayed_work(&qca->ctrl_memdump_timeout);
1628f98aa80fSVenkata Lakshmi Narayana Gubba 	}
16297c2c3e63SVenkata Lakshmi Narayana Gubba 	mutex_unlock(&qca->hci_memdump_lock);
1630f98aa80fSVenkata Lakshmi Narayana Gubba 
1631f98aa80fSVenkata Lakshmi Narayana Gubba 	if (qca->memdump_state == QCA_MEMDUMP_TIMEOUT ||
1632f98aa80fSVenkata Lakshmi Narayana Gubba 	    qca->memdump_state == QCA_MEMDUMP_COLLECTED) {
16337c2c3e63SVenkata Lakshmi Narayana Gubba 		cancel_work_sync(&qca->ctrl_memdump_evt);
1634f98aa80fSVenkata Lakshmi Narayana Gubba 		skb_queue_purge(&qca->rx_memdump_q);
16357c2c3e63SVenkata Lakshmi Narayana Gubba 	}
16367c2c3e63SVenkata Lakshmi Narayana Gubba 
16377c2c3e63SVenkata Lakshmi Narayana Gubba 	clear_bit(QCA_HW_ERROR_EVENT, &qca->flags);
1638d841502cSBalakrishna Godavarthi }
1639d841502cSBalakrishna Godavarthi 
qca_cmd_timeout(struct hci_dev * hdev)1640d841502cSBalakrishna Godavarthi static void qca_cmd_timeout(struct hci_dev *hdev)
1641d841502cSBalakrishna Godavarthi {
1642d841502cSBalakrishna Godavarthi 	struct hci_uart *hu = hci_get_drvdata(hdev);
1643d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
1644d841502cSBalakrishna Godavarthi 
16453344537fSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_SSR_TRIGGERED, &qca->flags);
16463344537fSVenkata Lakshmi Narayana Gubba 	if (qca->memdump_state == QCA_MEMDUMP_IDLE) {
16473344537fSVenkata Lakshmi Narayana Gubba 		set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
1648d841502cSBalakrishna Godavarthi 		qca_send_crashbuffer(hu);
16493344537fSVenkata Lakshmi Narayana Gubba 		qca_wait_for_dump_collection(hdev);
16503344537fSVenkata Lakshmi Narayana Gubba 	} else if (qca->memdump_state == QCA_MEMDUMP_COLLECTING) {
16513344537fSVenkata Lakshmi Narayana Gubba 		/* Let us wait here until memory dump collected or
16523344537fSVenkata Lakshmi Narayana Gubba 		 * memory dump timer expired.
16533344537fSVenkata Lakshmi Narayana Gubba 		 */
16543344537fSVenkata Lakshmi Narayana Gubba 		bt_dev_info(hdev, "waiting for dump to complete");
16553344537fSVenkata Lakshmi Narayana Gubba 		qca_wait_for_dump_collection(hdev);
16563344537fSVenkata Lakshmi Narayana Gubba 	}
16573344537fSVenkata Lakshmi Narayana Gubba 
16583344537fSVenkata Lakshmi Narayana Gubba 	mutex_lock(&qca->hci_memdump_lock);
16593344537fSVenkata Lakshmi Narayana Gubba 	if (qca->memdump_state != QCA_MEMDUMP_COLLECTED) {
16603344537fSVenkata Lakshmi Narayana Gubba 		qca->memdump_state = QCA_MEMDUMP_TIMEOUT;
16613344537fSVenkata Lakshmi Narayana Gubba 		if (!test_bit(QCA_HW_ERROR_EVENT, &qca->flags)) {
16623344537fSVenkata Lakshmi Narayana Gubba 			/* Inject hw error event to reset the device
16633344537fSVenkata Lakshmi Narayana Gubba 			 * and driver.
16643344537fSVenkata Lakshmi Narayana Gubba 			 */
16653344537fSVenkata Lakshmi Narayana Gubba 			hci_reset_dev(hu->hdev);
16663344537fSVenkata Lakshmi Narayana Gubba 		}
16673344537fSVenkata Lakshmi Narayana Gubba 	}
16683344537fSVenkata Lakshmi Narayana Gubba 	mutex_unlock(&qca->hci_memdump_lock);
1669d841502cSBalakrishna Godavarthi }
1670d841502cSBalakrishna Godavarthi 
qca_wakeup(struct hci_dev * hdev)16714539ca67SLuiz Augusto von Dentz static bool qca_wakeup(struct hci_dev *hdev)
1672c1a74160SVenkata Lakshmi Narayana Gubba {
1673c1a74160SVenkata Lakshmi Narayana Gubba 	struct hci_uart *hu = hci_get_drvdata(hdev);
1674c1a74160SVenkata Lakshmi Narayana Gubba 	bool wakeup;
1675c1a74160SVenkata Lakshmi Narayana Gubba 
16766b47cdebSJohan Hovold 	if (!hu->serdev)
16776b47cdebSJohan Hovold 		return true;
16786b47cdebSJohan Hovold 
167903b0093fSZhengping Jiang 	/* BT SoC attached through the serial bus is handled by the serdev driver.
168003b0093fSZhengping Jiang 	 * So we need to use the device handle of the serdev driver to get the
168103b0093fSZhengping Jiang 	 * status of device may wakeup.
1682c1a74160SVenkata Lakshmi Narayana Gubba 	 */
168303b0093fSZhengping Jiang 	wakeup = device_may_wakeup(&hu->serdev->ctrl->dev);
1684c1a74160SVenkata Lakshmi Narayana Gubba 	bt_dev_dbg(hu->hdev, "wakeup status : %d", wakeup);
1685c1a74160SVenkata Lakshmi Narayana Gubba 
1686bde63e9eSSai Teja Aluvala 	return wakeup;
1687c1a74160SVenkata Lakshmi Narayana Gubba }
1688c1a74160SVenkata Lakshmi Narayana Gubba 
qca_regulator_init(struct hci_uart * hu)1689d8f97da1SVenkata Lakshmi Narayana Gubba static int qca_regulator_init(struct hci_uart *hu)
1690fa9ad876SBalakrishna Godavarthi {
1691d8f97da1SVenkata Lakshmi Narayana Gubba 	enum qca_btsoc_type soc_type = qca_soc_type(hu);
16923e4be65eSBalakrishna Godavarthi 	struct qca_serdev *qcadev;
1693fa9ad876SBalakrishna Godavarthi 	int ret;
1694d8f97da1SVenkata Lakshmi Narayana Gubba 	bool sw_ctrl_state;
1695fa9ad876SBalakrishna Godavarthi 
16963e4be65eSBalakrishna Godavarthi 	/* Check for vregs status, may be hci down has turned
16973e4be65eSBalakrishna Godavarthi 	 * off the voltage regulator.
16983e4be65eSBalakrishna Godavarthi 	 */
16993e4be65eSBalakrishna Godavarthi 	qcadev = serdev_device_get_drvdata(hu->serdev);
17003e4be65eSBalakrishna Godavarthi 	if (!qcadev->bt_power->vregs_on) {
17013e4be65eSBalakrishna Godavarthi 		serdev_device_close(hu->serdev);
1702a9314e76SBjorn Andersson 		ret = qca_regulator_enable(qcadev);
17033e4be65eSBalakrishna Godavarthi 		if (ret)
17043e4be65eSBalakrishna Godavarthi 			return ret;
17053e4be65eSBalakrishna Godavarthi 
17063e4be65eSBalakrishna Godavarthi 		ret = serdev_device_open(hu->serdev);
17073e4be65eSBalakrishna Godavarthi 		if (ret) {
17083e4be65eSBalakrishna Godavarthi 			bt_dev_err(hu->hdev, "failed to open port");
17093e4be65eSBalakrishna Godavarthi 			return ret;
17103e4be65eSBalakrishna Godavarthi 		}
17113e4be65eSBalakrishna Godavarthi 	}
17123e4be65eSBalakrishna Godavarthi 
1713691d54d0SNeil Armstrong 	switch (soc_type) {
1714691d54d0SNeil Armstrong 	case QCA_WCN3988:
1715691d54d0SNeil Armstrong 	case QCA_WCN3990:
1716691d54d0SNeil Armstrong 	case QCA_WCN3991:
1717691d54d0SNeil Armstrong 	case QCA_WCN3998:
1718d8f97da1SVenkata Lakshmi Narayana Gubba 		/* Forcefully enable wcn399x to enter in to boot mode. */
1719fa9ad876SBalakrishna Godavarthi 		host_set_baudrate(hu, 2400);
17209836b802SMatthias Kaehlcke 		ret = qca_send_power_pulse(hu, false);
1721fa9ad876SBalakrishna Godavarthi 		if (ret)
1722fa9ad876SBalakrishna Godavarthi 			return ret;
1723691d54d0SNeil Armstrong 		break;
1724691d54d0SNeil Armstrong 
1725691d54d0SNeil Armstrong 	default:
1726691d54d0SNeil Armstrong 		break;
1727d8f97da1SVenkata Lakshmi Narayana Gubba 	}
1728d8f97da1SVenkata Lakshmi Narayana Gubba 
1729d8f97da1SVenkata Lakshmi Narayana Gubba 	/* For wcn6750 need to enable gpio bt_en */
1730d8f97da1SVenkata Lakshmi Narayana Gubba 	if (qcadev->bt_en) {
1731d8f97da1SVenkata Lakshmi Narayana Gubba 		gpiod_set_value_cansleep(qcadev->bt_en, 0);
1732d8f97da1SVenkata Lakshmi Narayana Gubba 		msleep(50);
1733d8f97da1SVenkata Lakshmi Narayana Gubba 		gpiod_set_value_cansleep(qcadev->bt_en, 1);
1734d8f97da1SVenkata Lakshmi Narayana Gubba 		msleep(50);
1735d8f97da1SVenkata Lakshmi Narayana Gubba 		if (qcadev->sw_ctrl) {
1736d8f97da1SVenkata Lakshmi Narayana Gubba 			sw_ctrl_state = gpiod_get_value_cansleep(qcadev->sw_ctrl);
1737d8f97da1SVenkata Lakshmi Narayana Gubba 			bt_dev_dbg(hu->hdev, "SW_CTRL is %d", sw_ctrl_state);
1738d8f97da1SVenkata Lakshmi Narayana Gubba 		}
1739d8f97da1SVenkata Lakshmi Narayana Gubba 	}
1740fa9ad876SBalakrishna Godavarthi 
1741fa9ad876SBalakrishna Godavarthi 	qca_set_speed(hu, QCA_INIT_SPEED);
1742d8f97da1SVenkata Lakshmi Narayana Gubba 
1743691d54d0SNeil Armstrong 	switch (soc_type) {
1744691d54d0SNeil Armstrong 	case QCA_WCN3988:
1745691d54d0SNeil Armstrong 	case QCA_WCN3990:
1746691d54d0SNeil Armstrong 	case QCA_WCN3991:
1747691d54d0SNeil Armstrong 	case QCA_WCN3998:
17489836b802SMatthias Kaehlcke 		ret = qca_send_power_pulse(hu, true);
1749fa9ad876SBalakrishna Godavarthi 		if (ret)
1750fa9ad876SBalakrishna Godavarthi 			return ret;
1751691d54d0SNeil Armstrong 		break;
1752691d54d0SNeil Armstrong 
1753691d54d0SNeil Armstrong 	default:
1754691d54d0SNeil Armstrong 		break;
1755d8f97da1SVenkata Lakshmi Narayana Gubba 	}
1756fa9ad876SBalakrishna Godavarthi 
1757fa9ad876SBalakrishna Godavarthi 	/* Now the device is in ready state to communicate with host.
1758fa9ad876SBalakrishna Godavarthi 	 * To sync host with device we need to reopen port.
1759fa9ad876SBalakrishna Godavarthi 	 * Without this, we will have RTS and CTS synchronization
1760fa9ad876SBalakrishna Godavarthi 	 * issues.
1761fa9ad876SBalakrishna Godavarthi 	 */
1762fa9ad876SBalakrishna Godavarthi 	serdev_device_close(hu->serdev);
1763fa9ad876SBalakrishna Godavarthi 	ret = serdev_device_open(hu->serdev);
1764fa9ad876SBalakrishna Godavarthi 	if (ret) {
1765fa9ad876SBalakrishna Godavarthi 		bt_dev_err(hu->hdev, "failed to open port");
1766fa9ad876SBalakrishna Godavarthi 		return ret;
1767fa9ad876SBalakrishna Godavarthi 	}
1768fa9ad876SBalakrishna Godavarthi 
1769fa9ad876SBalakrishna Godavarthi 	hci_uart_set_flow_control(hu, false);
1770fa9ad876SBalakrishna Godavarthi 
1771fa9ad876SBalakrishna Godavarthi 	return 0;
1772fa9ad876SBalakrishna Godavarthi }
1773fa9ad876SBalakrishna Godavarthi 
qca_power_on(struct hci_dev * hdev)17745e6d8401SRocky Liao static int qca_power_on(struct hci_dev *hdev)
17755e6d8401SRocky Liao {
17765e6d8401SRocky Liao 	struct hci_uart *hu = hci_get_drvdata(hdev);
17775e6d8401SRocky Liao 	enum qca_btsoc_type soc_type = qca_soc_type(hu);
17785e6d8401SRocky Liao 	struct qca_serdev *qcadev;
17792be43abaSVenkata Lakshmi Narayana Gubba 	struct qca_data *qca = hu->priv;
17805e6d8401SRocky Liao 	int ret = 0;
17815e6d8401SRocky Liao 
17825e6d8401SRocky Liao 	/* Non-serdev device usually is powered by external power
17835e6d8401SRocky Liao 	 * and don't need additional action in driver for power on
17845e6d8401SRocky Liao 	 */
17855e6d8401SRocky Liao 	if (!hu->serdev)
17865e6d8401SRocky Liao 		return 0;
17875e6d8401SRocky Liao 
1788691d54d0SNeil Armstrong 	switch (soc_type) {
1789691d54d0SNeil Armstrong 	case QCA_WCN3988:
1790691d54d0SNeil Armstrong 	case QCA_WCN3990:
1791691d54d0SNeil Armstrong 	case QCA_WCN3991:
1792691d54d0SNeil Armstrong 	case QCA_WCN3998:
1793691d54d0SNeil Armstrong 	case QCA_WCN6750:
1794691d54d0SNeil Armstrong 	case QCA_WCN6855:
1795e0c1278aSNeil Armstrong 	case QCA_WCN7850:
1796d8f97da1SVenkata Lakshmi Narayana Gubba 		ret = qca_regulator_init(hu);
1797691d54d0SNeil Armstrong 		break;
1798691d54d0SNeil Armstrong 
1799691d54d0SNeil Armstrong 	default:
18005e6d8401SRocky Liao 		qcadev = serdev_device_get_drvdata(hu->serdev);
180177131dfeSRocky Liao 		if (qcadev->bt_en) {
18025e6d8401SRocky Liao 			gpiod_set_value_cansleep(qcadev->bt_en, 1);
18035e6d8401SRocky Liao 			/* Controller needs time to bootup. */
18045e6d8401SRocky Liao 			msleep(150);
18055e6d8401SRocky Liao 		}
18068a208b24SRocky Liao 	}
18075e6d8401SRocky Liao 
18082be43abaSVenkata Lakshmi Narayana Gubba 	clear_bit(QCA_BT_OFF, &qca->flags);
18095e6d8401SRocky Liao 	return ret;
18105e6d8401SRocky Liao }
18115e6d8401SRocky Liao 
hci_coredump_qca(struct hci_dev * hdev)181206d3fdfcSSai Teja Aluvala static void hci_coredump_qca(struct hci_dev *hdev)
181306d3fdfcSSai Teja Aluvala {
181439e39c34SZijun Hu 	int err;
181506d3fdfcSSai Teja Aluvala 	static const u8 param[] = { 0x26 };
181606d3fdfcSSai Teja Aluvala 
181739e39c34SZijun Hu 	err = __hci_cmd_send(hdev, 0xfc0c, 1, param);
181839e39c34SZijun Hu 	if (err < 0)
181939e39c34SZijun Hu 		bt_dev_err(hdev, "%s: trigger crash failed (%d)", __func__, err);
182006d3fdfcSSai Teja Aluvala }
182106d3fdfcSSai Teja Aluvala 
qca_setup(struct hci_uart * hu)18220ff252c1SBen Young Tae Kim static int qca_setup(struct hci_uart *hu)
18230ff252c1SBen Young Tae Kim {
18240ff252c1SBen Young Tae Kim 	struct hci_dev *hdev = hu->hdev;
18250ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
18260ff252c1SBen Young Tae Kim 	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
1827bb2500abSRocky Liao 	unsigned int retries = 0;
18284fdd5a4fSMatthias Kaehlcke 	enum qca_btsoc_type soc_type = qca_soc_type(hu);
182999c905c6SRocky Liao 	const char *firmware_name = qca_get_firmware_name(hu);
18300ff252c1SBen Young Tae Kim 	int ret;
1831059924fdSVenkata Lakshmi Narayana Gubba 	struct qca_btsoc_version ver;
18321622e563SJohan Hovold 	struct qca_serdev *qcadev;
1833691d54d0SNeil Armstrong 	const char *soc_name;
18340ff252c1SBen Young Tae Kim 
183583d9c5e5SBalakrishna Godavarthi 	ret = qca_check_speeds(hu);
183683d9c5e5SBalakrishna Godavarthi 	if (ret)
183783d9c5e5SBalakrishna Godavarthi 		return ret;
183883d9c5e5SBalakrishna Godavarthi 
183955c0bd77SVenkata Lakshmi Narayana Gubba 	clear_bit(QCA_ROM_FW, &qca->flags);
18400ff252c1SBen Young Tae Kim 	/* Patch downloading has to be done without IBS mode */
18412be43abaSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_IBS_DISABLED, &qca->flags);
18420ff252c1SBen Young Tae Kim 
1843e14c167aSRocky Liao 	/* Enable controller to do both LE scan and BR/EDR inquiry
1844e14c167aSRocky Liao 	 * simultaneously.
1845e14c167aSRocky Liao 	 */
1846e14c167aSRocky Liao 	set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
1847e14c167aSRocky Liao 
1848691d54d0SNeil Armstrong 	switch (soc_type) {
1849a381ee26STim Jiang 	case QCA_QCA2066:
1850a381ee26STim Jiang 		soc_name = "qca2066";
1851a381ee26STim Jiang 		break;
1852a381ee26STim Jiang 
1853691d54d0SNeil Armstrong 	case QCA_WCN3988:
1854691d54d0SNeil Armstrong 	case QCA_WCN3990:
1855691d54d0SNeil Armstrong 	case QCA_WCN3991:
1856691d54d0SNeil Armstrong 	case QCA_WCN3998:
1857691d54d0SNeil Armstrong 		soc_name = "wcn399x";
1858691d54d0SNeil Armstrong 		break;
1859691d54d0SNeil Armstrong 
1860691d54d0SNeil Armstrong 	case QCA_WCN6750:
1861691d54d0SNeil Armstrong 		soc_name = "wcn6750";
1862691d54d0SNeil Armstrong 		break;
1863691d54d0SNeil Armstrong 
1864691d54d0SNeil Armstrong 	case QCA_WCN6855:
1865691d54d0SNeil Armstrong 		soc_name = "wcn6855";
1866691d54d0SNeil Armstrong 		break;
1867691d54d0SNeil Armstrong 
1868e0c1278aSNeil Armstrong 	case QCA_WCN7850:
1869e0c1278aSNeil Armstrong 		soc_name = "wcn7850";
1870e0c1278aSNeil Armstrong 		break;
1871e0c1278aSNeil Armstrong 
1872691d54d0SNeil Armstrong 	default:
1873691d54d0SNeil Armstrong 		soc_name = "ROME/QCA6390";
1874691d54d0SNeil Armstrong 	}
1875691d54d0SNeil Armstrong 	bt_dev_info(hdev, "setting up %s", soc_name);
18763e4be65eSBalakrishna Godavarthi 
187758789a19SVenkata Lakshmi Narayana Gubba 	qca->memdump_state = QCA_MEMDUMP_IDLE;
187858789a19SVenkata Lakshmi Narayana Gubba 
1879bb2500abSRocky Liao retry:
18805e6d8401SRocky Liao 	ret = qca_power_on(hdev);
18815e6d8401SRocky Liao 	if (ret)
18829e80587aSBalakrishna Godavarthi 		goto out;
18835e6d8401SRocky Liao 
18843344537fSVenkata Lakshmi Narayana Gubba 	clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
18853344537fSVenkata Lakshmi Narayana Gubba 
1886691d54d0SNeil Armstrong 	switch (soc_type) {
1887691d54d0SNeil Armstrong 	case QCA_WCN3988:
1888691d54d0SNeil Armstrong 	case QCA_WCN3990:
1889691d54d0SNeil Armstrong 	case QCA_WCN3991:
1890691d54d0SNeil Armstrong 	case QCA_WCN3998:
1891691d54d0SNeil Armstrong 	case QCA_WCN6750:
1892691d54d0SNeil Armstrong 	case QCA_WCN6855:
1893e0c1278aSNeil Armstrong 	case QCA_WCN7850:
18941622e563SJohan Hovold 		qcadev = serdev_device_get_drvdata(hu->serdev);
18951622e563SJohan Hovold 		if (qcadev->bdaddr_property_broken)
18961622e563SJohan Hovold 			set_bit(HCI_QUIRK_BDADDR_PROPERTY_BROKEN, &hdev->quirks);
18971622e563SJohan Hovold 
189834af56e8SJoseph Hwang 		hci_set_aosp_capable(hdev);
1899fa9ad876SBalakrishna Godavarthi 
1900059924fdSVenkata Lakshmi Narayana Gubba 		ret = qca_read_soc_version(hdev, &ver, soc_type);
1901fa9ad876SBalakrishna Godavarthi 		if (ret)
19029e80587aSBalakrishna Godavarthi 			goto out;
1903691d54d0SNeil Armstrong 		break;
1904691d54d0SNeil Armstrong 
1905691d54d0SNeil Armstrong 	default:
190683d9c5e5SBalakrishna Godavarthi 		qca_set_speed(hu, QCA_INIT_SPEED);
1907fa9ad876SBalakrishna Godavarthi 	}
19080ff252c1SBen Young Tae Kim 
19090ff252c1SBen Young Tae Kim 	/* Setup user speed if needed */
191083d9c5e5SBalakrishna Godavarthi 	speed = qca_get_speed(hu, QCA_OPER_SPEED);
19110ff252c1SBen Young Tae Kim 	if (speed) {
191283d9c5e5SBalakrishna Godavarthi 		ret = qca_set_speed(hu, QCA_OPER_SPEED);
191383d9c5e5SBalakrishna Godavarthi 		if (ret)
19149e80587aSBalakrishna Godavarthi 			goto out;
191583d9c5e5SBalakrishna Godavarthi 
191683d9c5e5SBalakrishna Godavarthi 		qca_baudrate = qca_get_baudrate_value(speed);
19170ff252c1SBen Young Tae Kim 	}
19180ff252c1SBen Young Tae Kim 
1919691d54d0SNeil Armstrong 	switch (soc_type) {
1920691d54d0SNeil Armstrong 	case QCA_WCN3988:
1921691d54d0SNeil Armstrong 	case QCA_WCN3990:
1922691d54d0SNeil Armstrong 	case QCA_WCN3991:
1923691d54d0SNeil Armstrong 	case QCA_WCN3998:
1924691d54d0SNeil Armstrong 	case QCA_WCN6750:
1925691d54d0SNeil Armstrong 	case QCA_WCN6855:
1926e0c1278aSNeil Armstrong 	case QCA_WCN7850:
1927691d54d0SNeil Armstrong 		break;
1928691d54d0SNeil Armstrong 
1929691d54d0SNeil Armstrong 	default:
1930aadebac4SBalakrishna Godavarthi 		/* Get QCA version information */
1931059924fdSVenkata Lakshmi Narayana Gubba 		ret = qca_read_soc_version(hdev, &ver, soc_type);
1932aadebac4SBalakrishna Godavarthi 		if (ret)
19339e80587aSBalakrishna Godavarthi 			goto out;
1934fa9ad876SBalakrishna Godavarthi 	}
1935aadebac4SBalakrishna Godavarthi 
19360ff252c1SBen Young Tae Kim 	/* Setup patch / NVM configurations */
1937059924fdSVenkata Lakshmi Narayana Gubba 	ret = qca_uart_setup(hdev, qca_baudrate, soc_type, ver,
193899c905c6SRocky Liao 			firmware_name);
19390ff252c1SBen Young Tae Kim 	if (!ret) {
19402be43abaSVenkata Lakshmi Narayana Gubba 		clear_bit(QCA_IBS_DISABLED, &qca->flags);
19410ff252c1SBen Young Tae Kim 		qca_debugfs_init(hdev);
1942d841502cSBalakrishna Godavarthi 		hu->hdev->hw_error = qca_hw_error;
1943d841502cSBalakrishna Godavarthi 		hu->hdev->cmd_timeout = qca_cmd_timeout;
194467459f1aSJohan Hovold 		if (hu->serdev) {
1945e9b3e5b8SZhengping Jiang 			if (device_can_wakeup(hu->serdev->ctrl->dev.parent))
19464539ca67SLuiz Augusto von Dentz 				hu->hdev->wakeup = qca_wakeup;
194767459f1aSJohan Hovold 		}
1948ba8f3597SLoic Poulain 	} else if (ret == -ENOENT) {
1949ba8f3597SLoic Poulain 		/* No patch/nvm-config found, run with original fw/config */
195055c0bd77SVenkata Lakshmi Narayana Gubba 		set_bit(QCA_ROM_FW, &qca->flags);
1951ba8f3597SLoic Poulain 		ret = 0;
19527dc5fe08SAmit Pundir 	} else if (ret == -EAGAIN) {
19537dc5fe08SAmit Pundir 		/*
19547dc5fe08SAmit Pundir 		 * Userspace firmware loader will return -EAGAIN in case no
19557dc5fe08SAmit Pundir 		 * patch/nvm-config is found, so run with original fw/config.
19567dc5fe08SAmit Pundir 		 */
195755c0bd77SVenkata Lakshmi Narayana Gubba 		set_bit(QCA_ROM_FW, &qca->flags);
19587dc5fe08SAmit Pundir 		ret = 0;
19599e80587aSBalakrishna Godavarthi 	}
19609e80587aSBalakrishna Godavarthi 
19619e80587aSBalakrishna Godavarthi out:
19629e80587aSBalakrishna Godavarthi 	if (ret && retries < MAX_INIT_RETRIES) {
19639e80587aSBalakrishna Godavarthi 		bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
1964bb2500abSRocky Liao 		qca_power_shutdown(hu);
1965bb2500abSRocky Liao 		if (hu->serdev) {
1966bb2500abSRocky Liao 			serdev_device_close(hu->serdev);
1967bb2500abSRocky Liao 			ret = serdev_device_open(hu->serdev);
1968bb2500abSRocky Liao 			if (ret) {
1969bb2500abSRocky Liao 				bt_dev_err(hdev, "failed to open port");
1970bb2500abSRocky Liao 				return ret;
1971bb2500abSRocky Liao 			}
1972bb2500abSRocky Liao 		}
1973bb2500abSRocky Liao 		retries++;
1974bb2500abSRocky Liao 		goto retry;
1975bb2500abSRocky Liao 	}
19760ff252c1SBen Young Tae Kim 
19770ff252c1SBen Young Tae Kim 	/* Setup bdaddr */
1978e5d6468fSRocky Liao 	if (soc_type == QCA_ROME)
19790ff252c1SBen Young Tae Kim 		hu->hdev->set_bdaddr = qca_set_bdaddr_rome;
1980e5d6468fSRocky Liao 	else
1981e5d6468fSRocky Liao 		hu->hdev->set_bdaddr = qca_set_bdaddr;
198206d3fdfcSSai Teja Aluvala 	qca->fw_version = le16_to_cpu(ver.patch_ver);
198306d3fdfcSSai Teja Aluvala 	qca->controller_id = le16_to_cpu(ver.rom_ver);
198406d3fdfcSSai Teja Aluvala 	hci_devcd_register(hdev, hci_coredump_qca, qca_dmp_hdr, NULL);
19850ff252c1SBen Young Tae Kim 
19860ff252c1SBen Young Tae Kim 	return ret;
19870ff252c1SBen Young Tae Kim }
19880ff252c1SBen Young Tae Kim 
19892edc9c5cSNishka Dasgupta static const struct hci_uart_proto qca_proto = {
19900ff252c1SBen Young Tae Kim 	.id		= HCI_UART_QCA,
19910ff252c1SBen Young Tae Kim 	.name		= "QCA",
1992aee61f7aSMarcel Holtmann 	.manufacturer	= 29,
19930ff252c1SBen Young Tae Kim 	.init_speed	= 115200,
19940ff252c1SBen Young Tae Kim 	.oper_speed	= 3000000,
19950ff252c1SBen Young Tae Kim 	.open		= qca_open,
19960ff252c1SBen Young Tae Kim 	.close		= qca_close,
19970ff252c1SBen Young Tae Kim 	.flush		= qca_flush,
19980ff252c1SBen Young Tae Kim 	.setup		= qca_setup,
19990ff252c1SBen Young Tae Kim 	.recv		= qca_recv,
20000ff252c1SBen Young Tae Kim 	.enqueue	= qca_enqueue,
20010ff252c1SBen Young Tae Kim 	.dequeue	= qca_dequeue,
20020ff252c1SBen Young Tae Kim };
20030ff252c1SBen Young Tae Kim 
2004f904feefSLuca Weiss static const struct qca_device_data qca_soc_data_wcn3988 __maybe_unused = {
2005f904feefSLuca Weiss 	.soc_type = QCA_WCN3988,
2006f904feefSLuca Weiss 	.vregs = (struct qca_vreg []) {
2007f904feefSLuca Weiss 		{ "vddio", 15000  },
2008f904feefSLuca Weiss 		{ "vddxo", 80000  },
2009f904feefSLuca Weiss 		{ "vddrf", 300000 },
2010f904feefSLuca Weiss 		{ "vddch0", 450000 },
2011f904feefSLuca Weiss 	},
2012f904feefSLuca Weiss 	.num_vregs = 4,
2013f904feefSLuca Weiss };
2014f904feefSLuca Weiss 
201544fac8a2SKrzysztof Kozlowski static const struct qca_device_data qca_soc_data_wcn3990 __maybe_unused = {
2016fa9ad876SBalakrishna Godavarthi 	.soc_type = QCA_WCN3990,
2017fa9ad876SBalakrishna Godavarthi 	.vregs = (struct qca_vreg []) {
2018f2edd66eSBjorn Andersson 		{ "vddio", 15000  },
2019f2edd66eSBjorn Andersson 		{ "vddxo", 80000  },
2020f2edd66eSBjorn Andersson 		{ "vddrf", 300000 },
2021f2edd66eSBjorn Andersson 		{ "vddch0", 450000 },
2022fa9ad876SBalakrishna Godavarthi 	},
2023fa9ad876SBalakrishna Godavarthi 	.num_vregs = 4,
2024fa9ad876SBalakrishna Godavarthi };
2025fa9ad876SBalakrishna Godavarthi 
202644fac8a2SKrzysztof Kozlowski static const struct qca_device_data qca_soc_data_wcn3991 __maybe_unused = {
20277d250a06SBalakrishna Godavarthi 	.soc_type = QCA_WCN3991,
20287d250a06SBalakrishna Godavarthi 	.vregs = (struct qca_vreg []) {
20297d250a06SBalakrishna Godavarthi 		{ "vddio", 15000  },
20307d250a06SBalakrishna Godavarthi 		{ "vddxo", 80000  },
20317d250a06SBalakrishna Godavarthi 		{ "vddrf", 300000 },
20327d250a06SBalakrishna Godavarthi 		{ "vddch0", 450000 },
20337d250a06SBalakrishna Godavarthi 	},
20347d250a06SBalakrishna Godavarthi 	.num_vregs = 4,
203554780138SAbhishek Pandit-Subedi 	.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
20367d250a06SBalakrishna Godavarthi };
20377d250a06SBalakrishna Godavarthi 
203844fac8a2SKrzysztof Kozlowski static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = {
2039523760b7SHarish Bandi 	.soc_type = QCA_WCN3998,
2040523760b7SHarish Bandi 	.vregs = (struct qca_vreg []) {
2041f2edd66eSBjorn Andersson 		{ "vddio", 10000  },
2042f2edd66eSBjorn Andersson 		{ "vddxo", 80000  },
2043f2edd66eSBjorn Andersson 		{ "vddrf", 300000 },
2044f2edd66eSBjorn Andersson 		{ "vddch0", 450000 },
2045523760b7SHarish Bandi 	},
2046523760b7SHarish Bandi 	.num_vregs = 4,
2047523760b7SHarish Bandi };
2048523760b7SHarish Bandi 
2049a381ee26STim Jiang static const struct qca_device_data qca_soc_data_qca2066 __maybe_unused = {
2050a381ee26STim Jiang 	.soc_type = QCA_QCA2066,
2051a381ee26STim Jiang 	.num_vregs = 0,
2052a381ee26STim Jiang };
2053a381ee26STim Jiang 
205444fac8a2SKrzysztof Kozlowski static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = {
2055e5d6468fSRocky Liao 	.soc_type = QCA_QCA6390,
2056e5d6468fSRocky Liao 	.num_vregs = 0,
2057f2719eccSZijun Hu 	.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
2058e5d6468fSRocky Liao };
2059e5d6468fSRocky Liao 
206044fac8a2SKrzysztof Kozlowski static const struct qca_device_data qca_soc_data_wcn6750 __maybe_unused = {
2061d8f97da1SVenkata Lakshmi Narayana Gubba 	.soc_type = QCA_WCN6750,
2062d8f97da1SVenkata Lakshmi Narayana Gubba 	.vregs = (struct qca_vreg []) {
2063d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddio", 5000 },
2064d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddaon", 26000 },
2065d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddbtcxmx", 126000 },
2066d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddrfacmn", 12500 },
2067d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddrfa0p8", 102000 },
2068d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddrfa1p7", 302000 },
2069d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddrfa1p2", 257000 },
2070d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddrfa2p2", 1700000 },
2071d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddasd", 200 },
2072d8f97da1SVenkata Lakshmi Narayana Gubba 	},
2073d8f97da1SVenkata Lakshmi Narayana Gubba 	.num_vregs = 9,
2074d8f97da1SVenkata Lakshmi Narayana Gubba 	.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
2075d8f97da1SVenkata Lakshmi Narayana Gubba };
2076d8f97da1SVenkata Lakshmi Narayana Gubba 
20770811ff48SSteev Klimaszewski static const struct qca_device_data qca_soc_data_wcn6855 __maybe_unused = {
2078095327feSSteev Klimaszewski 	.soc_type = QCA_WCN6855,
2079095327feSSteev Klimaszewski 	.vregs = (struct qca_vreg []) {
2080095327feSSteev Klimaszewski 		{ "vddio", 5000 },
2081095327feSSteev Klimaszewski 		{ "vddbtcxmx", 126000 },
2082095327feSSteev Klimaszewski 		{ "vddrfacmn", 12500 },
2083095327feSSteev Klimaszewski 		{ "vddrfa0p8", 102000 },
2084095327feSSteev Klimaszewski 		{ "vddrfa1p7", 302000 },
2085095327feSSteev Klimaszewski 		{ "vddrfa1p2", 257000 },
2086095327feSSteev Klimaszewski 	},
2087095327feSSteev Klimaszewski 	.num_vregs = 6,
2088095327feSSteev Klimaszewski 	.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
2089095327feSSteev Klimaszewski };
2090095327feSSteev Klimaszewski 
2091e0c1278aSNeil Armstrong static const struct qca_device_data qca_soc_data_wcn7850 __maybe_unused = {
2092e0c1278aSNeil Armstrong 	.soc_type = QCA_WCN7850,
2093e0c1278aSNeil Armstrong 	.vregs = (struct qca_vreg []) {
2094e0c1278aSNeil Armstrong 		{ "vddio", 5000 },
2095e0c1278aSNeil Armstrong 		{ "vddaon", 26000 },
2096e0c1278aSNeil Armstrong 		{ "vdddig", 126000 },
2097e0c1278aSNeil Armstrong 		{ "vddrfa0p8", 102000 },
2098e0c1278aSNeil Armstrong 		{ "vddrfa1p2", 257000 },
2099e0c1278aSNeil Armstrong 		{ "vddrfa1p9", 302000 },
2100e0c1278aSNeil Armstrong 	},
2101e0c1278aSNeil Armstrong 	.num_vregs = 6,
2102e0c1278aSNeil Armstrong 	.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
2103e0c1278aSNeil Armstrong };
2104e0c1278aSNeil Armstrong 
qca_power_shutdown(struct hci_uart * hu)2105c2d78273SBalakrishna Godavarthi static void qca_power_shutdown(struct hci_uart *hu)
2106fa9ad876SBalakrishna Godavarthi {
2107a9314e76SBjorn Andersson 	struct qca_serdev *qcadev;
2108035a960eSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
2109035a960eSBalakrishna Godavarthi 	unsigned long flags;
21105559904cSRocky Liao 	enum qca_btsoc_type soc_type = qca_soc_type(hu);
2111d8f97da1SVenkata Lakshmi Narayana Gubba 	bool sw_ctrl_state;
2112035a960eSBalakrishna Godavarthi 
2113035a960eSBalakrishna Godavarthi 	/* From this point we go into power off state. But serial port is
2114035a960eSBalakrishna Godavarthi 	 * still open, stop queueing the IBS data and flush all the buffered
2115035a960eSBalakrishna Godavarthi 	 * data in skb's.
2116035a960eSBalakrishna Godavarthi 	 */
2117035a960eSBalakrishna Godavarthi 	spin_lock_irqsave(&qca->hci_ibs_lock, flags);
21182be43abaSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_IBS_DISABLED, &qca->flags);
2119035a960eSBalakrishna Godavarthi 	qca_flush(hu);
2120035a960eSBalakrishna Godavarthi 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
2121035a960eSBalakrishna Godavarthi 
21225559904cSRocky Liao 	/* Non-serdev device usually is powered by external power
21235559904cSRocky Liao 	 * and don't need additional action in driver for power down
21245559904cSRocky Liao 	 */
21255559904cSRocky Liao 	if (!hu->serdev)
21265559904cSRocky Liao 		return;
21275559904cSRocky Liao 
212859f90f13SPavel Skripkin 	qcadev = serdev_device_get_drvdata(hu->serdev);
212959f90f13SPavel Skripkin 
2130691d54d0SNeil Armstrong 	switch (soc_type) {
2131691d54d0SNeil Armstrong 	case QCA_WCN3988:
2132691d54d0SNeil Armstrong 	case QCA_WCN3990:
2133691d54d0SNeil Armstrong 	case QCA_WCN3991:
2134691d54d0SNeil Armstrong 	case QCA_WCN3998:
2135fa9ad876SBalakrishna Godavarthi 		host_set_baudrate(hu, 2400);
21369836b802SMatthias Kaehlcke 		qca_send_power_pulse(hu, false);
2137a9314e76SBjorn Andersson 		qca_regulator_disable(qcadev);
2138691d54d0SNeil Armstrong 		break;
2139691d54d0SNeil Armstrong 
2140691d54d0SNeil Armstrong 	case QCA_WCN6750:
2141691d54d0SNeil Armstrong 	case QCA_WCN6855:
2142d8f97da1SVenkata Lakshmi Narayana Gubba 		gpiod_set_value_cansleep(qcadev->bt_en, 0);
2143d8f97da1SVenkata Lakshmi Narayana Gubba 		msleep(100);
2144d8f97da1SVenkata Lakshmi Narayana Gubba 		qca_regulator_disable(qcadev);
2145d8f97da1SVenkata Lakshmi Narayana Gubba 		if (qcadev->sw_ctrl) {
2146d8f97da1SVenkata Lakshmi Narayana Gubba 			sw_ctrl_state = gpiod_get_value_cansleep(qcadev->sw_ctrl);
2147d8f97da1SVenkata Lakshmi Narayana Gubba 			bt_dev_dbg(hu->hdev, "SW_CTRL is %d", sw_ctrl_state);
2148d8f97da1SVenkata Lakshmi Narayana Gubba 		}
2149691d54d0SNeil Armstrong 		break;
2150691d54d0SNeil Armstrong 
2151691d54d0SNeil Armstrong 	default:
21525559904cSRocky Liao 		gpiod_set_value_cansleep(qcadev->bt_en, 0);
21535559904cSRocky Liao 	}
21542be43abaSVenkata Lakshmi Narayana Gubba 
21552be43abaSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_BT_OFF, &qca->flags);
2156fa9ad876SBalakrishna Godavarthi }
2157fa9ad876SBalakrishna Godavarthi 
qca_power_off(struct hci_dev * hdev)21583e4be65eSBalakrishna Godavarthi static int qca_power_off(struct hci_dev *hdev)
21593e4be65eSBalakrishna Godavarthi {
21603e4be65eSBalakrishna Godavarthi 	struct hci_uart *hu = hci_get_drvdata(hdev);
2161d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
21624f9ed5bdSRocky Liao 	enum qca_btsoc_type soc_type = qca_soc_type(hu);
21633e4be65eSBalakrishna Godavarthi 
216458789a19SVenkata Lakshmi Narayana Gubba 	hu->hdev->hw_error = NULL;
216558789a19SVenkata Lakshmi Narayana Gubba 	hu->hdev->cmd_timeout = NULL;
216658789a19SVenkata Lakshmi Narayana Gubba 
2167df1e5c51SPanicker Harish 	del_timer_sync(&qca->wake_retrans_timer);
2168df1e5c51SPanicker Harish 	del_timer_sync(&qca->tx_idle_timer);
2169df1e5c51SPanicker Harish 
2170d841502cSBalakrishna Godavarthi 	/* Stop sending shutdown command if soc crashes. */
2171e5d6468fSRocky Liao 	if (soc_type != QCA_ROME
21724f9ed5bdSRocky Liao 		&& qca->memdump_state == QCA_MEMDUMP_IDLE) {
2173a2780889SHarish Bandi 		qca_send_pre_shutdown_cmd(hdev);
2174010376abSHarish Bandi 		usleep_range(8000, 10000);
2175d841502cSBalakrishna Godavarthi 	}
2176010376abSHarish Bandi 
21773e4be65eSBalakrishna Godavarthi 	qca_power_shutdown(hu);
21783e4be65eSBalakrishna Godavarthi 	return 0;
21793e4be65eSBalakrishna Godavarthi }
21803e4be65eSBalakrishna Godavarthi 
qca_regulator_enable(struct qca_serdev * qcadev)2181a9314e76SBjorn Andersson static int qca_regulator_enable(struct qca_serdev *qcadev)
2182fa9ad876SBalakrishna Godavarthi {
2183a9314e76SBjorn Andersson 	struct qca_power *power = qcadev->bt_power;
2184a9314e76SBjorn Andersson 	int ret;
2185fa9ad876SBalakrishna Godavarthi 
2186a9314e76SBjorn Andersson 	/* Already enabled */
2187a9314e76SBjorn Andersson 	if (power->vregs_on)
2188a9314e76SBjorn Andersson 		return 0;
2189fa9ad876SBalakrishna Godavarthi 
2190a9314e76SBjorn Andersson 	BT_DBG("enabling %d regulators)", power->num_vregs);
2191a9314e76SBjorn Andersson 
2192a9314e76SBjorn Andersson 	ret = regulator_bulk_enable(power->num_vregs, power->vreg_bulk);
2193fa9ad876SBalakrishna Godavarthi 	if (ret)
2194163d42faSBjorn Andersson 		return ret;
2195fa9ad876SBalakrishna Godavarthi 
2196a9314e76SBjorn Andersson 	power->vregs_on = true;
2197fa9ad876SBalakrishna Godavarthi 
219866cb7051SVenkata Lakshmi Narayana Gubba 	ret = clk_prepare_enable(qcadev->susclk);
2199f3d63f50SVenkata Lakshmi Narayana Gubba 	if (ret)
220066cb7051SVenkata Lakshmi Narayana Gubba 		qca_regulator_disable(qcadev);
220166cb7051SVenkata Lakshmi Narayana Gubba 
2202f3d63f50SVenkata Lakshmi Narayana Gubba 	return ret;
2203fa9ad876SBalakrishna Godavarthi }
2204fa9ad876SBalakrishna Godavarthi 
qca_regulator_disable(struct qca_serdev * qcadev)2205a9314e76SBjorn Andersson static void qca_regulator_disable(struct qca_serdev *qcadev)
2206a9314e76SBjorn Andersson {
2207a9314e76SBjorn Andersson 	struct qca_power *power;
2208a9314e76SBjorn Andersson 
2209a9314e76SBjorn Andersson 	if (!qcadev)
2210a9314e76SBjorn Andersson 		return;
2211a9314e76SBjorn Andersson 
2212a9314e76SBjorn Andersson 	power = qcadev->bt_power;
2213a9314e76SBjorn Andersson 
2214a9314e76SBjorn Andersson 	/* Already disabled? */
2215a9314e76SBjorn Andersson 	if (!power->vregs_on)
2216a9314e76SBjorn Andersson 		return;
2217a9314e76SBjorn Andersson 
2218a9314e76SBjorn Andersson 	regulator_bulk_disable(power->num_vregs, power->vreg_bulk);
2219a9314e76SBjorn Andersson 	power->vregs_on = false;
222066cb7051SVenkata Lakshmi Narayana Gubba 
222166cb7051SVenkata Lakshmi Narayana Gubba 	clk_disable_unprepare(qcadev->susclk);
2222a9314e76SBjorn Andersson }
2223a9314e76SBjorn Andersson 
qca_init_regulators(struct qca_power * qca,const struct qca_vreg * vregs,size_t num_vregs)2224fa9ad876SBalakrishna Godavarthi static int qca_init_regulators(struct qca_power *qca,
2225fa9ad876SBalakrishna Godavarthi 				const struct qca_vreg *vregs, size_t num_vregs)
2226fa9ad876SBalakrishna Godavarthi {
2227c29ff107SBjorn Andersson 	struct regulator_bulk_data *bulk;
2228c29ff107SBjorn Andersson 	int ret;
2229fa9ad876SBalakrishna Godavarthi 	int i;
2230fa9ad876SBalakrishna Godavarthi 
2231c29ff107SBjorn Andersson 	bulk = devm_kcalloc(qca->dev, num_vregs, sizeof(*bulk), GFP_KERNEL);
2232c29ff107SBjorn Andersson 	if (!bulk)
2233fa9ad876SBalakrishna Godavarthi 		return -ENOMEM;
2234fa9ad876SBalakrishna Godavarthi 
2235fa9ad876SBalakrishna Godavarthi 	for (i = 0; i < num_vregs; i++)
2236c29ff107SBjorn Andersson 		bulk[i].supply = vregs[i].name;
2237fa9ad876SBalakrishna Godavarthi 
2238c29ff107SBjorn Andersson 	ret = devm_regulator_bulk_get(qca->dev, num_vregs, bulk);
2239c29ff107SBjorn Andersson 	if (ret < 0)
2240c29ff107SBjorn Andersson 		return ret;
2241c29ff107SBjorn Andersson 
2242c29ff107SBjorn Andersson 	for (i = 0; i < num_vregs; i++) {
2243c29ff107SBjorn Andersson 		ret = regulator_set_load(bulk[i].consumer, vregs[i].load_uA);
2244c29ff107SBjorn Andersson 		if (ret)
2245c29ff107SBjorn Andersson 			return ret;
2246c29ff107SBjorn Andersson 	}
2247c29ff107SBjorn Andersson 
2248c29ff107SBjorn Andersson 	qca->vreg_bulk = bulk;
2249163d42faSBjorn Andersson 	qca->num_vregs = num_vregs;
2250c29ff107SBjorn Andersson 
2251c29ff107SBjorn Andersson 	return 0;
2252fa9ad876SBalakrishna Godavarthi }
2253fa9ad876SBalakrishna Godavarthi 
qca_serdev_probe(struct serdev_device * serdev)225405ba533cSThierry Escande static int qca_serdev_probe(struct serdev_device *serdev)
225505ba533cSThierry Escande {
225605ba533cSThierry Escande 	struct qca_serdev *qcadev;
2257ae563183SRocky Liao 	struct hci_dev *hdev;
2258a228f7a4SAbhishek Pandit-Subedi 	const struct qca_device_data *data;
225905ba533cSThierry Escande 	int err;
22608a208b24SRocky Liao 	bool power_ctrl_enabled = true;
226105ba533cSThierry Escande 
226205ba533cSThierry Escande 	qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL);
226305ba533cSThierry Escande 	if (!qcadev)
226405ba533cSThierry Escande 		return -ENOMEM;
226505ba533cSThierry Escande 
226605ba533cSThierry Escande 	qcadev->serdev_hu.serdev = serdev;
22679f3565b8SRocky Liao 	data = device_get_match_data(&serdev->dev);
226805ba533cSThierry Escande 	serdev_device_set_drvdata(serdev, qcadev);
226999c905c6SRocky Liao 	device_property_read_string(&serdev->dev, "firmware-name",
227099c905c6SRocky Liao 					 &qcadev->firmware_name);
227137aee136SChristian Hewitt 	device_property_read_u32(&serdev->dev, "max-speed",
227237aee136SChristian Hewitt 				 &qcadev->oper_speed);
227337aee136SChristian Hewitt 	if (!qcadev->oper_speed)
227437aee136SChristian Hewitt 		BT_DBG("UART will pick default operating speed");
227537aee136SChristian Hewitt 
22761622e563SJohan Hovold 	qcadev->bdaddr_property_broken = device_property_read_bool(&serdev->dev,
22771622e563SJohan Hovold 			"qcom,local-bd-address-broken");
22781622e563SJohan Hovold 
2279691d54d0SNeil Armstrong 	if (data)
2280523760b7SHarish Bandi 		qcadev->btsoc_type = data->soc_type;
2281691d54d0SNeil Armstrong 	else
2282691d54d0SNeil Armstrong 		qcadev->btsoc_type = QCA_ROME;
2283691d54d0SNeil Armstrong 
2284691d54d0SNeil Armstrong 	switch (qcadev->btsoc_type) {
2285691d54d0SNeil Armstrong 	case QCA_WCN3988:
2286691d54d0SNeil Armstrong 	case QCA_WCN3990:
2287691d54d0SNeil Armstrong 	case QCA_WCN3991:
2288691d54d0SNeil Armstrong 	case QCA_WCN3998:
2289691d54d0SNeil Armstrong 	case QCA_WCN6750:
2290691d54d0SNeil Armstrong 	case QCA_WCN6855:
2291e0c1278aSNeil Armstrong 	case QCA_WCN7850:
2292fa9ad876SBalakrishna Godavarthi 		qcadev->bt_power = devm_kzalloc(&serdev->dev,
2293fa9ad876SBalakrishna Godavarthi 						sizeof(struct qca_power),
2294fa9ad876SBalakrishna Godavarthi 						GFP_KERNEL);
2295fa9ad876SBalakrishna Godavarthi 		if (!qcadev->bt_power)
2296fa9ad876SBalakrishna Godavarthi 			return -ENOMEM;
229705ba533cSThierry Escande 
2298fa9ad876SBalakrishna Godavarthi 		qcadev->bt_power->dev = &serdev->dev;
2299fa9ad876SBalakrishna Godavarthi 		err = qca_init_regulators(qcadev->bt_power, data->vregs,
2300fa9ad876SBalakrishna Godavarthi 					  data->num_vregs);
2301fa9ad876SBalakrishna Godavarthi 		if (err) {
2302fa9ad876SBalakrishna Godavarthi 			BT_ERR("Failed to init regulators:%d", err);
2303ae563183SRocky Liao 			return err;
2304fa9ad876SBalakrishna Godavarthi 		}
2305fa9ad876SBalakrishna Godavarthi 
2306fa9ad876SBalakrishna Godavarthi 		qcadev->bt_power->vregs_on = false;
2307fa9ad876SBalakrishna Godavarthi 
2308d8f97da1SVenkata Lakshmi Narayana Gubba 		qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
2309d8f97da1SVenkata Lakshmi Narayana Gubba 					       GPIOD_OUT_LOW);
2310988b77baSBartosz Golaszewski 		if (IS_ERR(qcadev->bt_en) &&
2311095327feSSteev Klimaszewski 		    (data->soc_type == QCA_WCN6750 ||
2312095327feSSteev Klimaszewski 		     data->soc_type == QCA_WCN6855)) {
2313d8f97da1SVenkata Lakshmi Narayana Gubba 			dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n");
2314cd212ca2SBartosz Golaszewski 			return PTR_ERR(qcadev->bt_en);
2315d8f97da1SVenkata Lakshmi Narayana Gubba 		}
2316d8f97da1SVenkata Lakshmi Narayana Gubba 
2317cd212ca2SBartosz Golaszewski 		if (!qcadev->bt_en)
2318cd212ca2SBartosz Golaszewski 			power_ctrl_enabled = false;
2319cd212ca2SBartosz Golaszewski 
2320d8f97da1SVenkata Lakshmi Narayana Gubba 		qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl",
2321d8f97da1SVenkata Lakshmi Narayana Gubba 					       GPIOD_IN);
2322988b77baSBartosz Golaszewski 		if (IS_ERR(qcadev->sw_ctrl) &&
2323095327feSSteev Klimaszewski 		    (data->soc_type == QCA_WCN6750 ||
2324e0c1278aSNeil Armstrong 		     data->soc_type == QCA_WCN6855 ||
2325cd212ca2SBartosz Golaszewski 		     data->soc_type == QCA_WCN7850)) {
2326cd212ca2SBartosz Golaszewski 			dev_err(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
2327cd212ca2SBartosz Golaszewski 			return PTR_ERR(qcadev->sw_ctrl);
2328cd212ca2SBartosz Golaszewski 		}
2329d8f97da1SVenkata Lakshmi Narayana Gubba 
233066cb7051SVenkata Lakshmi Narayana Gubba 		qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
233166cb7051SVenkata Lakshmi Narayana Gubba 		if (IS_ERR(qcadev->susclk)) {
233266cb7051SVenkata Lakshmi Narayana Gubba 			dev_err(&serdev->dev, "failed to acquire clk\n");
233366cb7051SVenkata Lakshmi Narayana Gubba 			return PTR_ERR(qcadev->susclk);
233466cb7051SVenkata Lakshmi Narayana Gubba 		}
233566cb7051SVenkata Lakshmi Narayana Gubba 
2336fa9ad876SBalakrishna Godavarthi 		err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
2337fa9ad876SBalakrishna Godavarthi 		if (err) {
2338fa9ad876SBalakrishna Godavarthi 			BT_ERR("wcn3990 serdev registration failed");
2339ae563183SRocky Liao 			return err;
2340fa9ad876SBalakrishna Godavarthi 		}
2341691d54d0SNeil Armstrong 		break;
2342e5d6468fSRocky Liao 
2343691d54d0SNeil Armstrong 	default:
234477131dfeSRocky Liao 		qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
234505ba533cSThierry Escande 					       GPIOD_OUT_LOW);
2346988b77baSBartosz Golaszewski 		if (IS_ERR(qcadev->bt_en)) {
2347cd212ca2SBartosz Golaszewski 			dev_err(&serdev->dev, "failed to acquire enable gpio\n");
2348cd212ca2SBartosz Golaszewski 			return PTR_ERR(qcadev->bt_en);
234905ba533cSThierry Escande 		}
235005ba533cSThierry Escande 
2351cd212ca2SBartosz Golaszewski 		if (!qcadev->bt_en)
2352cd212ca2SBartosz Golaszewski 			power_ctrl_enabled = false;
2353cd212ca2SBartosz Golaszewski 
235477131dfeSRocky Liao 		qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
23554c07a5d7SDan Carpenter 		if (IS_ERR(qcadev->susclk)) {
23568a208b24SRocky Liao 			dev_warn(&serdev->dev, "failed to acquire clk\n");
23574c07a5d7SDan Carpenter 			return PTR_ERR(qcadev->susclk);
23584c07a5d7SDan Carpenter 		}
235905ba533cSThierry Escande 		err = clk_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ);
236005ba533cSThierry Escande 		if (err)
236105ba533cSThierry Escande 			return err;
236205ba533cSThierry Escande 
236305ba533cSThierry Escande 		err = clk_prepare_enable(qcadev->susclk);
236405ba533cSThierry Escande 		if (err)
236505ba533cSThierry Escande 			return err;
236605ba533cSThierry Escande 
236705ba533cSThierry Escande 		err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
2368ae563183SRocky Liao 		if (err) {
2369ae563183SRocky Liao 			BT_ERR("Rome serdev registration failed");
237005ba533cSThierry Escande 			clk_disable_unprepare(qcadev->susclk);
2371ae563183SRocky Liao 			return err;
2372ae563183SRocky Liao 		}
2373fa9ad876SBalakrishna Godavarthi 	}
237405ba533cSThierry Escande 
2375ae563183SRocky Liao 	hdev = qcadev->serdev_hu.hdev;
237685e90d93SAbhishek Pandit-Subedi 
237785e90d93SAbhishek Pandit-Subedi 	if (power_ctrl_enabled) {
2378ae563183SRocky Liao 		set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
2379ae563183SRocky Liao 		hdev->shutdown = qca_power_off;
23808a208b24SRocky Liao 	}
2381fa9ad876SBalakrishna Godavarthi 
238254780138SAbhishek Pandit-Subedi 	if (data) {
238354780138SAbhishek Pandit-Subedi 		/* Wideband speech support must be set per driver since it can't
238454780138SAbhishek Pandit-Subedi 		 * be queried via hci. Same with the valid le states quirk.
2385a228f7a4SAbhishek Pandit-Subedi 		 */
238654780138SAbhishek Pandit-Subedi 		if (data->capabilities & QCA_CAP_WIDEBAND_SPEECH)
238754780138SAbhishek Pandit-Subedi 			set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
238854780138SAbhishek Pandit-Subedi 				&hdev->quirks);
238954780138SAbhishek Pandit-Subedi 
239054780138SAbhishek Pandit-Subedi 		if (data->capabilities & QCA_CAP_VALID_LE_STATES)
239154780138SAbhishek Pandit-Subedi 			set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
239254780138SAbhishek Pandit-Subedi 	}
2393a228f7a4SAbhishek Pandit-Subedi 
2394ae563183SRocky Liao 	return 0;
239505ba533cSThierry Escande }
239605ba533cSThierry Escande 
qca_serdev_remove(struct serdev_device * serdev)239705ba533cSThierry Escande static void qca_serdev_remove(struct serdev_device *serdev)
239805ba533cSThierry Escande {
239905ba533cSThierry Escande 	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
2400054ec5e9SVenkata Lakshmi Narayana Gubba 	struct qca_power *power = qcadev->bt_power;
240105ba533cSThierry Escande 
2402691d54d0SNeil Armstrong 	switch (qcadev->btsoc_type) {
2403691d54d0SNeil Armstrong 	case QCA_WCN3988:
2404691d54d0SNeil Armstrong 	case QCA_WCN3990:
2405691d54d0SNeil Armstrong 	case QCA_WCN3991:
2406691d54d0SNeil Armstrong 	case QCA_WCN3998:
2407691d54d0SNeil Armstrong 	case QCA_WCN6750:
2408691d54d0SNeil Armstrong 	case QCA_WCN6855:
2409e0c1278aSNeil Armstrong 	case QCA_WCN7850:
2410691d54d0SNeil Armstrong 		if (power->vregs_on) {
2411c2d78273SBalakrishna Godavarthi 			qca_power_shutdown(&qcadev->serdev_hu);
2412691d54d0SNeil Armstrong 			break;
2413691d54d0SNeil Armstrong 		}
2414691d54d0SNeil Armstrong 		fallthrough;
2415691d54d0SNeil Armstrong 
2416691d54d0SNeil Armstrong 	default:
2417691d54d0SNeil Armstrong 		if (qcadev->susclk)
241805ba533cSThierry Escande 			clk_disable_unprepare(qcadev->susclk);
2419691d54d0SNeil Armstrong 	}
2420fa9ad876SBalakrishna Godavarthi 
2421fa9ad876SBalakrishna Godavarthi 	hci_uart_unregister_device(&qcadev->serdev_hu);
242205ba533cSThierry Escande }
242305ba533cSThierry Escande 
qca_serdev_shutdown(struct device * dev)24247e7bbdddSZijun Hu static void qca_serdev_shutdown(struct device *dev)
24257e7bbdddSZijun Hu {
24267e7bbdddSZijun Hu 	int ret;
24277e7bbdddSZijun Hu 	int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
24287e7bbdddSZijun Hu 	struct serdev_device *serdev = to_serdev_device(dev);
24297e7bbdddSZijun Hu 	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
2430272970beSKrzysztof Kozlowski 	struct hci_uart *hu = &qcadev->serdev_hu;
2431272970beSKrzysztof Kozlowski 	struct hci_dev *hdev = hu->hdev;
24327e7bbdddSZijun Hu 	const u8 ibs_wake_cmd[] = { 0xFD };
24337e7bbdddSZijun Hu 	const u8 edl_reset_soc_cmd[] = { 0x01, 0x00, 0xFC, 0x01, 0x05 };
24347e7bbdddSZijun Hu 
24357e7bbdddSZijun Hu 	if (qcadev->btsoc_type == QCA_QCA6390) {
2436e2d8aa4cSZijun Hu 		/* The purpose of sending the VSC is to reset SOC into a initial
2437e2d8aa4cSZijun Hu 		 * state and the state will ensure next hdev->setup() success.
2438e2d8aa4cSZijun Hu 		 * if HCI_QUIRK_NON_PERSISTENT_SETUP is set, it means that
2439e2d8aa4cSZijun Hu 		 * hdev->setup() can do its job regardless of SoC state, so
2440e2d8aa4cSZijun Hu 		 * don't need to send the VSC.
2441e2d8aa4cSZijun Hu 		 * if HCI_SETUP is set, it means that hdev->setup() was never
2442e2d8aa4cSZijun Hu 		 * invoked and the SOC is already in the initial state, so
2443e2d8aa4cSZijun Hu 		 * don't also need to send the VSC.
2444e2d8aa4cSZijun Hu 		 */
2445e2d8aa4cSZijun Hu 		if (test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks) ||
2446e2d8aa4cSZijun Hu 		    hci_dev_test_flag(hdev, HCI_SETUP))
2447272970beSKrzysztof Kozlowski 			return;
2448272970beSKrzysztof Kozlowski 
2449e2d8aa4cSZijun Hu 		/* The serdev must be in open state when conrol logic arrives
2450e2d8aa4cSZijun Hu 		 * here, so also fix the use-after-free issue caused by that
2451e2d8aa4cSZijun Hu 		 * the serdev is flushed or wrote after it is closed.
2452e2d8aa4cSZijun Hu 		 */
24537e7bbdddSZijun Hu 		serdev_device_write_flush(serdev);
24547e7bbdddSZijun Hu 		ret = serdev_device_write_buf(serdev, ibs_wake_cmd,
24557e7bbdddSZijun Hu 					      sizeof(ibs_wake_cmd));
24567e7bbdddSZijun Hu 		if (ret < 0) {
24577e7bbdddSZijun Hu 			BT_ERR("QCA send IBS_WAKE_IND error: %d", ret);
24587e7bbdddSZijun Hu 			return;
24597e7bbdddSZijun Hu 		}
24607e7bbdddSZijun Hu 		serdev_device_wait_until_sent(serdev, timeout);
24617e7bbdddSZijun Hu 		usleep_range(8000, 10000);
24627e7bbdddSZijun Hu 
24637e7bbdddSZijun Hu 		serdev_device_write_flush(serdev);
24647e7bbdddSZijun Hu 		ret = serdev_device_write_buf(serdev, edl_reset_soc_cmd,
24657e7bbdddSZijun Hu 					      sizeof(edl_reset_soc_cmd));
24667e7bbdddSZijun Hu 		if (ret < 0) {
24677e7bbdddSZijun Hu 			BT_ERR("QCA send EDL_RESET_REQ error: %d", ret);
24687e7bbdddSZijun Hu 			return;
24697e7bbdddSZijun Hu 		}
24707e7bbdddSZijun Hu 		serdev_device_wait_until_sent(serdev, timeout);
24717e7bbdddSZijun Hu 		usleep_range(8000, 10000);
24727e7bbdddSZijun Hu 	}
24737e7bbdddSZijun Hu }
24747e7bbdddSZijun Hu 
qca_suspend(struct device * dev)247541d5b25fSClaire Chang static int __maybe_unused qca_suspend(struct device *dev)
247641d5b25fSClaire Chang {
2477feac90d7SZijun Hu 	struct serdev_device *serdev = to_serdev_device(dev);
2478feac90d7SZijun Hu 	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
2479feac90d7SZijun Hu 	struct hci_uart *hu = &qcadev->serdev_hu;
248041d5b25fSClaire Chang 	struct qca_data *qca = hu->priv;
248141d5b25fSClaire Chang 	unsigned long flags;
2482e2a119cdSMatthias Kaehlcke 	bool tx_pending = false;
248341d5b25fSClaire Chang 	int ret = 0;
248441d5b25fSClaire Chang 	u8 cmd;
24852be43abaSVenkata Lakshmi Narayana Gubba 	u32 wait_timeout = 0;
248641d5b25fSClaire Chang 
248741d5b25fSClaire Chang 	set_bit(QCA_SUSPENDING, &qca->flags);
248841d5b25fSClaire Chang 
248955c0bd77SVenkata Lakshmi Narayana Gubba 	/* if BT SoC is running with default firmware then it does not
249055c0bd77SVenkata Lakshmi Narayana Gubba 	 * support in-band sleep
249155c0bd77SVenkata Lakshmi Narayana Gubba 	 */
249255c0bd77SVenkata Lakshmi Narayana Gubba 	if (test_bit(QCA_ROM_FW, &qca->flags))
249355c0bd77SVenkata Lakshmi Narayana Gubba 		return 0;
249455c0bd77SVenkata Lakshmi Narayana Gubba 
2495ad3a9c0eSVenkata Lakshmi Narayana Gubba 	/* During SSR after memory dump collection, controller will be
2496ad3a9c0eSVenkata Lakshmi Narayana Gubba 	 * powered off and then powered on.If controller is powered off
2497ad3a9c0eSVenkata Lakshmi Narayana Gubba 	 * during SSR then we should wait until SSR is completed.
2498ad3a9c0eSVenkata Lakshmi Narayana Gubba 	 */
2499ad3a9c0eSVenkata Lakshmi Narayana Gubba 	if (test_bit(QCA_BT_OFF, &qca->flags) &&
2500ad3a9c0eSVenkata Lakshmi Narayana Gubba 	    !test_bit(QCA_SSR_TRIGGERED, &qca->flags))
25012be43abaSVenkata Lakshmi Narayana Gubba 		return 0;
25022be43abaSVenkata Lakshmi Narayana Gubba 
25031bb0c663SVenkata Lakshmi Narayana Gubba 	if (test_bit(QCA_IBS_DISABLED, &qca->flags) ||
25041bb0c663SVenkata Lakshmi Narayana Gubba 	    test_bit(QCA_SSR_TRIGGERED, &qca->flags)) {
25052be43abaSVenkata Lakshmi Narayana Gubba 		wait_timeout = test_bit(QCA_SSR_TRIGGERED, &qca->flags) ?
25062be43abaSVenkata Lakshmi Narayana Gubba 					IBS_DISABLE_SSR_TIMEOUT_MS :
25072be43abaSVenkata Lakshmi Narayana Gubba 					FW_DOWNLOAD_TIMEOUT_MS;
25082be43abaSVenkata Lakshmi Narayana Gubba 
25092be43abaSVenkata Lakshmi Narayana Gubba 		/* QCA_IBS_DISABLED flag is set to true, During FW download
25102be43abaSVenkata Lakshmi Narayana Gubba 		 * and during memory dump collection. It is reset to false,
2511ad3a9c0eSVenkata Lakshmi Narayana Gubba 		 * After FW download complete.
25122be43abaSVenkata Lakshmi Narayana Gubba 		 */
25132be43abaSVenkata Lakshmi Narayana Gubba 		wait_on_bit_timeout(&qca->flags, QCA_IBS_DISABLED,
25142be43abaSVenkata Lakshmi Narayana Gubba 			    TASK_UNINTERRUPTIBLE, msecs_to_jiffies(wait_timeout));
25152be43abaSVenkata Lakshmi Narayana Gubba 
25162be43abaSVenkata Lakshmi Narayana Gubba 		if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
25172be43abaSVenkata Lakshmi Narayana Gubba 			bt_dev_err(hu->hdev, "SSR or FW download time out");
25182be43abaSVenkata Lakshmi Narayana Gubba 			ret = -ETIMEDOUT;
25192be43abaSVenkata Lakshmi Narayana Gubba 			goto error;
25202be43abaSVenkata Lakshmi Narayana Gubba 		}
25212be43abaSVenkata Lakshmi Narayana Gubba 	}
25222be43abaSVenkata Lakshmi Narayana Gubba 
252341d5b25fSClaire Chang 	cancel_work_sync(&qca->ws_awake_device);
252441d5b25fSClaire Chang 	cancel_work_sync(&qca->ws_awake_rx);
252541d5b25fSClaire Chang 
252641d5b25fSClaire Chang 	spin_lock_irqsave_nested(&qca->hci_ibs_lock,
252741d5b25fSClaire Chang 				 flags, SINGLE_DEPTH_NESTING);
252841d5b25fSClaire Chang 
252941d5b25fSClaire Chang 	switch (qca->tx_ibs_state) {
253041d5b25fSClaire Chang 	case HCI_IBS_TX_WAKING:
253141d5b25fSClaire Chang 		del_timer(&qca->wake_retrans_timer);
2532a3b4cbfcSGustavo A. R. Silva 		fallthrough;
253341d5b25fSClaire Chang 	case HCI_IBS_TX_AWAKE:
253441d5b25fSClaire Chang 		del_timer(&qca->tx_idle_timer);
253541d5b25fSClaire Chang 
253641d5b25fSClaire Chang 		serdev_device_write_flush(hu->serdev);
253741d5b25fSClaire Chang 		cmd = HCI_IBS_SLEEP_IND;
253841d5b25fSClaire Chang 		ret = serdev_device_write_buf(hu->serdev, &cmd, sizeof(cmd));
253941d5b25fSClaire Chang 
254041d5b25fSClaire Chang 		if (ret < 0) {
254141d5b25fSClaire Chang 			BT_ERR("Failed to send SLEEP to device");
254241d5b25fSClaire Chang 			break;
254341d5b25fSClaire Chang 		}
254441d5b25fSClaire Chang 
254541d5b25fSClaire Chang 		qca->tx_ibs_state = HCI_IBS_TX_ASLEEP;
254641d5b25fSClaire Chang 		qca->ibs_sent_slps++;
2547e2a119cdSMatthias Kaehlcke 		tx_pending = true;
254841d5b25fSClaire Chang 		break;
254941d5b25fSClaire Chang 
255041d5b25fSClaire Chang 	case HCI_IBS_TX_ASLEEP:
255141d5b25fSClaire Chang 		break;
255241d5b25fSClaire Chang 
255341d5b25fSClaire Chang 	default:
255441d5b25fSClaire Chang 		BT_ERR("Spurious tx state %d", qca->tx_ibs_state);
255541d5b25fSClaire Chang 		ret = -EINVAL;
255641d5b25fSClaire Chang 		break;
255741d5b25fSClaire Chang 	}
255841d5b25fSClaire Chang 
255941d5b25fSClaire Chang 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
256041d5b25fSClaire Chang 
256141d5b25fSClaire Chang 	if (ret < 0)
256241d5b25fSClaire Chang 		goto error;
256341d5b25fSClaire Chang 
2564e2a119cdSMatthias Kaehlcke 	if (tx_pending) {
256541d5b25fSClaire Chang 		serdev_device_wait_until_sent(hu->serdev,
256641d5b25fSClaire Chang 					      msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
2567201a1124SBalakrishna Godavarthi 		serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
2568e2a119cdSMatthias Kaehlcke 	}
256941d5b25fSClaire Chang 
257041d5b25fSClaire Chang 	/* Wait for HCI_IBS_SLEEP_IND sent by device to indicate its Tx is going
257141d5b25fSClaire Chang 	 * to sleep, so that the packet does not wake the system later.
257241d5b25fSClaire Chang 	 */
257341d5b25fSClaire Chang 	ret = wait_event_interruptible_timeout(qca->suspend_wait_q,
257441d5b25fSClaire Chang 			qca->rx_ibs_state == HCI_IBS_RX_ASLEEP,
257541d5b25fSClaire Chang 			msecs_to_jiffies(IBS_BTSOC_TX_IDLE_TIMEOUT_MS));
25764da385f7SMatthias Kaehlcke 	if (ret == 0) {
25774da385f7SMatthias Kaehlcke 		ret = -ETIMEDOUT;
25784da385f7SMatthias Kaehlcke 		goto error;
2579eff981f6SMatthias Kaehlcke 	}
258041d5b25fSClaire Chang 
25814da385f7SMatthias Kaehlcke 	return 0;
258241d5b25fSClaire Chang 
258341d5b25fSClaire Chang error:
258441d5b25fSClaire Chang 	clear_bit(QCA_SUSPENDING, &qca->flags);
258541d5b25fSClaire Chang 
258641d5b25fSClaire Chang 	return ret;
258741d5b25fSClaire Chang }
258841d5b25fSClaire Chang 
qca_resume(struct device * dev)258941d5b25fSClaire Chang static int __maybe_unused qca_resume(struct device *dev)
259041d5b25fSClaire Chang {
2591feac90d7SZijun Hu 	struct serdev_device *serdev = to_serdev_device(dev);
2592feac90d7SZijun Hu 	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
2593feac90d7SZijun Hu 	struct hci_uart *hu = &qcadev->serdev_hu;
259441d5b25fSClaire Chang 	struct qca_data *qca = hu->priv;
259541d5b25fSClaire Chang 
259641d5b25fSClaire Chang 	clear_bit(QCA_SUSPENDING, &qca->flags);
259741d5b25fSClaire Chang 
259841d5b25fSClaire Chang 	return 0;
259941d5b25fSClaire Chang }
260041d5b25fSClaire Chang 
260141d5b25fSClaire Chang static SIMPLE_DEV_PM_OPS(qca_pm_ops, qca_suspend, qca_resume);
260241d5b25fSClaire Chang 
2603e5d6468fSRocky Liao #ifdef CONFIG_OF
260405ba533cSThierry Escande static const struct of_device_id qca_bluetooth_of_match[] = {
2605a381ee26STim Jiang 	{ .compatible = "qcom,qca2066-bt", .data = &qca_soc_data_qca2066},
260605ba533cSThierry Escande 	{ .compatible = "qcom,qca6174-bt" },
2607e5d6468fSRocky Liao 	{ .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390},
260831d4ab85SChristian Hewitt 	{ .compatible = "qcom,qca9377-bt" },
2609f904feefSLuca Weiss 	{ .compatible = "qcom,wcn3988-bt", .data = &qca_soc_data_wcn3988},
2610523760b7SHarish Bandi 	{ .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990},
26117d250a06SBalakrishna Godavarthi 	{ .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3991},
2612523760b7SHarish Bandi 	{ .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998},
2613d8f97da1SVenkata Lakshmi Narayana Gubba 	{ .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750},
2614095327feSSteev Klimaszewski 	{ .compatible = "qcom,wcn6855-bt", .data = &qca_soc_data_wcn6855},
2615e0c1278aSNeil Armstrong 	{ .compatible = "qcom,wcn7850-bt", .data = &qca_soc_data_wcn7850},
261605ba533cSThierry Escande 	{ /* sentinel */ }
261705ba533cSThierry Escande };
261805ba533cSThierry Escande MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
2619e5d6468fSRocky Liao #endif
2620e5d6468fSRocky Liao 
2621e5d6468fSRocky Liao #ifdef CONFIG_ACPI
2622e5d6468fSRocky Liao static const struct acpi_device_id qca_bluetooth_acpi_match[] = {
2623a381ee26STim Jiang 	{ "QCOM2066", (kernel_ulong_t)&qca_soc_data_qca2066 },
2624e5d6468fSRocky Liao 	{ "QCOM6390", (kernel_ulong_t)&qca_soc_data_qca6390 },
2625e5d6468fSRocky Liao 	{ "DLA16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
2626e5d6468fSRocky Liao 	{ "DLB16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
2627e5d6468fSRocky Liao 	{ "DLB26390", (kernel_ulong_t)&qca_soc_data_qca6390 },
2628e5d6468fSRocky Liao 	{ },
2629e5d6468fSRocky Liao };
2630e5d6468fSRocky Liao MODULE_DEVICE_TABLE(acpi, qca_bluetooth_acpi_match);
2631e5d6468fSRocky Liao #endif
2632e5d6468fSRocky Liao 
26336ce95a30SSai Teja Aluvala #ifdef CONFIG_DEV_COREDUMP
hciqca_coredump(struct device * dev)26346ce95a30SSai Teja Aluvala static void hciqca_coredump(struct device *dev)
26356ce95a30SSai Teja Aluvala {
26366ce95a30SSai Teja Aluvala 	struct serdev_device *serdev = to_serdev_device(dev);
26376ce95a30SSai Teja Aluvala 	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
26386ce95a30SSai Teja Aluvala 	struct hci_uart *hu = &qcadev->serdev_hu;
26396ce95a30SSai Teja Aluvala 	struct hci_dev  *hdev = hu->hdev;
26406ce95a30SSai Teja Aluvala 
26416ce95a30SSai Teja Aluvala 	if (hdev->dump.coredump)
26426ce95a30SSai Teja Aluvala 		hdev->dump.coredump(hdev);
26436ce95a30SSai Teja Aluvala }
26446ce95a30SSai Teja Aluvala #endif
264505ba533cSThierry Escande 
264605ba533cSThierry Escande static struct serdev_device_driver qca_serdev_driver = {
264705ba533cSThierry Escande 	.probe = qca_serdev_probe,
264805ba533cSThierry Escande 	.remove = qca_serdev_remove,
264905ba533cSThierry Escande 	.driver = {
265005ba533cSThierry Escande 		.name = "hci_uart_qca",
2651e5d6468fSRocky Liao 		.of_match_table = of_match_ptr(qca_bluetooth_of_match),
2652e5d6468fSRocky Liao 		.acpi_match_table = ACPI_PTR(qca_bluetooth_acpi_match),
26537e7bbdddSZijun Hu 		.shutdown = qca_serdev_shutdown,
265441d5b25fSClaire Chang 		.pm = &qca_pm_ops,
26556ce95a30SSai Teja Aluvala #ifdef CONFIG_DEV_COREDUMP
26566ce95a30SSai Teja Aluvala 		.coredump = hciqca_coredump,
26576ce95a30SSai Teja Aluvala #endif
265805ba533cSThierry Escande 	},
265905ba533cSThierry Escande };
266005ba533cSThierry Escande 
qca_init(void)26610ff252c1SBen Young Tae Kim int __init qca_init(void)
26620ff252c1SBen Young Tae Kim {
266305ba533cSThierry Escande 	serdev_device_driver_register(&qca_serdev_driver);
266405ba533cSThierry Escande 
26650ff252c1SBen Young Tae Kim 	return hci_uart_register_proto(&qca_proto);
26660ff252c1SBen Young Tae Kim }
26670ff252c1SBen Young Tae Kim 
qca_deinit(void)26680ff252c1SBen Young Tae Kim int __exit qca_deinit(void)
26690ff252c1SBen Young Tae Kim {
267005ba533cSThierry Escande 	serdev_device_driver_unregister(&qca_serdev_driver);
267105ba533cSThierry Escande 
26720ff252c1SBen Young Tae Kim 	return hci_uart_unregister_proto(&qca_proto);
26730ff252c1SBen Young Tae Kim }
2674