xref: /openbmc/linux/drivers/bluetooth/hci_qca.c (revision 3019a9d3)
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);
10937c2c3e63SVenkata Lakshmi Narayana Gubba 				mutex_unlock(&qca->hci_memdump_lock);
1094d841502cSBalakrishna Godavarthi 				return;
1095d841502cSBalakrishna Godavarthi 			}
1096d841502cSBalakrishna Godavarthi 
1097d841502cSBalakrishna Godavarthi 			bt_dev_info(hu->hdev, "QCA collecting dump of size:%u",
109806d3fdfcSSai Teja Aluvala 				    qca_memdump->ram_dump_size);
1099d841502cSBalakrishna Godavarthi 
1100d841502cSBalakrishna Godavarthi 		}
1101d841502cSBalakrishna Godavarthi 
1102d841502cSBalakrishna Godavarthi 		/* If sequence no 0 is missed then there is no point in
1103d841502cSBalakrishna Godavarthi 		 * accepting the other sequences.
1104d841502cSBalakrishna Godavarthi 		 */
110506d3fdfcSSai Teja Aluvala 		if (!test_bit(QCA_MEMDUMP_COLLECTION, &qca->flags)) {
1106d841502cSBalakrishna Godavarthi 			bt_dev_err(hu->hdev, "QCA: Discarding other packets");
1107d841502cSBalakrishna Godavarthi 			kfree(qca_memdump);
1108d841502cSBalakrishna Godavarthi 			kfree_skb(skb);
11097c2c3e63SVenkata Lakshmi Narayana Gubba 			mutex_unlock(&qca->hci_memdump_lock);
1110d841502cSBalakrishna Godavarthi 			return;
1111d841502cSBalakrishna Godavarthi 		}
1112d841502cSBalakrishna Godavarthi 		/* There could be chance of missing some packets from
1113d841502cSBalakrishna Godavarthi 		 * the controller. In such cases let us store the dummy
1114d841502cSBalakrishna Godavarthi 		 * packets in the buffer.
1115d841502cSBalakrishna Godavarthi 		 */
1116e5aeebddSZijun Hu 		/* For QCA6390, controller does not lost packets but
111707528783SBhaskar Chowdhury 		 * sequence number field of packet sometimes has error
1118e5aeebddSZijun Hu 		 * bits, so skip this checking for missing packet.
1119e5aeebddSZijun Hu 		 */
1120d841502cSBalakrishna Godavarthi 		while ((seq_no > qca_memdump->current_seq_no + 1) &&
1121e5aeebddSZijun Hu 			(soc_type != QCA_QCA6390) &&
1122d841502cSBalakrishna Godavarthi 			seq_no != QCA_LAST_SEQUENCE_NUM) {
1123d841502cSBalakrishna Godavarthi 			bt_dev_err(hu->hdev, "QCA controller missed packet:%d",
1124d841502cSBalakrishna Godavarthi 				   qca_memdump->current_seq_no);
1125e5aeebddSZijun Hu 			rx_size = qca_memdump->received_dump;
1126e5aeebddSZijun Hu 			rx_size += QCA_DUMP_PACKET_SIZE;
1127e5aeebddSZijun Hu 			if (rx_size > qca_memdump->ram_dump_size) {
1128e5aeebddSZijun Hu 				bt_dev_err(hu->hdev,
1129e5aeebddSZijun Hu 					   "QCA memdump received %d, no space for missed packet",
1130e5aeebddSZijun Hu 					   qca_memdump->received_dump);
1131e5aeebddSZijun Hu 				break;
1132e5aeebddSZijun Hu 			}
113306d3fdfcSSai Teja Aluvala 			hci_devcd_append_pattern(hu->hdev, 0x00,
113406d3fdfcSSai Teja Aluvala 				QCA_DUMP_PACKET_SIZE);
1135d841502cSBalakrishna Godavarthi 			qca_memdump->received_dump += QCA_DUMP_PACKET_SIZE;
1136d841502cSBalakrishna Godavarthi 			qca_memdump->current_seq_no++;
1137d841502cSBalakrishna Godavarthi 		}
1138d841502cSBalakrishna Godavarthi 
1139e5aeebddSZijun Hu 		rx_size = qca_memdump->received_dump  + skb->len;
1140e5aeebddSZijun Hu 		if (rx_size <= qca_memdump->ram_dump_size) {
1141e5aeebddSZijun Hu 			if ((seq_no != QCA_LAST_SEQUENCE_NUM) &&
114206d3fdfcSSai Teja Aluvala 			    (seq_no != qca_memdump->current_seq_no)) {
1143e5aeebddSZijun Hu 				bt_dev_err(hu->hdev,
1144e5aeebddSZijun Hu 					   "QCA memdump unexpected packet %d",
1145e5aeebddSZijun Hu 					   seq_no);
114606d3fdfcSSai Teja Aluvala 			}
1147e5aeebddSZijun Hu 			bt_dev_dbg(hu->hdev,
1148e5aeebddSZijun Hu 				   "QCA memdump packet %d with length %d",
1149e5aeebddSZijun Hu 				   seq_no, skb->len);
115006d3fdfcSSai Teja Aluvala 			hci_devcd_append(hu->hdev, skb);
115106d3fdfcSSai Teja Aluvala 			qca_memdump->current_seq_no += 1;
115206d3fdfcSSai Teja Aluvala 			qca_memdump->received_dump = rx_size;
1153e5aeebddSZijun Hu 		} else {
1154e5aeebddSZijun Hu 			bt_dev_err(hu->hdev,
115506d3fdfcSSai Teja Aluvala 				   "QCA memdump received no space for packet %d",
115606d3fdfcSSai Teja Aluvala 				    qca_memdump->current_seq_no);
1157e5aeebddSZijun Hu 		}
115806d3fdfcSSai Teja Aluvala 
1159d841502cSBalakrishna Godavarthi 		if (seq_no == QCA_LAST_SEQUENCE_NUM) {
1160e5aeebddSZijun Hu 			bt_dev_info(hu->hdev,
1161e5aeebddSZijun Hu 				"QCA memdump Done, received %d, total %d",
1162e5aeebddSZijun Hu 				qca_memdump->received_dump,
1163e5aeebddSZijun Hu 				qca_memdump->ram_dump_size);
116406d3fdfcSSai Teja Aluvala 			hci_devcd_complete(hu->hdev);
11657c2c3e63SVenkata Lakshmi Narayana Gubba 			cancel_delayed_work(&qca->ctrl_memdump_timeout);
1166d841502cSBalakrishna Godavarthi 			kfree(qca->qca_memdump);
1167d841502cSBalakrishna Godavarthi 			qca->qca_memdump = NULL;
1168d841502cSBalakrishna Godavarthi 			qca->memdump_state = QCA_MEMDUMP_COLLECTED;
11697c2c3e63SVenkata Lakshmi Narayana Gubba 			clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
1170d841502cSBalakrishna Godavarthi 		}
11717c2c3e63SVenkata Lakshmi Narayana Gubba 
11727c2c3e63SVenkata Lakshmi Narayana Gubba 		mutex_unlock(&qca->hci_memdump_lock);
1173d841502cSBalakrishna Godavarthi 	}
1174d841502cSBalakrishna Godavarthi 
1175d841502cSBalakrishna Godavarthi }
1176d841502cSBalakrishna Godavarthi 
qca_controller_memdump_event(struct hci_dev * hdev,struct sk_buff * skb)11777c2c3e63SVenkata Lakshmi Narayana Gubba static int qca_controller_memdump_event(struct hci_dev *hdev,
11787c2c3e63SVenkata Lakshmi Narayana Gubba 					struct sk_buff *skb)
1179d841502cSBalakrishna Godavarthi {
1180d841502cSBalakrishna Godavarthi 	struct hci_uart *hu = hci_get_drvdata(hdev);
1181d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
1182d841502cSBalakrishna Godavarthi 
11833344537fSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_SSR_TRIGGERED, &qca->flags);
1184d841502cSBalakrishna Godavarthi 	skb_queue_tail(&qca->rx_memdump_q, skb);
1185d841502cSBalakrishna Godavarthi 	queue_work(qca->workqueue, &qca->ctrl_memdump_evt);
1186d841502cSBalakrishna Godavarthi 
1187d841502cSBalakrishna Godavarthi 	return 0;
1188d841502cSBalakrishna Godavarthi }
1189d841502cSBalakrishna Godavarthi 
qca_recv_event(struct hci_dev * hdev,struct sk_buff * skb)11902faa3f15SMatthias Kaehlcke static int qca_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
11912faa3f15SMatthias Kaehlcke {
11922faa3f15SMatthias Kaehlcke 	struct hci_uart *hu = hci_get_drvdata(hdev);
11932faa3f15SMatthias Kaehlcke 	struct qca_data *qca = hu->priv;
11942faa3f15SMatthias Kaehlcke 
11952faa3f15SMatthias Kaehlcke 	if (test_bit(QCA_DROP_VENDOR_EVENT, &qca->flags)) {
11962faa3f15SMatthias Kaehlcke 		struct hci_event_hdr *hdr = (void *)skb->data;
11972faa3f15SMatthias Kaehlcke 
11982faa3f15SMatthias Kaehlcke 		/* For the WCN3990 the vendor command for a baudrate change
11992faa3f15SMatthias Kaehlcke 		 * isn't sent as synchronous HCI command, because the
12002faa3f15SMatthias Kaehlcke 		 * controller sends the corresponding vendor event with the
12012faa3f15SMatthias Kaehlcke 		 * new baudrate. The event is received and properly decoded
12022faa3f15SMatthias Kaehlcke 		 * after changing the baudrate of the host port. It needs to
12032faa3f15SMatthias Kaehlcke 		 * be dropped, otherwise it can be misinterpreted as
12042faa3f15SMatthias Kaehlcke 		 * response to a later firmware download command (also a
12052faa3f15SMatthias Kaehlcke 		 * vendor command).
12062faa3f15SMatthias Kaehlcke 		 */
12072faa3f15SMatthias Kaehlcke 
12082faa3f15SMatthias Kaehlcke 		if (hdr->evt == HCI_EV_VENDOR)
12092faa3f15SMatthias Kaehlcke 			complete(&qca->drop_ev_comp);
12102faa3f15SMatthias Kaehlcke 
12114974c839SWei Yongjun 		kfree_skb(skb);
12122faa3f15SMatthias Kaehlcke 
12132faa3f15SMatthias Kaehlcke 		return 0;
12142faa3f15SMatthias Kaehlcke 	}
1215d841502cSBalakrishna Godavarthi 	/* We receive chip memory dump as an event packet, With a dedicated
1216d841502cSBalakrishna Godavarthi 	 * handler followed by a hardware error event. When this event is
1217d841502cSBalakrishna Godavarthi 	 * received we store dump into a file before closing hci. This
1218d841502cSBalakrishna Godavarthi 	 * dump will help in triaging the issues.
1219d841502cSBalakrishna Godavarthi 	 */
1220d841502cSBalakrishna Godavarthi 	if ((skb->data[0] == HCI_VENDOR_PKT) &&
1221d841502cSBalakrishna Godavarthi 	    (get_unaligned_be16(skb->data + 2) == QCA_SSR_DUMP_HANDLE))
1222d841502cSBalakrishna Godavarthi 		return qca_controller_memdump_event(hdev, skb);
12232faa3f15SMatthias Kaehlcke 
12242faa3f15SMatthias Kaehlcke 	return hci_recv_frame(hdev, skb);
12252faa3f15SMatthias Kaehlcke }
12262faa3f15SMatthias Kaehlcke 
12270ff252c1SBen Young Tae Kim #define QCA_IBS_SLEEP_IND_EVENT \
12280ff252c1SBen Young Tae Kim 	.type = HCI_IBS_SLEEP_IND, \
12290ff252c1SBen Young Tae Kim 	.hlen = 0, \
12300ff252c1SBen Young Tae Kim 	.loff = 0, \
12310ff252c1SBen Young Tae Kim 	.lsize = 0, \
12320ff252c1SBen Young Tae Kim 	.maxlen = HCI_MAX_IBS_SIZE
12330ff252c1SBen Young Tae Kim 
12340ff252c1SBen Young Tae Kim #define QCA_IBS_WAKE_IND_EVENT \
12350ff252c1SBen Young Tae Kim 	.type = HCI_IBS_WAKE_IND, \
12360ff252c1SBen Young Tae Kim 	.hlen = 0, \
12370ff252c1SBen Young Tae Kim 	.loff = 0, \
12380ff252c1SBen Young Tae Kim 	.lsize = 0, \
12390ff252c1SBen Young Tae Kim 	.maxlen = HCI_MAX_IBS_SIZE
12400ff252c1SBen Young Tae Kim 
12410ff252c1SBen Young Tae Kim #define QCA_IBS_WAKE_ACK_EVENT \
12420ff252c1SBen Young Tae Kim 	.type = HCI_IBS_WAKE_ACK, \
12430ff252c1SBen Young Tae Kim 	.hlen = 0, \
12440ff252c1SBen Young Tae Kim 	.loff = 0, \
12450ff252c1SBen Young Tae Kim 	.lsize = 0, \
12460ff252c1SBen Young Tae Kim 	.maxlen = HCI_MAX_IBS_SIZE
12470ff252c1SBen Young Tae Kim 
12480ff252c1SBen Young Tae Kim static const struct h4_recv_pkt qca_recv_pkts[] = {
1249c614ca3fSBalakrishna Godavarthi 	{ H4_RECV_ACL,             .recv = qca_recv_acl_data },
12500ff252c1SBen Young Tae Kim 	{ H4_RECV_SCO,             .recv = hci_recv_frame    },
12512faa3f15SMatthias Kaehlcke 	{ H4_RECV_EVENT,           .recv = qca_recv_event    },
12520ff252c1SBen Young Tae Kim 	{ QCA_IBS_WAKE_IND_EVENT,  .recv = qca_ibs_wake_ind  },
12530ff252c1SBen Young Tae Kim 	{ QCA_IBS_WAKE_ACK_EVENT,  .recv = qca_ibs_wake_ack  },
12540ff252c1SBen Young Tae Kim 	{ QCA_IBS_SLEEP_IND_EVENT, .recv = qca_ibs_sleep_ind },
12550ff252c1SBen Young Tae Kim };
12560ff252c1SBen Young Tae Kim 
qca_recv(struct hci_uart * hu,const void * data,int count)12570ff252c1SBen Young Tae Kim static int qca_recv(struct hci_uart *hu, const void *data, int count)
12580ff252c1SBen Young Tae Kim {
12590ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
12600ff252c1SBen Young Tae Kim 
12610ff252c1SBen Young Tae Kim 	if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
12620ff252c1SBen Young Tae Kim 		return -EUNATCH;
12630ff252c1SBen Young Tae Kim 
12640ff252c1SBen Young Tae Kim 	qca->rx_skb = h4_recv_buf(hu->hdev, qca->rx_skb, data, count,
12650ff252c1SBen Young Tae Kim 				  qca_recv_pkts, ARRAY_SIZE(qca_recv_pkts));
12660ff252c1SBen Young Tae Kim 	if (IS_ERR(qca->rx_skb)) {
12670ff252c1SBen Young Tae Kim 		int err = PTR_ERR(qca->rx_skb);
12682064ee33SMarcel Holtmann 		bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
12690ff252c1SBen Young Tae Kim 		qca->rx_skb = NULL;
12700ff252c1SBen Young Tae Kim 		return err;
12710ff252c1SBen Young Tae Kim 	}
12720ff252c1SBen Young Tae Kim 
12730ff252c1SBen Young Tae Kim 	return count;
12740ff252c1SBen Young Tae Kim }
12750ff252c1SBen Young Tae Kim 
qca_dequeue(struct hci_uart * hu)12760ff252c1SBen Young Tae Kim static struct sk_buff *qca_dequeue(struct hci_uart *hu)
12770ff252c1SBen Young Tae Kim {
12780ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
12790ff252c1SBen Young Tae Kim 
12800ff252c1SBen Young Tae Kim 	return skb_dequeue(&qca->txq);
12810ff252c1SBen Young Tae Kim }
12820ff252c1SBen Young Tae Kim 
qca_get_baudrate_value(int speed)12830ff252c1SBen Young Tae Kim static uint8_t qca_get_baudrate_value(int speed)
12840ff252c1SBen Young Tae Kim {
12850ff252c1SBen Young Tae Kim 	switch (speed) {
12860ff252c1SBen Young Tae Kim 	case 9600:
12870ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_9600;
12880ff252c1SBen Young Tae Kim 	case 19200:
12890ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_19200;
12900ff252c1SBen Young Tae Kim 	case 38400:
12910ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_38400;
12920ff252c1SBen Young Tae Kim 	case 57600:
12930ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_57600;
12940ff252c1SBen Young Tae Kim 	case 115200:
12950ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_115200;
12960ff252c1SBen Young Tae Kim 	case 230400:
12970ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_230400;
12980ff252c1SBen Young Tae Kim 	case 460800:
12990ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_460800;
13000ff252c1SBen Young Tae Kim 	case 500000:
13010ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_500000;
13020ff252c1SBen Young Tae Kim 	case 921600:
13030ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_921600;
13040ff252c1SBen Young Tae Kim 	case 1000000:
13050ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_1000000;
13060ff252c1SBen Young Tae Kim 	case 2000000:
13070ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_2000000;
13080ff252c1SBen Young Tae Kim 	case 3000000:
13090ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_3000000;
1310be93a497SBalakrishna Godavarthi 	case 3200000:
1311be93a497SBalakrishna Godavarthi 		return QCA_BAUDRATE_3200000;
13120ff252c1SBen Young Tae Kim 	case 3500000:
13130ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_3500000;
13140ff252c1SBen Young Tae Kim 	default:
13150ff252c1SBen Young Tae Kim 		return QCA_BAUDRATE_115200;
13160ff252c1SBen Young Tae Kim 	}
13170ff252c1SBen Young Tae Kim }
13180ff252c1SBen Young Tae Kim 
qca_set_baudrate(struct hci_dev * hdev,uint8_t baudrate)13190ff252c1SBen Young Tae Kim static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
13200ff252c1SBen Young Tae Kim {
13210ff252c1SBen Young Tae Kim 	struct hci_uart *hu = hci_get_drvdata(hdev);
13220ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
13230ff252c1SBen Young Tae Kim 	struct sk_buff *skb;
13240ff252c1SBen Young Tae Kim 	u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
13250ff252c1SBen Young Tae Kim 
1326be93a497SBalakrishna Godavarthi 	if (baudrate > QCA_BAUDRATE_3200000)
13270ff252c1SBen Young Tae Kim 		return -EINVAL;
13280ff252c1SBen Young Tae Kim 
13290ff252c1SBen Young Tae Kim 	cmd[4] = baudrate;
13300ff252c1SBen Young Tae Kim 
133125a13e38SJia-Ju Bai 	skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
13320ff252c1SBen Young Tae Kim 	if (!skb) {
13332064ee33SMarcel Holtmann 		bt_dev_err(hdev, "Failed to allocate baudrate packet");
13340ff252c1SBen Young Tae Kim 		return -ENOMEM;
13350ff252c1SBen Young Tae Kim 	}
13360ff252c1SBen Young Tae Kim 
13370ff252c1SBen Young Tae Kim 	/* Assign commands to change baudrate and packet type. */
133859ae1d12SJohannes Berg 	skb_put_data(skb, cmd, sizeof(cmd));
1339618e8bc2SMarcel Holtmann 	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
13400ff252c1SBen Young Tae Kim 
13410ff252c1SBen Young Tae Kim 	skb_queue_tail(&qca->txq, skb);
13420ff252c1SBen Young Tae Kim 	hci_uart_tx_wakeup(hu);
13430ff252c1SBen Young Tae Kim 
134494d66714SMatthias Kaehlcke 	/* Wait for the baudrate change request to be sent */
134594d66714SMatthias Kaehlcke 
134694d66714SMatthias Kaehlcke 	while (!skb_queue_empty(&qca->txq))
134794d66714SMatthias Kaehlcke 		usleep_range(100, 200);
134894d66714SMatthias Kaehlcke 
1349ecf2b768SMatthias Kaehlcke 	if (hu->serdev)
135094d66714SMatthias Kaehlcke 		serdev_device_wait_until_sent(hu->serdev,
135194d66714SMatthias Kaehlcke 		      msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
135294d66714SMatthias Kaehlcke 
135394d66714SMatthias Kaehlcke 	/* Give the controller time to process the request */
1354691d54d0SNeil Armstrong 	switch (qca_soc_type(hu)) {
1355691d54d0SNeil Armstrong 	case QCA_WCN3988:
1356691d54d0SNeil Armstrong 	case QCA_WCN3990:
1357691d54d0SNeil Armstrong 	case QCA_WCN3991:
1358691d54d0SNeil Armstrong 	case QCA_WCN3998:
1359691d54d0SNeil Armstrong 	case QCA_WCN6750:
1360691d54d0SNeil Armstrong 	case QCA_WCN6855:
1361e0c1278aSNeil Armstrong 	case QCA_WCN7850:
136299719449SNigel Christian 		usleep_range(1000, 10000);
1363691d54d0SNeil Armstrong 		break;
1364691d54d0SNeil Armstrong 
1365691d54d0SNeil Armstrong 	default:
136694d66714SMatthias Kaehlcke 		msleep(300);
1367691d54d0SNeil Armstrong 	}
13680ff252c1SBen Young Tae Kim 
13690ff252c1SBen Young Tae Kim 	return 0;
13700ff252c1SBen Young Tae Kim }
13710ff252c1SBen Young Tae Kim 
host_set_baudrate(struct hci_uart * hu,unsigned int speed)137205ba533cSThierry Escande static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed)
137305ba533cSThierry Escande {
137405ba533cSThierry Escande 	if (hu->serdev)
137505ba533cSThierry Escande 		serdev_device_set_baudrate(hu->serdev, speed);
137605ba533cSThierry Escande 	else
137705ba533cSThierry Escande 		hci_uart_set_baudrate(hu, speed);
137805ba533cSThierry Escande }
137905ba533cSThierry Escande 
qca_send_power_pulse(struct hci_uart * hu,bool on)13809836b802SMatthias Kaehlcke static int qca_send_power_pulse(struct hci_uart *hu, bool on)
1381fa9ad876SBalakrishna Godavarthi {
1382f9558270SBalakrishna Godavarthi 	int ret;
138394d66714SMatthias Kaehlcke 	int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
13849836b802SMatthias Kaehlcke 	u8 cmd = on ? QCA_WCN3990_POWERON_PULSE : QCA_WCN3990_POWEROFF_PULSE;
1385fa9ad876SBalakrishna Godavarthi 
1386fa9ad876SBalakrishna Godavarthi 	/* These power pulses are single byte command which are sent
1387fa9ad876SBalakrishna Godavarthi 	 * at required baudrate to wcn3990. On wcn3990, we have an external
1388fa9ad876SBalakrishna Godavarthi 	 * circuit at Tx pin which decodes the pulse sent at specific baudrate.
1389fa9ad876SBalakrishna Godavarthi 	 * For example, wcn3990 supports RF COEX antenna for both Wi-Fi/BT
1390fa9ad876SBalakrishna Godavarthi 	 * and also we use the same power inputs to turn on and off for
1391fa9ad876SBalakrishna Godavarthi 	 * Wi-Fi/BT. Powering up the power sources will not enable BT, until
1392fa9ad876SBalakrishna Godavarthi 	 * we send a power on pulse at 115200 bps. This algorithm will help to
1393fa9ad876SBalakrishna Godavarthi 	 * save power. Disabling hardware flow control is mandatory while
1394fa9ad876SBalakrishna Godavarthi 	 * sending power pulses to SoC.
1395fa9ad876SBalakrishna Godavarthi 	 */
1396f9558270SBalakrishna Godavarthi 	bt_dev_dbg(hu->hdev, "sending power pulse %02x to controller", cmd);
1397fa9ad876SBalakrishna Godavarthi 
1398f9558270SBalakrishna Godavarthi 	serdev_device_write_flush(hu->serdev);
1399fa9ad876SBalakrishna Godavarthi 	hci_uart_set_flow_control(hu, true);
1400f9558270SBalakrishna Godavarthi 	ret = serdev_device_write_buf(hu->serdev, &cmd, sizeof(cmd));
1401f9558270SBalakrishna Godavarthi 	if (ret < 0) {
1402f9558270SBalakrishna Godavarthi 		bt_dev_err(hu->hdev, "failed to send power pulse %02x", cmd);
1403f9558270SBalakrishna Godavarthi 		return ret;
1404f9558270SBalakrishna Godavarthi 	}
1405fa9ad876SBalakrishna Godavarthi 
1406f9558270SBalakrishna Godavarthi 	serdev_device_wait_until_sent(hu->serdev, timeout);
1407fa9ad876SBalakrishna Godavarthi 	hci_uart_set_flow_control(hu, false);
1408fa9ad876SBalakrishna Godavarthi 
14090ebcddd8SMatthias Kaehlcke 	/* Give to controller time to boot/shutdown */
1410ad571d72SMatthias Kaehlcke 	if (on)
1411ad571d72SMatthias Kaehlcke 		msleep(100);
14120ebcddd8SMatthias Kaehlcke 	else
141399719449SNigel Christian 		usleep_range(1000, 10000);
1414ad571d72SMatthias Kaehlcke 
1415fa9ad876SBalakrishna Godavarthi 	return 0;
1416fa9ad876SBalakrishna Godavarthi }
1417fa9ad876SBalakrishna Godavarthi 
qca_get_speed(struct hci_uart * hu,enum qca_speed_type speed_type)141883d9c5e5SBalakrishna Godavarthi static unsigned int qca_get_speed(struct hci_uart *hu,
141983d9c5e5SBalakrishna Godavarthi 				  enum qca_speed_type speed_type)
142083d9c5e5SBalakrishna Godavarthi {
142183d9c5e5SBalakrishna Godavarthi 	unsigned int speed = 0;
142283d9c5e5SBalakrishna Godavarthi 
142383d9c5e5SBalakrishna Godavarthi 	if (speed_type == QCA_INIT_SPEED) {
142483d9c5e5SBalakrishna Godavarthi 		if (hu->init_speed)
142583d9c5e5SBalakrishna Godavarthi 			speed = hu->init_speed;
142683d9c5e5SBalakrishna Godavarthi 		else if (hu->proto->init_speed)
142783d9c5e5SBalakrishna Godavarthi 			speed = hu->proto->init_speed;
142883d9c5e5SBalakrishna Godavarthi 	} else {
142983d9c5e5SBalakrishna Godavarthi 		if (hu->oper_speed)
143083d9c5e5SBalakrishna Godavarthi 			speed = hu->oper_speed;
143183d9c5e5SBalakrishna Godavarthi 		else if (hu->proto->oper_speed)
143283d9c5e5SBalakrishna Godavarthi 			speed = hu->proto->oper_speed;
143383d9c5e5SBalakrishna Godavarthi 	}
143483d9c5e5SBalakrishna Godavarthi 
143583d9c5e5SBalakrishna Godavarthi 	return speed;
143683d9c5e5SBalakrishna Godavarthi }
143783d9c5e5SBalakrishna Godavarthi 
qca_check_speeds(struct hci_uart * hu)143883d9c5e5SBalakrishna Godavarthi static int qca_check_speeds(struct hci_uart *hu)
143983d9c5e5SBalakrishna Godavarthi {
1440691d54d0SNeil Armstrong 	switch (qca_soc_type(hu)) {
1441691d54d0SNeil Armstrong 	case QCA_WCN3988:
1442691d54d0SNeil Armstrong 	case QCA_WCN3990:
1443691d54d0SNeil Armstrong 	case QCA_WCN3991:
1444691d54d0SNeil Armstrong 	case QCA_WCN3998:
1445691d54d0SNeil Armstrong 	case QCA_WCN6750:
1446691d54d0SNeil Armstrong 	case QCA_WCN6855:
1447e0c1278aSNeil Armstrong 	case QCA_WCN7850:
1448fa9ad876SBalakrishna Godavarthi 		if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
1449fa9ad876SBalakrishna Godavarthi 		    !qca_get_speed(hu, QCA_OPER_SPEED))
1450fa9ad876SBalakrishna Godavarthi 			return -EINVAL;
1451691d54d0SNeil Armstrong 		break;
1452691d54d0SNeil Armstrong 
1453691d54d0SNeil Armstrong 	default:
145483d9c5e5SBalakrishna Godavarthi 		if (!qca_get_speed(hu, QCA_INIT_SPEED) ||
145583d9c5e5SBalakrishna Godavarthi 		    !qca_get_speed(hu, QCA_OPER_SPEED))
145683d9c5e5SBalakrishna Godavarthi 			return -EINVAL;
1457fa9ad876SBalakrishna Godavarthi 	}
145883d9c5e5SBalakrishna Godavarthi 
145983d9c5e5SBalakrishna Godavarthi 	return 0;
146083d9c5e5SBalakrishna Godavarthi }
146183d9c5e5SBalakrishna Godavarthi 
qca_set_speed(struct hci_uart * hu,enum qca_speed_type speed_type)146283d9c5e5SBalakrishna Godavarthi static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
146383d9c5e5SBalakrishna Godavarthi {
146483d9c5e5SBalakrishna Godavarthi 	unsigned int speed, qca_baudrate;
14652faa3f15SMatthias Kaehlcke 	struct qca_data *qca = hu->priv;
146678e8fa29SBalakrishna Godavarthi 	int ret = 0;
146783d9c5e5SBalakrishna Godavarthi 
146883d9c5e5SBalakrishna Godavarthi 	if (speed_type == QCA_INIT_SPEED) {
146983d9c5e5SBalakrishna Godavarthi 		speed = qca_get_speed(hu, QCA_INIT_SPEED);
147083d9c5e5SBalakrishna Godavarthi 		if (speed)
147183d9c5e5SBalakrishna Godavarthi 			host_set_baudrate(hu, speed);
147283d9c5e5SBalakrishna Godavarthi 	} else {
14734fdd5a4fSMatthias Kaehlcke 		enum qca_btsoc_type soc_type = qca_soc_type(hu);
14744fdd5a4fSMatthias Kaehlcke 
147583d9c5e5SBalakrishna Godavarthi 		speed = qca_get_speed(hu, QCA_OPER_SPEED);
147683d9c5e5SBalakrishna Godavarthi 		if (!speed)
147783d9c5e5SBalakrishna Godavarthi 			return 0;
147883d9c5e5SBalakrishna Godavarthi 
147978e8fa29SBalakrishna Godavarthi 		/* Disable flow control for wcn3990 to deassert RTS while
148078e8fa29SBalakrishna Godavarthi 		 * changing the baudrate of chip and host.
148178e8fa29SBalakrishna Godavarthi 		 */
1482691d54d0SNeil Armstrong 		switch (soc_type) {
1483691d54d0SNeil Armstrong 		case QCA_WCN3988:
1484691d54d0SNeil Armstrong 		case QCA_WCN3990:
1485691d54d0SNeil Armstrong 		case QCA_WCN3991:
1486691d54d0SNeil Armstrong 		case QCA_WCN3998:
1487691d54d0SNeil Armstrong 		case QCA_WCN6750:
1488691d54d0SNeil Armstrong 		case QCA_WCN6855:
1489e0c1278aSNeil Armstrong 		case QCA_WCN7850:
149078e8fa29SBalakrishna Godavarthi 			hci_uart_set_flow_control(hu, true);
1491691d54d0SNeil Armstrong 			break;
149278e8fa29SBalakrishna Godavarthi 
1493691d54d0SNeil Armstrong 		default:
1494691d54d0SNeil Armstrong 			break;
1495691d54d0SNeil Armstrong 		}
1496691d54d0SNeil Armstrong 
1497691d54d0SNeil Armstrong 		switch (soc_type) {
1498691d54d0SNeil Armstrong 		case QCA_WCN3990:
14992faa3f15SMatthias Kaehlcke 			reinit_completion(&qca->drop_ev_comp);
15002faa3f15SMatthias Kaehlcke 			set_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
1501691d54d0SNeil Armstrong 			break;
1502691d54d0SNeil Armstrong 
1503691d54d0SNeil Armstrong 		default:
1504691d54d0SNeil Armstrong 			break;
15052faa3f15SMatthias Kaehlcke 		}
15062faa3f15SMatthias Kaehlcke 
150783d9c5e5SBalakrishna Godavarthi 		qca_baudrate = qca_get_baudrate_value(speed);
1508fa9ad876SBalakrishna Godavarthi 		bt_dev_dbg(hu->hdev, "Set UART speed to %d", speed);
150983d9c5e5SBalakrishna Godavarthi 		ret = qca_set_baudrate(hu->hdev, qca_baudrate);
151083d9c5e5SBalakrishna Godavarthi 		if (ret)
151178e8fa29SBalakrishna Godavarthi 			goto error;
151283d9c5e5SBalakrishna Godavarthi 
151383d9c5e5SBalakrishna Godavarthi 		host_set_baudrate(hu, speed);
151478e8fa29SBalakrishna Godavarthi 
151578e8fa29SBalakrishna Godavarthi error:
1516691d54d0SNeil Armstrong 		switch (soc_type) {
1517691d54d0SNeil Armstrong 		case QCA_WCN3988:
1518691d54d0SNeil Armstrong 		case QCA_WCN3990:
1519691d54d0SNeil Armstrong 		case QCA_WCN3991:
1520691d54d0SNeil Armstrong 		case QCA_WCN3998:
1521691d54d0SNeil Armstrong 		case QCA_WCN6750:
1522691d54d0SNeil Armstrong 		case QCA_WCN6855:
1523e0c1278aSNeil Armstrong 		case QCA_WCN7850:
152478e8fa29SBalakrishna Godavarthi 			hci_uart_set_flow_control(hu, false);
1525691d54d0SNeil Armstrong 			break;
15262faa3f15SMatthias Kaehlcke 
1527691d54d0SNeil Armstrong 		default:
1528691d54d0SNeil Armstrong 			break;
1529691d54d0SNeil Armstrong 		}
1530691d54d0SNeil Armstrong 
1531691d54d0SNeil Armstrong 		switch (soc_type) {
1532691d54d0SNeil Armstrong 		case QCA_WCN3990:
15332faa3f15SMatthias Kaehlcke 			/* Wait for the controller to send the vendor event
15342faa3f15SMatthias Kaehlcke 			 * for the baudrate change command.
15352faa3f15SMatthias Kaehlcke 			 */
15362faa3f15SMatthias Kaehlcke 			if (!wait_for_completion_timeout(&qca->drop_ev_comp,
15372faa3f15SMatthias Kaehlcke 						 msecs_to_jiffies(100))) {
15382faa3f15SMatthias Kaehlcke 				bt_dev_err(hu->hdev,
15392faa3f15SMatthias Kaehlcke 					   "Failed to change controller baudrate\n");
15402faa3f15SMatthias Kaehlcke 				ret = -ETIMEDOUT;
15412faa3f15SMatthias Kaehlcke 			}
15422faa3f15SMatthias Kaehlcke 
15432faa3f15SMatthias Kaehlcke 			clear_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
1544691d54d0SNeil Armstrong 			break;
1545691d54d0SNeil Armstrong 
1546691d54d0SNeil Armstrong 		default:
1547691d54d0SNeil Armstrong 			break;
15482faa3f15SMatthias Kaehlcke 		}
154983d9c5e5SBalakrishna Godavarthi 	}
155083d9c5e5SBalakrishna Godavarthi 
155178e8fa29SBalakrishna Godavarthi 	return ret;
155283d9c5e5SBalakrishna Godavarthi }
155383d9c5e5SBalakrishna Godavarthi 
qca_send_crashbuffer(struct hci_uart * hu)1554d841502cSBalakrishna Godavarthi static int qca_send_crashbuffer(struct hci_uart *hu)
1555d841502cSBalakrishna Godavarthi {
1556d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
1557d841502cSBalakrishna Godavarthi 	struct sk_buff *skb;
1558d841502cSBalakrishna Godavarthi 
1559d841502cSBalakrishna Godavarthi 	skb = bt_skb_alloc(QCA_CRASHBYTE_PACKET_LEN, GFP_KERNEL);
1560d841502cSBalakrishna Godavarthi 	if (!skb) {
1561d841502cSBalakrishna Godavarthi 		bt_dev_err(hu->hdev, "Failed to allocate memory for skb packet");
1562d841502cSBalakrishna Godavarthi 		return -ENOMEM;
1563d841502cSBalakrishna Godavarthi 	}
1564d841502cSBalakrishna Godavarthi 
1565d841502cSBalakrishna Godavarthi 	/* We forcefully crash the controller, by sending 0xfb byte for
1566d841502cSBalakrishna Godavarthi 	 * 1024 times. We also might have chance of losing data, To be
1567d841502cSBalakrishna Godavarthi 	 * on safer side we send 1096 bytes to the SoC.
1568d841502cSBalakrishna Godavarthi 	 */
1569d841502cSBalakrishna Godavarthi 	memset(skb_put(skb, QCA_CRASHBYTE_PACKET_LEN), QCA_MEMDUMP_BYTE,
1570d841502cSBalakrishna Godavarthi 	       QCA_CRASHBYTE_PACKET_LEN);
1571d841502cSBalakrishna Godavarthi 	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
1572d841502cSBalakrishna Godavarthi 	bt_dev_info(hu->hdev, "crash the soc to collect controller dump");
1573d841502cSBalakrishna Godavarthi 	skb_queue_tail(&qca->txq, skb);
1574d841502cSBalakrishna Godavarthi 	hci_uart_tx_wakeup(hu);
1575d841502cSBalakrishna Godavarthi 
1576d841502cSBalakrishna Godavarthi 	return 0;
1577d841502cSBalakrishna Godavarthi }
1578d841502cSBalakrishna Godavarthi 
qca_wait_for_dump_collection(struct hci_dev * hdev)1579d841502cSBalakrishna Godavarthi static void qca_wait_for_dump_collection(struct hci_dev *hdev)
1580d841502cSBalakrishna Godavarthi {
1581d841502cSBalakrishna Godavarthi 	struct hci_uart *hu = hci_get_drvdata(hdev);
1582d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
1583d841502cSBalakrishna Godavarthi 
1584d841502cSBalakrishna Godavarthi 	wait_on_bit_timeout(&qca->flags, QCA_MEMDUMP_COLLECTION,
1585d841502cSBalakrishna Godavarthi 			    TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT_MS);
1586d841502cSBalakrishna Godavarthi 
1587d841502cSBalakrishna Godavarthi 	clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
1588d841502cSBalakrishna Godavarthi }
1589d841502cSBalakrishna Godavarthi 
qca_hw_error(struct hci_dev * hdev,u8 code)1590d841502cSBalakrishna Godavarthi static void qca_hw_error(struct hci_dev *hdev, u8 code)
1591d841502cSBalakrishna Godavarthi {
1592d841502cSBalakrishna Godavarthi 	struct hci_uart *hu = hci_get_drvdata(hdev);
1593d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
1594d841502cSBalakrishna Godavarthi 
15953344537fSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_SSR_TRIGGERED, &qca->flags);
15967c2c3e63SVenkata Lakshmi Narayana Gubba 	set_bit(QCA_HW_ERROR_EVENT, &qca->flags);
1597d841502cSBalakrishna Godavarthi 	bt_dev_info(hdev, "mem_dump_status: %d", qca->memdump_state);
1598d841502cSBalakrishna Godavarthi 
1599d841502cSBalakrishna Godavarthi 	if (qca->memdump_state == QCA_MEMDUMP_IDLE) {
1600d841502cSBalakrishna Godavarthi 		/* If hardware error event received for other than QCA
1601d841502cSBalakrishna Godavarthi 		 * soc memory dump event, then we need to crash the SOC
1602d841502cSBalakrishna Godavarthi 		 * and wait here for 8 seconds to get the dump packets.
1603d841502cSBalakrishna Godavarthi 		 * This will block main thread to be on hold until we
1604d841502cSBalakrishna Godavarthi 		 * collect dump.
1605d841502cSBalakrishna Godavarthi 		 */
1606d841502cSBalakrishna Godavarthi 		set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
1607d841502cSBalakrishna Godavarthi 		qca_send_crashbuffer(hu);
1608d841502cSBalakrishna Godavarthi 		qca_wait_for_dump_collection(hdev);
1609d841502cSBalakrishna Godavarthi 	} else if (qca->memdump_state == QCA_MEMDUMP_COLLECTING) {
1610d841502cSBalakrishna Godavarthi 		/* Let us wait here until memory dump collected or
1611d841502cSBalakrishna Godavarthi 		 * memory dump timer expired.
1612d841502cSBalakrishna Godavarthi 		 */
1613d841502cSBalakrishna Godavarthi 		bt_dev_info(hdev, "waiting for dump to complete");
1614d841502cSBalakrishna Godavarthi 		qca_wait_for_dump_collection(hdev);
1615d841502cSBalakrishna Godavarthi 	}
16167c2c3e63SVenkata Lakshmi Narayana Gubba 
1617f98aa80fSVenkata Lakshmi Narayana Gubba 	mutex_lock(&qca->hci_memdump_lock);
16187c2c3e63SVenkata Lakshmi Narayana Gubba 	if (qca->memdump_state != QCA_MEMDUMP_COLLECTED) {
16197c2c3e63SVenkata Lakshmi Narayana Gubba 		bt_dev_err(hu->hdev, "clearing allocated memory due to memdump timeout");
162006d3fdfcSSai Teja Aluvala 		hci_devcd_abort(hu->hdev);
1621f98aa80fSVenkata Lakshmi Narayana Gubba 		if (qca->qca_memdump) {
1622f98aa80fSVenkata Lakshmi Narayana Gubba 			kfree(qca->qca_memdump);
16237c2c3e63SVenkata Lakshmi Narayana Gubba 			qca->qca_memdump = NULL;
1624f98aa80fSVenkata Lakshmi Narayana Gubba 		}
16257c2c3e63SVenkata Lakshmi Narayana Gubba 		qca->memdump_state = QCA_MEMDUMP_TIMEOUT;
16267c2c3e63SVenkata Lakshmi Narayana Gubba 		cancel_delayed_work(&qca->ctrl_memdump_timeout);
1627f98aa80fSVenkata Lakshmi Narayana Gubba 	}
16287c2c3e63SVenkata Lakshmi Narayana Gubba 	mutex_unlock(&qca->hci_memdump_lock);
1629f98aa80fSVenkata Lakshmi Narayana Gubba 
1630f98aa80fSVenkata Lakshmi Narayana Gubba 	if (qca->memdump_state == QCA_MEMDUMP_TIMEOUT ||
1631f98aa80fSVenkata Lakshmi Narayana Gubba 	    qca->memdump_state == QCA_MEMDUMP_COLLECTED) {
16327c2c3e63SVenkata Lakshmi Narayana Gubba 		cancel_work_sync(&qca->ctrl_memdump_evt);
1633f98aa80fSVenkata Lakshmi Narayana Gubba 		skb_queue_purge(&qca->rx_memdump_q);
16347c2c3e63SVenkata Lakshmi Narayana Gubba 	}
16357c2c3e63SVenkata Lakshmi Narayana Gubba 
16367c2c3e63SVenkata Lakshmi Narayana Gubba 	clear_bit(QCA_HW_ERROR_EVENT, &qca->flags);
1637d841502cSBalakrishna Godavarthi }
1638d841502cSBalakrishna Godavarthi 
qca_cmd_timeout(struct hci_dev * hdev)1639d841502cSBalakrishna Godavarthi static void qca_cmd_timeout(struct hci_dev *hdev)
1640d841502cSBalakrishna Godavarthi {
1641d841502cSBalakrishna Godavarthi 	struct hci_uart *hu = hci_get_drvdata(hdev);
1642d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
1643d841502cSBalakrishna Godavarthi 
16443344537fSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_SSR_TRIGGERED, &qca->flags);
16453344537fSVenkata Lakshmi Narayana Gubba 	if (qca->memdump_state == QCA_MEMDUMP_IDLE) {
16463344537fSVenkata Lakshmi Narayana Gubba 		set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
1647d841502cSBalakrishna Godavarthi 		qca_send_crashbuffer(hu);
16483344537fSVenkata Lakshmi Narayana Gubba 		qca_wait_for_dump_collection(hdev);
16493344537fSVenkata Lakshmi Narayana Gubba 	} else if (qca->memdump_state == QCA_MEMDUMP_COLLECTING) {
16503344537fSVenkata Lakshmi Narayana Gubba 		/* Let us wait here until memory dump collected or
16513344537fSVenkata Lakshmi Narayana Gubba 		 * memory dump timer expired.
16523344537fSVenkata Lakshmi Narayana Gubba 		 */
16533344537fSVenkata Lakshmi Narayana Gubba 		bt_dev_info(hdev, "waiting for dump to complete");
16543344537fSVenkata Lakshmi Narayana Gubba 		qca_wait_for_dump_collection(hdev);
16553344537fSVenkata Lakshmi Narayana Gubba 	}
16563344537fSVenkata Lakshmi Narayana Gubba 
16573344537fSVenkata Lakshmi Narayana Gubba 	mutex_lock(&qca->hci_memdump_lock);
16583344537fSVenkata Lakshmi Narayana Gubba 	if (qca->memdump_state != QCA_MEMDUMP_COLLECTED) {
16593344537fSVenkata Lakshmi Narayana Gubba 		qca->memdump_state = QCA_MEMDUMP_TIMEOUT;
16603344537fSVenkata Lakshmi Narayana Gubba 		if (!test_bit(QCA_HW_ERROR_EVENT, &qca->flags)) {
16613344537fSVenkata Lakshmi Narayana Gubba 			/* Inject hw error event to reset the device
16623344537fSVenkata Lakshmi Narayana Gubba 			 * and driver.
16633344537fSVenkata Lakshmi Narayana Gubba 			 */
16643344537fSVenkata Lakshmi Narayana Gubba 			hci_reset_dev(hu->hdev);
16653344537fSVenkata Lakshmi Narayana Gubba 		}
16663344537fSVenkata Lakshmi Narayana Gubba 	}
16673344537fSVenkata Lakshmi Narayana Gubba 	mutex_unlock(&qca->hci_memdump_lock);
1668d841502cSBalakrishna Godavarthi }
1669d841502cSBalakrishna Godavarthi 
qca_wakeup(struct hci_dev * hdev)16704539ca67SLuiz Augusto von Dentz static bool qca_wakeup(struct hci_dev *hdev)
1671c1a74160SVenkata Lakshmi Narayana Gubba {
1672c1a74160SVenkata Lakshmi Narayana Gubba 	struct hci_uart *hu = hci_get_drvdata(hdev);
1673c1a74160SVenkata Lakshmi Narayana Gubba 	bool wakeup;
1674c1a74160SVenkata Lakshmi Narayana Gubba 
16756b47cdebSJohan Hovold 	if (!hu->serdev)
16766b47cdebSJohan Hovold 		return true;
16776b47cdebSJohan Hovold 
167803b0093fSZhengping Jiang 	/* BT SoC attached through the serial bus is handled by the serdev driver.
167903b0093fSZhengping Jiang 	 * So we need to use the device handle of the serdev driver to get the
168003b0093fSZhengping Jiang 	 * status of device may wakeup.
1681c1a74160SVenkata Lakshmi Narayana Gubba 	 */
168203b0093fSZhengping Jiang 	wakeup = device_may_wakeup(&hu->serdev->ctrl->dev);
1683c1a74160SVenkata Lakshmi Narayana Gubba 	bt_dev_dbg(hu->hdev, "wakeup status : %d", wakeup);
1684c1a74160SVenkata Lakshmi Narayana Gubba 
1685bde63e9eSSai Teja Aluvala 	return wakeup;
1686c1a74160SVenkata Lakshmi Narayana Gubba }
1687c1a74160SVenkata Lakshmi Narayana Gubba 
qca_regulator_init(struct hci_uart * hu)1688d8f97da1SVenkata Lakshmi Narayana Gubba static int qca_regulator_init(struct hci_uart *hu)
1689fa9ad876SBalakrishna Godavarthi {
1690d8f97da1SVenkata Lakshmi Narayana Gubba 	enum qca_btsoc_type soc_type = qca_soc_type(hu);
16913e4be65eSBalakrishna Godavarthi 	struct qca_serdev *qcadev;
1692fa9ad876SBalakrishna Godavarthi 	int ret;
1693d8f97da1SVenkata Lakshmi Narayana Gubba 	bool sw_ctrl_state;
1694fa9ad876SBalakrishna Godavarthi 
16953e4be65eSBalakrishna Godavarthi 	/* Check for vregs status, may be hci down has turned
16963e4be65eSBalakrishna Godavarthi 	 * off the voltage regulator.
16973e4be65eSBalakrishna Godavarthi 	 */
16983e4be65eSBalakrishna Godavarthi 	qcadev = serdev_device_get_drvdata(hu->serdev);
16993e4be65eSBalakrishna Godavarthi 	if (!qcadev->bt_power->vregs_on) {
17003e4be65eSBalakrishna Godavarthi 		serdev_device_close(hu->serdev);
1701a9314e76SBjorn Andersson 		ret = qca_regulator_enable(qcadev);
17023e4be65eSBalakrishna Godavarthi 		if (ret)
17033e4be65eSBalakrishna Godavarthi 			return ret;
17043e4be65eSBalakrishna Godavarthi 
17053e4be65eSBalakrishna Godavarthi 		ret = serdev_device_open(hu->serdev);
17063e4be65eSBalakrishna Godavarthi 		if (ret) {
17073e4be65eSBalakrishna Godavarthi 			bt_dev_err(hu->hdev, "failed to open port");
17083e4be65eSBalakrishna Godavarthi 			return ret;
17093e4be65eSBalakrishna Godavarthi 		}
17103e4be65eSBalakrishna Godavarthi 	}
17113e4be65eSBalakrishna Godavarthi 
1712691d54d0SNeil Armstrong 	switch (soc_type) {
1713691d54d0SNeil Armstrong 	case QCA_WCN3988:
1714691d54d0SNeil Armstrong 	case QCA_WCN3990:
1715691d54d0SNeil Armstrong 	case QCA_WCN3991:
1716691d54d0SNeil Armstrong 	case QCA_WCN3998:
1717d8f97da1SVenkata Lakshmi Narayana Gubba 		/* Forcefully enable wcn399x to enter in to boot mode. */
1718fa9ad876SBalakrishna Godavarthi 		host_set_baudrate(hu, 2400);
17199836b802SMatthias Kaehlcke 		ret = qca_send_power_pulse(hu, false);
1720fa9ad876SBalakrishna Godavarthi 		if (ret)
1721fa9ad876SBalakrishna Godavarthi 			return ret;
1722691d54d0SNeil Armstrong 		break;
1723691d54d0SNeil Armstrong 
1724691d54d0SNeil Armstrong 	default:
1725691d54d0SNeil Armstrong 		break;
1726d8f97da1SVenkata Lakshmi Narayana Gubba 	}
1727d8f97da1SVenkata Lakshmi Narayana Gubba 
1728d8f97da1SVenkata Lakshmi Narayana Gubba 	/* For wcn6750 need to enable gpio bt_en */
1729d8f97da1SVenkata Lakshmi Narayana Gubba 	if (qcadev->bt_en) {
1730d8f97da1SVenkata Lakshmi Narayana Gubba 		gpiod_set_value_cansleep(qcadev->bt_en, 0);
1731d8f97da1SVenkata Lakshmi Narayana Gubba 		msleep(50);
1732d8f97da1SVenkata Lakshmi Narayana Gubba 		gpiod_set_value_cansleep(qcadev->bt_en, 1);
1733d8f97da1SVenkata Lakshmi Narayana Gubba 		msleep(50);
1734d8f97da1SVenkata Lakshmi Narayana Gubba 		if (qcadev->sw_ctrl) {
1735d8f97da1SVenkata Lakshmi Narayana Gubba 			sw_ctrl_state = gpiod_get_value_cansleep(qcadev->sw_ctrl);
1736d8f97da1SVenkata Lakshmi Narayana Gubba 			bt_dev_dbg(hu->hdev, "SW_CTRL is %d", sw_ctrl_state);
1737d8f97da1SVenkata Lakshmi Narayana Gubba 		}
1738d8f97da1SVenkata Lakshmi Narayana Gubba 	}
1739fa9ad876SBalakrishna Godavarthi 
1740fa9ad876SBalakrishna Godavarthi 	qca_set_speed(hu, QCA_INIT_SPEED);
1741d8f97da1SVenkata Lakshmi Narayana Gubba 
1742691d54d0SNeil Armstrong 	switch (soc_type) {
1743691d54d0SNeil Armstrong 	case QCA_WCN3988:
1744691d54d0SNeil Armstrong 	case QCA_WCN3990:
1745691d54d0SNeil Armstrong 	case QCA_WCN3991:
1746691d54d0SNeil Armstrong 	case QCA_WCN3998:
17479836b802SMatthias Kaehlcke 		ret = qca_send_power_pulse(hu, true);
1748fa9ad876SBalakrishna Godavarthi 		if (ret)
1749fa9ad876SBalakrishna Godavarthi 			return ret;
1750691d54d0SNeil Armstrong 		break;
1751691d54d0SNeil Armstrong 
1752691d54d0SNeil Armstrong 	default:
1753691d54d0SNeil Armstrong 		break;
1754d8f97da1SVenkata Lakshmi Narayana Gubba 	}
1755fa9ad876SBalakrishna Godavarthi 
1756fa9ad876SBalakrishna Godavarthi 	/* Now the device is in ready state to communicate with host.
1757fa9ad876SBalakrishna Godavarthi 	 * To sync host with device we need to reopen port.
1758fa9ad876SBalakrishna Godavarthi 	 * Without this, we will have RTS and CTS synchronization
1759fa9ad876SBalakrishna Godavarthi 	 * issues.
1760fa9ad876SBalakrishna Godavarthi 	 */
1761fa9ad876SBalakrishna Godavarthi 	serdev_device_close(hu->serdev);
1762fa9ad876SBalakrishna Godavarthi 	ret = serdev_device_open(hu->serdev);
1763fa9ad876SBalakrishna Godavarthi 	if (ret) {
1764fa9ad876SBalakrishna Godavarthi 		bt_dev_err(hu->hdev, "failed to open port");
1765fa9ad876SBalakrishna Godavarthi 		return ret;
1766fa9ad876SBalakrishna Godavarthi 	}
1767fa9ad876SBalakrishna Godavarthi 
1768fa9ad876SBalakrishna Godavarthi 	hci_uart_set_flow_control(hu, false);
1769fa9ad876SBalakrishna Godavarthi 
1770fa9ad876SBalakrishna Godavarthi 	return 0;
1771fa9ad876SBalakrishna Godavarthi }
1772fa9ad876SBalakrishna Godavarthi 
qca_power_on(struct hci_dev * hdev)17735e6d8401SRocky Liao static int qca_power_on(struct hci_dev *hdev)
17745e6d8401SRocky Liao {
17755e6d8401SRocky Liao 	struct hci_uart *hu = hci_get_drvdata(hdev);
17765e6d8401SRocky Liao 	enum qca_btsoc_type soc_type = qca_soc_type(hu);
17775e6d8401SRocky Liao 	struct qca_serdev *qcadev;
17782be43abaSVenkata Lakshmi Narayana Gubba 	struct qca_data *qca = hu->priv;
17795e6d8401SRocky Liao 	int ret = 0;
17805e6d8401SRocky Liao 
17815e6d8401SRocky Liao 	/* Non-serdev device usually is powered by external power
17825e6d8401SRocky Liao 	 * and don't need additional action in driver for power on
17835e6d8401SRocky Liao 	 */
17845e6d8401SRocky Liao 	if (!hu->serdev)
17855e6d8401SRocky Liao 		return 0;
17865e6d8401SRocky Liao 
1787691d54d0SNeil Armstrong 	switch (soc_type) {
1788691d54d0SNeil Armstrong 	case QCA_WCN3988:
1789691d54d0SNeil Armstrong 	case QCA_WCN3990:
1790691d54d0SNeil Armstrong 	case QCA_WCN3991:
1791691d54d0SNeil Armstrong 	case QCA_WCN3998:
1792691d54d0SNeil Armstrong 	case QCA_WCN6750:
1793691d54d0SNeil Armstrong 	case QCA_WCN6855:
1794e0c1278aSNeil Armstrong 	case QCA_WCN7850:
1795d8f97da1SVenkata Lakshmi Narayana Gubba 		ret = qca_regulator_init(hu);
1796691d54d0SNeil Armstrong 		break;
1797691d54d0SNeil Armstrong 
1798691d54d0SNeil Armstrong 	default:
17995e6d8401SRocky Liao 		qcadev = serdev_device_get_drvdata(hu->serdev);
180077131dfeSRocky Liao 		if (qcadev->bt_en) {
18015e6d8401SRocky Liao 			gpiod_set_value_cansleep(qcadev->bt_en, 1);
18025e6d8401SRocky Liao 			/* Controller needs time to bootup. */
18035e6d8401SRocky Liao 			msleep(150);
18045e6d8401SRocky Liao 		}
18058a208b24SRocky Liao 	}
18065e6d8401SRocky Liao 
18072be43abaSVenkata Lakshmi Narayana Gubba 	clear_bit(QCA_BT_OFF, &qca->flags);
18085e6d8401SRocky Liao 	return ret;
18095e6d8401SRocky Liao }
18105e6d8401SRocky Liao 
hci_coredump_qca(struct hci_dev * hdev)181106d3fdfcSSai Teja Aluvala static void hci_coredump_qca(struct hci_dev *hdev)
181206d3fdfcSSai Teja Aluvala {
181339e39c34SZijun Hu 	int err;
181406d3fdfcSSai Teja Aluvala 	static const u8 param[] = { 0x26 };
181506d3fdfcSSai Teja Aluvala 
181639e39c34SZijun Hu 	err = __hci_cmd_send(hdev, 0xfc0c, 1, param);
181739e39c34SZijun Hu 	if (err < 0)
181839e39c34SZijun Hu 		bt_dev_err(hdev, "%s: trigger crash failed (%d)", __func__, err);
181906d3fdfcSSai Teja Aluvala }
182006d3fdfcSSai Teja Aluvala 
qca_setup(struct hci_uart * hu)18210ff252c1SBen Young Tae Kim static int qca_setup(struct hci_uart *hu)
18220ff252c1SBen Young Tae Kim {
18230ff252c1SBen Young Tae Kim 	struct hci_dev *hdev = hu->hdev;
18240ff252c1SBen Young Tae Kim 	struct qca_data *qca = hu->priv;
18250ff252c1SBen Young Tae Kim 	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
1826bb2500abSRocky Liao 	unsigned int retries = 0;
18274fdd5a4fSMatthias Kaehlcke 	enum qca_btsoc_type soc_type = qca_soc_type(hu);
182899c905c6SRocky Liao 	const char *firmware_name = qca_get_firmware_name(hu);
18290ff252c1SBen Young Tae Kim 	int ret;
1830059924fdSVenkata Lakshmi Narayana Gubba 	struct qca_btsoc_version ver;
18311622e563SJohan Hovold 	struct qca_serdev *qcadev;
1832691d54d0SNeil Armstrong 	const char *soc_name;
18330ff252c1SBen Young Tae Kim 
183483d9c5e5SBalakrishna Godavarthi 	ret = qca_check_speeds(hu);
183583d9c5e5SBalakrishna Godavarthi 	if (ret)
183683d9c5e5SBalakrishna Godavarthi 		return ret;
183783d9c5e5SBalakrishna Godavarthi 
183855c0bd77SVenkata Lakshmi Narayana Gubba 	clear_bit(QCA_ROM_FW, &qca->flags);
18390ff252c1SBen Young Tae Kim 	/* Patch downloading has to be done without IBS mode */
18402be43abaSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_IBS_DISABLED, &qca->flags);
18410ff252c1SBen Young Tae Kim 
1842e14c167aSRocky Liao 	/* Enable controller to do both LE scan and BR/EDR inquiry
1843e14c167aSRocky Liao 	 * simultaneously.
1844e14c167aSRocky Liao 	 */
1845e14c167aSRocky Liao 	set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
1846e14c167aSRocky Liao 
1847691d54d0SNeil Armstrong 	switch (soc_type) {
1848a381ee26STim Jiang 	case QCA_QCA2066:
1849a381ee26STim Jiang 		soc_name = "qca2066";
1850a381ee26STim Jiang 		break;
1851a381ee26STim Jiang 
1852691d54d0SNeil Armstrong 	case QCA_WCN3988:
1853691d54d0SNeil Armstrong 	case QCA_WCN3990:
1854691d54d0SNeil Armstrong 	case QCA_WCN3991:
1855691d54d0SNeil Armstrong 	case QCA_WCN3998:
1856691d54d0SNeil Armstrong 		soc_name = "wcn399x";
1857691d54d0SNeil Armstrong 		break;
1858691d54d0SNeil Armstrong 
1859691d54d0SNeil Armstrong 	case QCA_WCN6750:
1860691d54d0SNeil Armstrong 		soc_name = "wcn6750";
1861691d54d0SNeil Armstrong 		break;
1862691d54d0SNeil Armstrong 
1863691d54d0SNeil Armstrong 	case QCA_WCN6855:
1864691d54d0SNeil Armstrong 		soc_name = "wcn6855";
1865691d54d0SNeil Armstrong 		break;
1866691d54d0SNeil Armstrong 
1867e0c1278aSNeil Armstrong 	case QCA_WCN7850:
1868e0c1278aSNeil Armstrong 		soc_name = "wcn7850";
1869e0c1278aSNeil Armstrong 		break;
1870e0c1278aSNeil Armstrong 
1871691d54d0SNeil Armstrong 	default:
1872691d54d0SNeil Armstrong 		soc_name = "ROME/QCA6390";
1873691d54d0SNeil Armstrong 	}
1874691d54d0SNeil Armstrong 	bt_dev_info(hdev, "setting up %s", soc_name);
18753e4be65eSBalakrishna Godavarthi 
187658789a19SVenkata Lakshmi Narayana Gubba 	qca->memdump_state = QCA_MEMDUMP_IDLE;
187758789a19SVenkata Lakshmi Narayana Gubba 
1878bb2500abSRocky Liao retry:
18795e6d8401SRocky Liao 	ret = qca_power_on(hdev);
18805e6d8401SRocky Liao 	if (ret)
18819e80587aSBalakrishna Godavarthi 		goto out;
18825e6d8401SRocky Liao 
18833344537fSVenkata Lakshmi Narayana Gubba 	clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
18843344537fSVenkata Lakshmi Narayana Gubba 
1885691d54d0SNeil Armstrong 	switch (soc_type) {
1886691d54d0SNeil Armstrong 	case QCA_WCN3988:
1887691d54d0SNeil Armstrong 	case QCA_WCN3990:
1888691d54d0SNeil Armstrong 	case QCA_WCN3991:
1889691d54d0SNeil Armstrong 	case QCA_WCN3998:
1890691d54d0SNeil Armstrong 	case QCA_WCN6750:
1891691d54d0SNeil Armstrong 	case QCA_WCN6855:
1892e0c1278aSNeil Armstrong 	case QCA_WCN7850:
18931622e563SJohan Hovold 		qcadev = serdev_device_get_drvdata(hu->serdev);
18941622e563SJohan Hovold 		if (qcadev->bdaddr_property_broken)
18951622e563SJohan Hovold 			set_bit(HCI_QUIRK_BDADDR_PROPERTY_BROKEN, &hdev->quirks);
18961622e563SJohan Hovold 
189734af56e8SJoseph Hwang 		hci_set_aosp_capable(hdev);
1898fa9ad876SBalakrishna Godavarthi 
1899059924fdSVenkata Lakshmi Narayana Gubba 		ret = qca_read_soc_version(hdev, &ver, soc_type);
1900fa9ad876SBalakrishna Godavarthi 		if (ret)
19019e80587aSBalakrishna Godavarthi 			goto out;
1902691d54d0SNeil Armstrong 		break;
1903691d54d0SNeil Armstrong 
1904691d54d0SNeil Armstrong 	default:
190583d9c5e5SBalakrishna Godavarthi 		qca_set_speed(hu, QCA_INIT_SPEED);
1906fa9ad876SBalakrishna Godavarthi 	}
19070ff252c1SBen Young Tae Kim 
19080ff252c1SBen Young Tae Kim 	/* Setup user speed if needed */
190983d9c5e5SBalakrishna Godavarthi 	speed = qca_get_speed(hu, QCA_OPER_SPEED);
19100ff252c1SBen Young Tae Kim 	if (speed) {
191183d9c5e5SBalakrishna Godavarthi 		ret = qca_set_speed(hu, QCA_OPER_SPEED);
191283d9c5e5SBalakrishna Godavarthi 		if (ret)
19139e80587aSBalakrishna Godavarthi 			goto out;
191483d9c5e5SBalakrishna Godavarthi 
191583d9c5e5SBalakrishna Godavarthi 		qca_baudrate = qca_get_baudrate_value(speed);
19160ff252c1SBen Young Tae Kim 	}
19170ff252c1SBen Young Tae Kim 
1918691d54d0SNeil Armstrong 	switch (soc_type) {
1919691d54d0SNeil Armstrong 	case QCA_WCN3988:
1920691d54d0SNeil Armstrong 	case QCA_WCN3990:
1921691d54d0SNeil Armstrong 	case QCA_WCN3991:
1922691d54d0SNeil Armstrong 	case QCA_WCN3998:
1923691d54d0SNeil Armstrong 	case QCA_WCN6750:
1924691d54d0SNeil Armstrong 	case QCA_WCN6855:
1925e0c1278aSNeil Armstrong 	case QCA_WCN7850:
1926691d54d0SNeil Armstrong 		break;
1927691d54d0SNeil Armstrong 
1928691d54d0SNeil Armstrong 	default:
1929aadebac4SBalakrishna Godavarthi 		/* Get QCA version information */
1930059924fdSVenkata Lakshmi Narayana Gubba 		ret = qca_read_soc_version(hdev, &ver, soc_type);
1931aadebac4SBalakrishna Godavarthi 		if (ret)
19329e80587aSBalakrishna Godavarthi 			goto out;
1933fa9ad876SBalakrishna Godavarthi 	}
1934aadebac4SBalakrishna Godavarthi 
19350ff252c1SBen Young Tae Kim 	/* Setup patch / NVM configurations */
1936059924fdSVenkata Lakshmi Narayana Gubba 	ret = qca_uart_setup(hdev, qca_baudrate, soc_type, ver,
193799c905c6SRocky Liao 			firmware_name);
19380ff252c1SBen Young Tae Kim 	if (!ret) {
19392be43abaSVenkata Lakshmi Narayana Gubba 		clear_bit(QCA_IBS_DISABLED, &qca->flags);
19400ff252c1SBen Young Tae Kim 		qca_debugfs_init(hdev);
1941d841502cSBalakrishna Godavarthi 		hu->hdev->hw_error = qca_hw_error;
1942d841502cSBalakrishna Godavarthi 		hu->hdev->cmd_timeout = qca_cmd_timeout;
194367459f1aSJohan Hovold 		if (hu->serdev) {
1944e9b3e5b8SZhengping Jiang 			if (device_can_wakeup(hu->serdev->ctrl->dev.parent))
19454539ca67SLuiz Augusto von Dentz 				hu->hdev->wakeup = qca_wakeup;
194667459f1aSJohan Hovold 		}
1947ba8f3597SLoic Poulain 	} else if (ret == -ENOENT) {
1948ba8f3597SLoic Poulain 		/* No patch/nvm-config found, run with original fw/config */
194955c0bd77SVenkata Lakshmi Narayana Gubba 		set_bit(QCA_ROM_FW, &qca->flags);
1950ba8f3597SLoic Poulain 		ret = 0;
19517dc5fe08SAmit Pundir 	} else if (ret == -EAGAIN) {
19527dc5fe08SAmit Pundir 		/*
19537dc5fe08SAmit Pundir 		 * Userspace firmware loader will return -EAGAIN in case no
19547dc5fe08SAmit Pundir 		 * patch/nvm-config is found, so run with original fw/config.
19557dc5fe08SAmit Pundir 		 */
195655c0bd77SVenkata Lakshmi Narayana Gubba 		set_bit(QCA_ROM_FW, &qca->flags);
19577dc5fe08SAmit Pundir 		ret = 0;
19589e80587aSBalakrishna Godavarthi 	}
19599e80587aSBalakrishna Godavarthi 
19609e80587aSBalakrishna Godavarthi out:
19619e80587aSBalakrishna Godavarthi 	if (ret && retries < MAX_INIT_RETRIES) {
19629e80587aSBalakrishna Godavarthi 		bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
1963bb2500abSRocky Liao 		qca_power_shutdown(hu);
1964bb2500abSRocky Liao 		if (hu->serdev) {
1965bb2500abSRocky Liao 			serdev_device_close(hu->serdev);
1966bb2500abSRocky Liao 			ret = serdev_device_open(hu->serdev);
1967bb2500abSRocky Liao 			if (ret) {
1968bb2500abSRocky Liao 				bt_dev_err(hdev, "failed to open port");
1969bb2500abSRocky Liao 				return ret;
1970bb2500abSRocky Liao 			}
1971bb2500abSRocky Liao 		}
1972bb2500abSRocky Liao 		retries++;
1973bb2500abSRocky Liao 		goto retry;
1974bb2500abSRocky Liao 	}
19750ff252c1SBen Young Tae Kim 
19760ff252c1SBen Young Tae Kim 	/* Setup bdaddr */
1977e5d6468fSRocky Liao 	if (soc_type == QCA_ROME)
19780ff252c1SBen Young Tae Kim 		hu->hdev->set_bdaddr = qca_set_bdaddr_rome;
1979e5d6468fSRocky Liao 	else
1980e5d6468fSRocky Liao 		hu->hdev->set_bdaddr = qca_set_bdaddr;
198106d3fdfcSSai Teja Aluvala 	qca->fw_version = le16_to_cpu(ver.patch_ver);
198206d3fdfcSSai Teja Aluvala 	qca->controller_id = le16_to_cpu(ver.rom_ver);
198306d3fdfcSSai Teja Aluvala 	hci_devcd_register(hdev, hci_coredump_qca, qca_dmp_hdr, NULL);
19840ff252c1SBen Young Tae Kim 
19850ff252c1SBen Young Tae Kim 	return ret;
19860ff252c1SBen Young Tae Kim }
19870ff252c1SBen Young Tae Kim 
19882edc9c5cSNishka Dasgupta static const struct hci_uart_proto qca_proto = {
19890ff252c1SBen Young Tae Kim 	.id		= HCI_UART_QCA,
19900ff252c1SBen Young Tae Kim 	.name		= "QCA",
1991aee61f7aSMarcel Holtmann 	.manufacturer	= 29,
19920ff252c1SBen Young Tae Kim 	.init_speed	= 115200,
19930ff252c1SBen Young Tae Kim 	.oper_speed	= 3000000,
19940ff252c1SBen Young Tae Kim 	.open		= qca_open,
19950ff252c1SBen Young Tae Kim 	.close		= qca_close,
19960ff252c1SBen Young Tae Kim 	.flush		= qca_flush,
19970ff252c1SBen Young Tae Kim 	.setup		= qca_setup,
19980ff252c1SBen Young Tae Kim 	.recv		= qca_recv,
19990ff252c1SBen Young Tae Kim 	.enqueue	= qca_enqueue,
20000ff252c1SBen Young Tae Kim 	.dequeue	= qca_dequeue,
20010ff252c1SBen Young Tae Kim };
20020ff252c1SBen Young Tae Kim 
2003f904feefSLuca Weiss static const struct qca_device_data qca_soc_data_wcn3988 __maybe_unused = {
2004f904feefSLuca Weiss 	.soc_type = QCA_WCN3988,
2005f904feefSLuca Weiss 	.vregs = (struct qca_vreg []) {
2006f904feefSLuca Weiss 		{ "vddio", 15000  },
2007f904feefSLuca Weiss 		{ "vddxo", 80000  },
2008f904feefSLuca Weiss 		{ "vddrf", 300000 },
2009f904feefSLuca Weiss 		{ "vddch0", 450000 },
2010f904feefSLuca Weiss 	},
2011f904feefSLuca Weiss 	.num_vregs = 4,
2012f904feefSLuca Weiss };
2013f904feefSLuca Weiss 
201444fac8a2SKrzysztof Kozlowski static const struct qca_device_data qca_soc_data_wcn3990 __maybe_unused = {
2015fa9ad876SBalakrishna Godavarthi 	.soc_type = QCA_WCN3990,
2016fa9ad876SBalakrishna Godavarthi 	.vregs = (struct qca_vreg []) {
2017f2edd66eSBjorn Andersson 		{ "vddio", 15000  },
2018f2edd66eSBjorn Andersson 		{ "vddxo", 80000  },
2019f2edd66eSBjorn Andersson 		{ "vddrf", 300000 },
2020f2edd66eSBjorn Andersson 		{ "vddch0", 450000 },
2021fa9ad876SBalakrishna Godavarthi 	},
2022fa9ad876SBalakrishna Godavarthi 	.num_vregs = 4,
2023fa9ad876SBalakrishna Godavarthi };
2024fa9ad876SBalakrishna Godavarthi 
202544fac8a2SKrzysztof Kozlowski static const struct qca_device_data qca_soc_data_wcn3991 __maybe_unused = {
20267d250a06SBalakrishna Godavarthi 	.soc_type = QCA_WCN3991,
20277d250a06SBalakrishna Godavarthi 	.vregs = (struct qca_vreg []) {
20287d250a06SBalakrishna Godavarthi 		{ "vddio", 15000  },
20297d250a06SBalakrishna Godavarthi 		{ "vddxo", 80000  },
20307d250a06SBalakrishna Godavarthi 		{ "vddrf", 300000 },
20317d250a06SBalakrishna Godavarthi 		{ "vddch0", 450000 },
20327d250a06SBalakrishna Godavarthi 	},
20337d250a06SBalakrishna Godavarthi 	.num_vregs = 4,
203454780138SAbhishek Pandit-Subedi 	.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
20357d250a06SBalakrishna Godavarthi };
20367d250a06SBalakrishna Godavarthi 
203744fac8a2SKrzysztof Kozlowski static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = {
2038523760b7SHarish Bandi 	.soc_type = QCA_WCN3998,
2039523760b7SHarish Bandi 	.vregs = (struct qca_vreg []) {
2040f2edd66eSBjorn Andersson 		{ "vddio", 10000  },
2041f2edd66eSBjorn Andersson 		{ "vddxo", 80000  },
2042f2edd66eSBjorn Andersson 		{ "vddrf", 300000 },
2043f2edd66eSBjorn Andersson 		{ "vddch0", 450000 },
2044523760b7SHarish Bandi 	},
2045523760b7SHarish Bandi 	.num_vregs = 4,
2046523760b7SHarish Bandi };
2047523760b7SHarish Bandi 
2048a381ee26STim Jiang static const struct qca_device_data qca_soc_data_qca2066 __maybe_unused = {
2049a381ee26STim Jiang 	.soc_type = QCA_QCA2066,
2050a381ee26STim Jiang 	.num_vregs = 0,
2051a381ee26STim Jiang };
2052a381ee26STim Jiang 
205344fac8a2SKrzysztof Kozlowski static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = {
2054e5d6468fSRocky Liao 	.soc_type = QCA_QCA6390,
2055e5d6468fSRocky Liao 	.num_vregs = 0,
2056f2719eccSZijun Hu 	.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
2057e5d6468fSRocky Liao };
2058e5d6468fSRocky Liao 
205944fac8a2SKrzysztof Kozlowski static const struct qca_device_data qca_soc_data_wcn6750 __maybe_unused = {
2060d8f97da1SVenkata Lakshmi Narayana Gubba 	.soc_type = QCA_WCN6750,
2061d8f97da1SVenkata Lakshmi Narayana Gubba 	.vregs = (struct qca_vreg []) {
2062d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddio", 5000 },
2063d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddaon", 26000 },
2064d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddbtcxmx", 126000 },
2065d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddrfacmn", 12500 },
2066d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddrfa0p8", 102000 },
2067d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddrfa1p7", 302000 },
2068d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddrfa1p2", 257000 },
2069d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddrfa2p2", 1700000 },
2070d8f97da1SVenkata Lakshmi Narayana Gubba 		{ "vddasd", 200 },
2071d8f97da1SVenkata Lakshmi Narayana Gubba 	},
2072d8f97da1SVenkata Lakshmi Narayana Gubba 	.num_vregs = 9,
2073d8f97da1SVenkata Lakshmi Narayana Gubba 	.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
2074d8f97da1SVenkata Lakshmi Narayana Gubba };
2075d8f97da1SVenkata Lakshmi Narayana Gubba 
20760811ff48SSteev Klimaszewski static const struct qca_device_data qca_soc_data_wcn6855 __maybe_unused = {
2077095327feSSteev Klimaszewski 	.soc_type = QCA_WCN6855,
2078095327feSSteev Klimaszewski 	.vregs = (struct qca_vreg []) {
2079095327feSSteev Klimaszewski 		{ "vddio", 5000 },
2080095327feSSteev Klimaszewski 		{ "vddbtcxmx", 126000 },
2081095327feSSteev Klimaszewski 		{ "vddrfacmn", 12500 },
2082095327feSSteev Klimaszewski 		{ "vddrfa0p8", 102000 },
2083095327feSSteev Klimaszewski 		{ "vddrfa1p7", 302000 },
2084095327feSSteev Klimaszewski 		{ "vddrfa1p2", 257000 },
2085095327feSSteev Klimaszewski 	},
2086095327feSSteev Klimaszewski 	.num_vregs = 6,
2087095327feSSteev Klimaszewski 	.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
2088095327feSSteev Klimaszewski };
2089095327feSSteev Klimaszewski 
2090e0c1278aSNeil Armstrong static const struct qca_device_data qca_soc_data_wcn7850 __maybe_unused = {
2091e0c1278aSNeil Armstrong 	.soc_type = QCA_WCN7850,
2092e0c1278aSNeil Armstrong 	.vregs = (struct qca_vreg []) {
2093e0c1278aSNeil Armstrong 		{ "vddio", 5000 },
2094e0c1278aSNeil Armstrong 		{ "vddaon", 26000 },
2095e0c1278aSNeil Armstrong 		{ "vdddig", 126000 },
2096e0c1278aSNeil Armstrong 		{ "vddrfa0p8", 102000 },
2097e0c1278aSNeil Armstrong 		{ "vddrfa1p2", 257000 },
2098e0c1278aSNeil Armstrong 		{ "vddrfa1p9", 302000 },
2099e0c1278aSNeil Armstrong 	},
2100e0c1278aSNeil Armstrong 	.num_vregs = 6,
2101e0c1278aSNeil Armstrong 	.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
2102e0c1278aSNeil Armstrong };
2103e0c1278aSNeil Armstrong 
qca_power_shutdown(struct hci_uart * hu)2104c2d78273SBalakrishna Godavarthi static void qca_power_shutdown(struct hci_uart *hu)
2105fa9ad876SBalakrishna Godavarthi {
2106a9314e76SBjorn Andersson 	struct qca_serdev *qcadev;
2107035a960eSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
2108035a960eSBalakrishna Godavarthi 	unsigned long flags;
21095559904cSRocky Liao 	enum qca_btsoc_type soc_type = qca_soc_type(hu);
2110d8f97da1SVenkata Lakshmi Narayana Gubba 	bool sw_ctrl_state;
2111035a960eSBalakrishna Godavarthi 
2112035a960eSBalakrishna Godavarthi 	/* From this point we go into power off state. But serial port is
2113035a960eSBalakrishna Godavarthi 	 * still open, stop queueing the IBS data and flush all the buffered
2114035a960eSBalakrishna Godavarthi 	 * data in skb's.
2115035a960eSBalakrishna Godavarthi 	 */
2116035a960eSBalakrishna Godavarthi 	spin_lock_irqsave(&qca->hci_ibs_lock, flags);
21172be43abaSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_IBS_DISABLED, &qca->flags);
2118035a960eSBalakrishna Godavarthi 	qca_flush(hu);
2119035a960eSBalakrishna Godavarthi 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
2120035a960eSBalakrishna Godavarthi 
21215559904cSRocky Liao 	/* Non-serdev device usually is powered by external power
21225559904cSRocky Liao 	 * and don't need additional action in driver for power down
21235559904cSRocky Liao 	 */
21245559904cSRocky Liao 	if (!hu->serdev)
21255559904cSRocky Liao 		return;
21265559904cSRocky Liao 
212759f90f13SPavel Skripkin 	qcadev = serdev_device_get_drvdata(hu->serdev);
212859f90f13SPavel Skripkin 
2129691d54d0SNeil Armstrong 	switch (soc_type) {
2130691d54d0SNeil Armstrong 	case QCA_WCN3988:
2131691d54d0SNeil Armstrong 	case QCA_WCN3990:
2132691d54d0SNeil Armstrong 	case QCA_WCN3991:
2133691d54d0SNeil Armstrong 	case QCA_WCN3998:
2134fa9ad876SBalakrishna Godavarthi 		host_set_baudrate(hu, 2400);
21359836b802SMatthias Kaehlcke 		qca_send_power_pulse(hu, false);
2136a9314e76SBjorn Andersson 		qca_regulator_disable(qcadev);
2137691d54d0SNeil Armstrong 		break;
2138691d54d0SNeil Armstrong 
2139691d54d0SNeil Armstrong 	case QCA_WCN6750:
2140691d54d0SNeil Armstrong 	case QCA_WCN6855:
2141d8f97da1SVenkata Lakshmi Narayana Gubba 		gpiod_set_value_cansleep(qcadev->bt_en, 0);
2142d8f97da1SVenkata Lakshmi Narayana Gubba 		msleep(100);
2143d8f97da1SVenkata Lakshmi Narayana Gubba 		qca_regulator_disable(qcadev);
2144d8f97da1SVenkata Lakshmi Narayana Gubba 		if (qcadev->sw_ctrl) {
2145d8f97da1SVenkata Lakshmi Narayana Gubba 			sw_ctrl_state = gpiod_get_value_cansleep(qcadev->sw_ctrl);
2146d8f97da1SVenkata Lakshmi Narayana Gubba 			bt_dev_dbg(hu->hdev, "SW_CTRL is %d", sw_ctrl_state);
2147d8f97da1SVenkata Lakshmi Narayana Gubba 		}
2148691d54d0SNeil Armstrong 		break;
2149691d54d0SNeil Armstrong 
2150691d54d0SNeil Armstrong 	default:
21515559904cSRocky Liao 		gpiod_set_value_cansleep(qcadev->bt_en, 0);
21525559904cSRocky Liao 	}
21532be43abaSVenkata Lakshmi Narayana Gubba 
21542be43abaSVenkata Lakshmi Narayana Gubba 	set_bit(QCA_BT_OFF, &qca->flags);
2155fa9ad876SBalakrishna Godavarthi }
2156fa9ad876SBalakrishna Godavarthi 
qca_power_off(struct hci_dev * hdev)21573e4be65eSBalakrishna Godavarthi static int qca_power_off(struct hci_dev *hdev)
21583e4be65eSBalakrishna Godavarthi {
21593e4be65eSBalakrishna Godavarthi 	struct hci_uart *hu = hci_get_drvdata(hdev);
2160d841502cSBalakrishna Godavarthi 	struct qca_data *qca = hu->priv;
21614f9ed5bdSRocky Liao 	enum qca_btsoc_type soc_type = qca_soc_type(hu);
21623e4be65eSBalakrishna Godavarthi 
216358789a19SVenkata Lakshmi Narayana Gubba 	hu->hdev->hw_error = NULL;
216458789a19SVenkata Lakshmi Narayana Gubba 	hu->hdev->cmd_timeout = NULL;
216558789a19SVenkata Lakshmi Narayana Gubba 
2166df1e5c51SPanicker Harish 	del_timer_sync(&qca->wake_retrans_timer);
2167df1e5c51SPanicker Harish 	del_timer_sync(&qca->tx_idle_timer);
2168df1e5c51SPanicker Harish 
2169d841502cSBalakrishna Godavarthi 	/* Stop sending shutdown command if soc crashes. */
2170e5d6468fSRocky Liao 	if (soc_type != QCA_ROME
21714f9ed5bdSRocky Liao 		&& qca->memdump_state == QCA_MEMDUMP_IDLE) {
2172a2780889SHarish Bandi 		qca_send_pre_shutdown_cmd(hdev);
2173010376abSHarish Bandi 		usleep_range(8000, 10000);
2174d841502cSBalakrishna Godavarthi 	}
2175010376abSHarish Bandi 
21763e4be65eSBalakrishna Godavarthi 	qca_power_shutdown(hu);
21773e4be65eSBalakrishna Godavarthi 	return 0;
21783e4be65eSBalakrishna Godavarthi }
21793e4be65eSBalakrishna Godavarthi 
qca_regulator_enable(struct qca_serdev * qcadev)2180a9314e76SBjorn Andersson static int qca_regulator_enable(struct qca_serdev *qcadev)
2181fa9ad876SBalakrishna Godavarthi {
2182a9314e76SBjorn Andersson 	struct qca_power *power = qcadev->bt_power;
2183a9314e76SBjorn Andersson 	int ret;
2184fa9ad876SBalakrishna Godavarthi 
2185a9314e76SBjorn Andersson 	/* Already enabled */
2186a9314e76SBjorn Andersson 	if (power->vregs_on)
2187a9314e76SBjorn Andersson 		return 0;
2188fa9ad876SBalakrishna Godavarthi 
2189a9314e76SBjorn Andersson 	BT_DBG("enabling %d regulators)", power->num_vregs);
2190a9314e76SBjorn Andersson 
2191a9314e76SBjorn Andersson 	ret = regulator_bulk_enable(power->num_vregs, power->vreg_bulk);
2192fa9ad876SBalakrishna Godavarthi 	if (ret)
2193163d42faSBjorn Andersson 		return ret;
2194fa9ad876SBalakrishna Godavarthi 
2195a9314e76SBjorn Andersson 	power->vregs_on = true;
2196fa9ad876SBalakrishna Godavarthi 
219766cb7051SVenkata Lakshmi Narayana Gubba 	ret = clk_prepare_enable(qcadev->susclk);
2198f3d63f50SVenkata Lakshmi Narayana Gubba 	if (ret)
219966cb7051SVenkata Lakshmi Narayana Gubba 		qca_regulator_disable(qcadev);
220066cb7051SVenkata Lakshmi Narayana Gubba 
2201f3d63f50SVenkata Lakshmi Narayana Gubba 	return ret;
2202fa9ad876SBalakrishna Godavarthi }
2203fa9ad876SBalakrishna Godavarthi 
qca_regulator_disable(struct qca_serdev * qcadev)2204a9314e76SBjorn Andersson static void qca_regulator_disable(struct qca_serdev *qcadev)
2205a9314e76SBjorn Andersson {
2206a9314e76SBjorn Andersson 	struct qca_power *power;
2207a9314e76SBjorn Andersson 
2208a9314e76SBjorn Andersson 	if (!qcadev)
2209a9314e76SBjorn Andersson 		return;
2210a9314e76SBjorn Andersson 
2211a9314e76SBjorn Andersson 	power = qcadev->bt_power;
2212a9314e76SBjorn Andersson 
2213a9314e76SBjorn Andersson 	/* Already disabled? */
2214a9314e76SBjorn Andersson 	if (!power->vregs_on)
2215a9314e76SBjorn Andersson 		return;
2216a9314e76SBjorn Andersson 
2217a9314e76SBjorn Andersson 	regulator_bulk_disable(power->num_vregs, power->vreg_bulk);
2218a9314e76SBjorn Andersson 	power->vregs_on = false;
221966cb7051SVenkata Lakshmi Narayana Gubba 
222066cb7051SVenkata Lakshmi Narayana Gubba 	clk_disable_unprepare(qcadev->susclk);
2221a9314e76SBjorn Andersson }
2222a9314e76SBjorn Andersson 
qca_init_regulators(struct qca_power * qca,const struct qca_vreg * vregs,size_t num_vregs)2223fa9ad876SBalakrishna Godavarthi static int qca_init_regulators(struct qca_power *qca,
2224fa9ad876SBalakrishna Godavarthi 				const struct qca_vreg *vregs, size_t num_vregs)
2225fa9ad876SBalakrishna Godavarthi {
2226c29ff107SBjorn Andersson 	struct regulator_bulk_data *bulk;
2227c29ff107SBjorn Andersson 	int ret;
2228fa9ad876SBalakrishna Godavarthi 	int i;
2229fa9ad876SBalakrishna Godavarthi 
2230c29ff107SBjorn Andersson 	bulk = devm_kcalloc(qca->dev, num_vregs, sizeof(*bulk), GFP_KERNEL);
2231c29ff107SBjorn Andersson 	if (!bulk)
2232fa9ad876SBalakrishna Godavarthi 		return -ENOMEM;
2233fa9ad876SBalakrishna Godavarthi 
2234fa9ad876SBalakrishna Godavarthi 	for (i = 0; i < num_vregs; i++)
2235c29ff107SBjorn Andersson 		bulk[i].supply = vregs[i].name;
2236fa9ad876SBalakrishna Godavarthi 
2237c29ff107SBjorn Andersson 	ret = devm_regulator_bulk_get(qca->dev, num_vregs, bulk);
2238c29ff107SBjorn Andersson 	if (ret < 0)
2239c29ff107SBjorn Andersson 		return ret;
2240c29ff107SBjorn Andersson 
2241c29ff107SBjorn Andersson 	for (i = 0; i < num_vregs; i++) {
2242c29ff107SBjorn Andersson 		ret = regulator_set_load(bulk[i].consumer, vregs[i].load_uA);
2243c29ff107SBjorn Andersson 		if (ret)
2244c29ff107SBjorn Andersson 			return ret;
2245c29ff107SBjorn Andersson 	}
2246c29ff107SBjorn Andersson 
2247c29ff107SBjorn Andersson 	qca->vreg_bulk = bulk;
2248163d42faSBjorn Andersson 	qca->num_vregs = num_vregs;
2249c29ff107SBjorn Andersson 
2250c29ff107SBjorn Andersson 	return 0;
2251fa9ad876SBalakrishna Godavarthi }
2252fa9ad876SBalakrishna Godavarthi 
qca_serdev_probe(struct serdev_device * serdev)225305ba533cSThierry Escande static int qca_serdev_probe(struct serdev_device *serdev)
225405ba533cSThierry Escande {
225505ba533cSThierry Escande 	struct qca_serdev *qcadev;
2256ae563183SRocky Liao 	struct hci_dev *hdev;
2257a228f7a4SAbhishek Pandit-Subedi 	const struct qca_device_data *data;
225805ba533cSThierry Escande 	int err;
22598a208b24SRocky Liao 	bool power_ctrl_enabled = true;
226005ba533cSThierry Escande 
226105ba533cSThierry Escande 	qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL);
226205ba533cSThierry Escande 	if (!qcadev)
226305ba533cSThierry Escande 		return -ENOMEM;
226405ba533cSThierry Escande 
226505ba533cSThierry Escande 	qcadev->serdev_hu.serdev = serdev;
22669f3565b8SRocky Liao 	data = device_get_match_data(&serdev->dev);
226705ba533cSThierry Escande 	serdev_device_set_drvdata(serdev, qcadev);
226899c905c6SRocky Liao 	device_property_read_string(&serdev->dev, "firmware-name",
226999c905c6SRocky Liao 					 &qcadev->firmware_name);
227037aee136SChristian Hewitt 	device_property_read_u32(&serdev->dev, "max-speed",
227137aee136SChristian Hewitt 				 &qcadev->oper_speed);
227237aee136SChristian Hewitt 	if (!qcadev->oper_speed)
227337aee136SChristian Hewitt 		BT_DBG("UART will pick default operating speed");
227437aee136SChristian Hewitt 
22751622e563SJohan Hovold 	qcadev->bdaddr_property_broken = device_property_read_bool(&serdev->dev,
22761622e563SJohan Hovold 			"qcom,local-bd-address-broken");
22771622e563SJohan Hovold 
2278691d54d0SNeil Armstrong 	if (data)
2279523760b7SHarish Bandi 		qcadev->btsoc_type = data->soc_type;
2280691d54d0SNeil Armstrong 	else
2281691d54d0SNeil Armstrong 		qcadev->btsoc_type = QCA_ROME;
2282691d54d0SNeil Armstrong 
2283691d54d0SNeil Armstrong 	switch (qcadev->btsoc_type) {
2284691d54d0SNeil Armstrong 	case QCA_WCN3988:
2285691d54d0SNeil Armstrong 	case QCA_WCN3990:
2286691d54d0SNeil Armstrong 	case QCA_WCN3991:
2287691d54d0SNeil Armstrong 	case QCA_WCN3998:
2288691d54d0SNeil Armstrong 	case QCA_WCN6750:
2289691d54d0SNeil Armstrong 	case QCA_WCN6855:
2290e0c1278aSNeil Armstrong 	case QCA_WCN7850:
2291fa9ad876SBalakrishna Godavarthi 		qcadev->bt_power = devm_kzalloc(&serdev->dev,
2292fa9ad876SBalakrishna Godavarthi 						sizeof(struct qca_power),
2293fa9ad876SBalakrishna Godavarthi 						GFP_KERNEL);
2294fa9ad876SBalakrishna Godavarthi 		if (!qcadev->bt_power)
2295fa9ad876SBalakrishna Godavarthi 			return -ENOMEM;
229605ba533cSThierry Escande 
2297fa9ad876SBalakrishna Godavarthi 		qcadev->bt_power->dev = &serdev->dev;
2298fa9ad876SBalakrishna Godavarthi 		err = qca_init_regulators(qcadev->bt_power, data->vregs,
2299fa9ad876SBalakrishna Godavarthi 					  data->num_vregs);
2300fa9ad876SBalakrishna Godavarthi 		if (err) {
2301fa9ad876SBalakrishna Godavarthi 			BT_ERR("Failed to init regulators:%d", err);
2302ae563183SRocky Liao 			return err;
2303fa9ad876SBalakrishna Godavarthi 		}
2304fa9ad876SBalakrishna Godavarthi 
2305fa9ad876SBalakrishna Godavarthi 		qcadev->bt_power->vregs_on = false;
2306fa9ad876SBalakrishna Godavarthi 
2307d8f97da1SVenkata Lakshmi Narayana Gubba 		qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
2308d8f97da1SVenkata Lakshmi Narayana Gubba 					       GPIOD_OUT_LOW);
2309988b77baSBartosz Golaszewski 		if (IS_ERR(qcadev->bt_en) &&
2310095327feSSteev Klimaszewski 		    (data->soc_type == QCA_WCN6750 ||
2311095327feSSteev Klimaszewski 		     data->soc_type == QCA_WCN6855)) {
2312d8f97da1SVenkata Lakshmi Narayana Gubba 			dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n");
2313cd212ca2SBartosz Golaszewski 			return PTR_ERR(qcadev->bt_en);
2314d8f97da1SVenkata Lakshmi Narayana Gubba 		}
2315d8f97da1SVenkata Lakshmi Narayana Gubba 
2316cd212ca2SBartosz Golaszewski 		if (!qcadev->bt_en)
2317cd212ca2SBartosz Golaszewski 			power_ctrl_enabled = false;
2318cd212ca2SBartosz Golaszewski 
2319d8f97da1SVenkata Lakshmi Narayana Gubba 		qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl",
2320d8f97da1SVenkata Lakshmi Narayana Gubba 					       GPIOD_IN);
2321988b77baSBartosz Golaszewski 		if (IS_ERR(qcadev->sw_ctrl) &&
2322095327feSSteev Klimaszewski 		    (data->soc_type == QCA_WCN6750 ||
2323e0c1278aSNeil Armstrong 		     data->soc_type == QCA_WCN6855 ||
2324cd212ca2SBartosz Golaszewski 		     data->soc_type == QCA_WCN7850)) {
2325cd212ca2SBartosz Golaszewski 			dev_err(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
2326cd212ca2SBartosz Golaszewski 			return PTR_ERR(qcadev->sw_ctrl);
2327cd212ca2SBartosz Golaszewski 		}
2328d8f97da1SVenkata Lakshmi Narayana Gubba 
232966cb7051SVenkata Lakshmi Narayana Gubba 		qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
233066cb7051SVenkata Lakshmi Narayana Gubba 		if (IS_ERR(qcadev->susclk)) {
233166cb7051SVenkata Lakshmi Narayana Gubba 			dev_err(&serdev->dev, "failed to acquire clk\n");
233266cb7051SVenkata Lakshmi Narayana Gubba 			return PTR_ERR(qcadev->susclk);
233366cb7051SVenkata Lakshmi Narayana Gubba 		}
233466cb7051SVenkata Lakshmi Narayana Gubba 
2335fa9ad876SBalakrishna Godavarthi 		err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
2336fa9ad876SBalakrishna Godavarthi 		if (err) {
2337fa9ad876SBalakrishna Godavarthi 			BT_ERR("wcn3990 serdev registration failed");
2338ae563183SRocky Liao 			return err;
2339fa9ad876SBalakrishna Godavarthi 		}
2340691d54d0SNeil Armstrong 		break;
2341e5d6468fSRocky Liao 
2342691d54d0SNeil Armstrong 	default:
234377131dfeSRocky Liao 		qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
234405ba533cSThierry Escande 					       GPIOD_OUT_LOW);
2345988b77baSBartosz Golaszewski 		if (IS_ERR(qcadev->bt_en)) {
2346cd212ca2SBartosz Golaszewski 			dev_err(&serdev->dev, "failed to acquire enable gpio\n");
2347cd212ca2SBartosz Golaszewski 			return PTR_ERR(qcadev->bt_en);
234805ba533cSThierry Escande 		}
234905ba533cSThierry Escande 
2350cd212ca2SBartosz Golaszewski 		if (!qcadev->bt_en)
2351cd212ca2SBartosz Golaszewski 			power_ctrl_enabled = false;
2352cd212ca2SBartosz Golaszewski 
235377131dfeSRocky Liao 		qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
23544c07a5d7SDan Carpenter 		if (IS_ERR(qcadev->susclk)) {
23558a208b24SRocky Liao 			dev_warn(&serdev->dev, "failed to acquire clk\n");
23564c07a5d7SDan Carpenter 			return PTR_ERR(qcadev->susclk);
23574c07a5d7SDan Carpenter 		}
235805ba533cSThierry Escande 		err = clk_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ);
235905ba533cSThierry Escande 		if (err)
236005ba533cSThierry Escande 			return err;
236105ba533cSThierry Escande 
236205ba533cSThierry Escande 		err = clk_prepare_enable(qcadev->susclk);
236305ba533cSThierry Escande 		if (err)
236405ba533cSThierry Escande 			return err;
236505ba533cSThierry Escande 
236605ba533cSThierry Escande 		err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
2367ae563183SRocky Liao 		if (err) {
2368ae563183SRocky Liao 			BT_ERR("Rome serdev registration failed");
236905ba533cSThierry Escande 			clk_disable_unprepare(qcadev->susclk);
2370ae563183SRocky Liao 			return err;
2371ae563183SRocky Liao 		}
2372fa9ad876SBalakrishna Godavarthi 	}
237305ba533cSThierry Escande 
2374ae563183SRocky Liao 	hdev = qcadev->serdev_hu.hdev;
237585e90d93SAbhishek Pandit-Subedi 
237685e90d93SAbhishek Pandit-Subedi 	if (power_ctrl_enabled) {
2377ae563183SRocky Liao 		set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
2378ae563183SRocky Liao 		hdev->shutdown = qca_power_off;
23798a208b24SRocky Liao 	}
2380fa9ad876SBalakrishna Godavarthi 
238154780138SAbhishek Pandit-Subedi 	if (data) {
238254780138SAbhishek Pandit-Subedi 		/* Wideband speech support must be set per driver since it can't
238354780138SAbhishek Pandit-Subedi 		 * be queried via hci. Same with the valid le states quirk.
2384a228f7a4SAbhishek Pandit-Subedi 		 */
238554780138SAbhishek Pandit-Subedi 		if (data->capabilities & QCA_CAP_WIDEBAND_SPEECH)
238654780138SAbhishek Pandit-Subedi 			set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
238754780138SAbhishek Pandit-Subedi 				&hdev->quirks);
238854780138SAbhishek Pandit-Subedi 
238954780138SAbhishek Pandit-Subedi 		if (data->capabilities & QCA_CAP_VALID_LE_STATES)
239054780138SAbhishek Pandit-Subedi 			set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
239154780138SAbhishek Pandit-Subedi 	}
2392a228f7a4SAbhishek Pandit-Subedi 
2393ae563183SRocky Liao 	return 0;
239405ba533cSThierry Escande }
239505ba533cSThierry Escande 
qca_serdev_remove(struct serdev_device * serdev)239605ba533cSThierry Escande static void qca_serdev_remove(struct serdev_device *serdev)
239705ba533cSThierry Escande {
239805ba533cSThierry Escande 	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
2399054ec5e9SVenkata Lakshmi Narayana Gubba 	struct qca_power *power = qcadev->bt_power;
240005ba533cSThierry Escande 
2401691d54d0SNeil Armstrong 	switch (qcadev->btsoc_type) {
2402691d54d0SNeil Armstrong 	case QCA_WCN3988:
2403691d54d0SNeil Armstrong 	case QCA_WCN3990:
2404691d54d0SNeil Armstrong 	case QCA_WCN3991:
2405691d54d0SNeil Armstrong 	case QCA_WCN3998:
2406691d54d0SNeil Armstrong 	case QCA_WCN6750:
2407691d54d0SNeil Armstrong 	case QCA_WCN6855:
2408e0c1278aSNeil Armstrong 	case QCA_WCN7850:
2409691d54d0SNeil Armstrong 		if (power->vregs_on) {
2410c2d78273SBalakrishna Godavarthi 			qca_power_shutdown(&qcadev->serdev_hu);
2411691d54d0SNeil Armstrong 			break;
2412691d54d0SNeil Armstrong 		}
2413691d54d0SNeil Armstrong 		fallthrough;
2414691d54d0SNeil Armstrong 
2415691d54d0SNeil Armstrong 	default:
2416691d54d0SNeil Armstrong 		if (qcadev->susclk)
241705ba533cSThierry Escande 			clk_disable_unprepare(qcadev->susclk);
2418691d54d0SNeil Armstrong 	}
2419fa9ad876SBalakrishna Godavarthi 
2420fa9ad876SBalakrishna Godavarthi 	hci_uart_unregister_device(&qcadev->serdev_hu);
242105ba533cSThierry Escande }
242205ba533cSThierry Escande 
qca_serdev_shutdown(struct device * dev)24237e7bbdddSZijun Hu static void qca_serdev_shutdown(struct device *dev)
24247e7bbdddSZijun Hu {
24257e7bbdddSZijun Hu 	int ret;
24267e7bbdddSZijun Hu 	int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
24277e7bbdddSZijun Hu 	struct serdev_device *serdev = to_serdev_device(dev);
24287e7bbdddSZijun Hu 	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
2429272970beSKrzysztof Kozlowski 	struct hci_uart *hu = &qcadev->serdev_hu;
2430272970beSKrzysztof Kozlowski 	struct hci_dev *hdev = hu->hdev;
2431272970beSKrzysztof Kozlowski 	struct qca_data *qca = hu->priv;
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) {
2436272970beSKrzysztof Kozlowski 		if (test_bit(QCA_BT_OFF, &qca->flags) ||
2437272970beSKrzysztof Kozlowski 		    !test_bit(HCI_RUNNING, &hdev->flags))
2438272970beSKrzysztof Kozlowski 			return;
2439272970beSKrzysztof Kozlowski 
24407e7bbdddSZijun Hu 		serdev_device_write_flush(serdev);
24417e7bbdddSZijun Hu 		ret = serdev_device_write_buf(serdev, ibs_wake_cmd,
24427e7bbdddSZijun Hu 					      sizeof(ibs_wake_cmd));
24437e7bbdddSZijun Hu 		if (ret < 0) {
24447e7bbdddSZijun Hu 			BT_ERR("QCA send IBS_WAKE_IND error: %d", ret);
24457e7bbdddSZijun Hu 			return;
24467e7bbdddSZijun Hu 		}
24477e7bbdddSZijun Hu 		serdev_device_wait_until_sent(serdev, timeout);
24487e7bbdddSZijun Hu 		usleep_range(8000, 10000);
24497e7bbdddSZijun Hu 
24507e7bbdddSZijun Hu 		serdev_device_write_flush(serdev);
24517e7bbdddSZijun Hu 		ret = serdev_device_write_buf(serdev, edl_reset_soc_cmd,
24527e7bbdddSZijun Hu 					      sizeof(edl_reset_soc_cmd));
24537e7bbdddSZijun Hu 		if (ret < 0) {
24547e7bbdddSZijun Hu 			BT_ERR("QCA send EDL_RESET_REQ error: %d", ret);
24557e7bbdddSZijun Hu 			return;
24567e7bbdddSZijun Hu 		}
24577e7bbdddSZijun Hu 		serdev_device_wait_until_sent(serdev, timeout);
24587e7bbdddSZijun Hu 		usleep_range(8000, 10000);
24597e7bbdddSZijun Hu 	}
24607e7bbdddSZijun Hu }
24617e7bbdddSZijun Hu 
qca_suspend(struct device * dev)246241d5b25fSClaire Chang static int __maybe_unused qca_suspend(struct device *dev)
246341d5b25fSClaire Chang {
2464feac90d7SZijun Hu 	struct serdev_device *serdev = to_serdev_device(dev);
2465feac90d7SZijun Hu 	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
2466feac90d7SZijun Hu 	struct hci_uart *hu = &qcadev->serdev_hu;
246741d5b25fSClaire Chang 	struct qca_data *qca = hu->priv;
246841d5b25fSClaire Chang 	unsigned long flags;
2469e2a119cdSMatthias Kaehlcke 	bool tx_pending = false;
247041d5b25fSClaire Chang 	int ret = 0;
247141d5b25fSClaire Chang 	u8 cmd;
24722be43abaSVenkata Lakshmi Narayana Gubba 	u32 wait_timeout = 0;
247341d5b25fSClaire Chang 
247441d5b25fSClaire Chang 	set_bit(QCA_SUSPENDING, &qca->flags);
247541d5b25fSClaire Chang 
247655c0bd77SVenkata Lakshmi Narayana Gubba 	/* if BT SoC is running with default firmware then it does not
247755c0bd77SVenkata Lakshmi Narayana Gubba 	 * support in-band sleep
247855c0bd77SVenkata Lakshmi Narayana Gubba 	 */
247955c0bd77SVenkata Lakshmi Narayana Gubba 	if (test_bit(QCA_ROM_FW, &qca->flags))
248055c0bd77SVenkata Lakshmi Narayana Gubba 		return 0;
248155c0bd77SVenkata Lakshmi Narayana Gubba 
2482ad3a9c0eSVenkata Lakshmi Narayana Gubba 	/* During SSR after memory dump collection, controller will be
2483ad3a9c0eSVenkata Lakshmi Narayana Gubba 	 * powered off and then powered on.If controller is powered off
2484ad3a9c0eSVenkata Lakshmi Narayana Gubba 	 * during SSR then we should wait until SSR is completed.
2485ad3a9c0eSVenkata Lakshmi Narayana Gubba 	 */
2486ad3a9c0eSVenkata Lakshmi Narayana Gubba 	if (test_bit(QCA_BT_OFF, &qca->flags) &&
2487ad3a9c0eSVenkata Lakshmi Narayana Gubba 	    !test_bit(QCA_SSR_TRIGGERED, &qca->flags))
24882be43abaSVenkata Lakshmi Narayana Gubba 		return 0;
24892be43abaSVenkata Lakshmi Narayana Gubba 
24901bb0c663SVenkata Lakshmi Narayana Gubba 	if (test_bit(QCA_IBS_DISABLED, &qca->flags) ||
24911bb0c663SVenkata Lakshmi Narayana Gubba 	    test_bit(QCA_SSR_TRIGGERED, &qca->flags)) {
24922be43abaSVenkata Lakshmi Narayana Gubba 		wait_timeout = test_bit(QCA_SSR_TRIGGERED, &qca->flags) ?
24932be43abaSVenkata Lakshmi Narayana Gubba 					IBS_DISABLE_SSR_TIMEOUT_MS :
24942be43abaSVenkata Lakshmi Narayana Gubba 					FW_DOWNLOAD_TIMEOUT_MS;
24952be43abaSVenkata Lakshmi Narayana Gubba 
24962be43abaSVenkata Lakshmi Narayana Gubba 		/* QCA_IBS_DISABLED flag is set to true, During FW download
24972be43abaSVenkata Lakshmi Narayana Gubba 		 * and during memory dump collection. It is reset to false,
2498ad3a9c0eSVenkata Lakshmi Narayana Gubba 		 * After FW download complete.
24992be43abaSVenkata Lakshmi Narayana Gubba 		 */
25002be43abaSVenkata Lakshmi Narayana Gubba 		wait_on_bit_timeout(&qca->flags, QCA_IBS_DISABLED,
25012be43abaSVenkata Lakshmi Narayana Gubba 			    TASK_UNINTERRUPTIBLE, msecs_to_jiffies(wait_timeout));
25022be43abaSVenkata Lakshmi Narayana Gubba 
25032be43abaSVenkata Lakshmi Narayana Gubba 		if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
25042be43abaSVenkata Lakshmi Narayana Gubba 			bt_dev_err(hu->hdev, "SSR or FW download time out");
25052be43abaSVenkata Lakshmi Narayana Gubba 			ret = -ETIMEDOUT;
25062be43abaSVenkata Lakshmi Narayana Gubba 			goto error;
25072be43abaSVenkata Lakshmi Narayana Gubba 		}
25082be43abaSVenkata Lakshmi Narayana Gubba 	}
25092be43abaSVenkata Lakshmi Narayana Gubba 
251041d5b25fSClaire Chang 	cancel_work_sync(&qca->ws_awake_device);
251141d5b25fSClaire Chang 	cancel_work_sync(&qca->ws_awake_rx);
251241d5b25fSClaire Chang 
251341d5b25fSClaire Chang 	spin_lock_irqsave_nested(&qca->hci_ibs_lock,
251441d5b25fSClaire Chang 				 flags, SINGLE_DEPTH_NESTING);
251541d5b25fSClaire Chang 
251641d5b25fSClaire Chang 	switch (qca->tx_ibs_state) {
251741d5b25fSClaire Chang 	case HCI_IBS_TX_WAKING:
251841d5b25fSClaire Chang 		del_timer(&qca->wake_retrans_timer);
2519a3b4cbfcSGustavo A. R. Silva 		fallthrough;
252041d5b25fSClaire Chang 	case HCI_IBS_TX_AWAKE:
252141d5b25fSClaire Chang 		del_timer(&qca->tx_idle_timer);
252241d5b25fSClaire Chang 
252341d5b25fSClaire Chang 		serdev_device_write_flush(hu->serdev);
252441d5b25fSClaire Chang 		cmd = HCI_IBS_SLEEP_IND;
252541d5b25fSClaire Chang 		ret = serdev_device_write_buf(hu->serdev, &cmd, sizeof(cmd));
252641d5b25fSClaire Chang 
252741d5b25fSClaire Chang 		if (ret < 0) {
252841d5b25fSClaire Chang 			BT_ERR("Failed to send SLEEP to device");
252941d5b25fSClaire Chang 			break;
253041d5b25fSClaire Chang 		}
253141d5b25fSClaire Chang 
253241d5b25fSClaire Chang 		qca->tx_ibs_state = HCI_IBS_TX_ASLEEP;
253341d5b25fSClaire Chang 		qca->ibs_sent_slps++;
2534e2a119cdSMatthias Kaehlcke 		tx_pending = true;
253541d5b25fSClaire Chang 		break;
253641d5b25fSClaire Chang 
253741d5b25fSClaire Chang 	case HCI_IBS_TX_ASLEEP:
253841d5b25fSClaire Chang 		break;
253941d5b25fSClaire Chang 
254041d5b25fSClaire Chang 	default:
254141d5b25fSClaire Chang 		BT_ERR("Spurious tx state %d", qca->tx_ibs_state);
254241d5b25fSClaire Chang 		ret = -EINVAL;
254341d5b25fSClaire Chang 		break;
254441d5b25fSClaire Chang 	}
254541d5b25fSClaire Chang 
254641d5b25fSClaire Chang 	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
254741d5b25fSClaire Chang 
254841d5b25fSClaire Chang 	if (ret < 0)
254941d5b25fSClaire Chang 		goto error;
255041d5b25fSClaire Chang 
2551e2a119cdSMatthias Kaehlcke 	if (tx_pending) {
255241d5b25fSClaire Chang 		serdev_device_wait_until_sent(hu->serdev,
255341d5b25fSClaire Chang 					      msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
2554201a1124SBalakrishna Godavarthi 		serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
2555e2a119cdSMatthias Kaehlcke 	}
255641d5b25fSClaire Chang 
255741d5b25fSClaire Chang 	/* Wait for HCI_IBS_SLEEP_IND sent by device to indicate its Tx is going
255841d5b25fSClaire Chang 	 * to sleep, so that the packet does not wake the system later.
255941d5b25fSClaire Chang 	 */
256041d5b25fSClaire Chang 	ret = wait_event_interruptible_timeout(qca->suspend_wait_q,
256141d5b25fSClaire Chang 			qca->rx_ibs_state == HCI_IBS_RX_ASLEEP,
256241d5b25fSClaire Chang 			msecs_to_jiffies(IBS_BTSOC_TX_IDLE_TIMEOUT_MS));
25634da385f7SMatthias Kaehlcke 	if (ret == 0) {
25644da385f7SMatthias Kaehlcke 		ret = -ETIMEDOUT;
25654da385f7SMatthias Kaehlcke 		goto error;
2566eff981f6SMatthias Kaehlcke 	}
256741d5b25fSClaire Chang 
25684da385f7SMatthias Kaehlcke 	return 0;
256941d5b25fSClaire Chang 
257041d5b25fSClaire Chang error:
257141d5b25fSClaire Chang 	clear_bit(QCA_SUSPENDING, &qca->flags);
257241d5b25fSClaire Chang 
257341d5b25fSClaire Chang 	return ret;
257441d5b25fSClaire Chang }
257541d5b25fSClaire Chang 
qca_resume(struct device * dev)257641d5b25fSClaire Chang static int __maybe_unused qca_resume(struct device *dev)
257741d5b25fSClaire Chang {
2578feac90d7SZijun Hu 	struct serdev_device *serdev = to_serdev_device(dev);
2579feac90d7SZijun Hu 	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
2580feac90d7SZijun Hu 	struct hci_uart *hu = &qcadev->serdev_hu;
258141d5b25fSClaire Chang 	struct qca_data *qca = hu->priv;
258241d5b25fSClaire Chang 
258341d5b25fSClaire Chang 	clear_bit(QCA_SUSPENDING, &qca->flags);
258441d5b25fSClaire Chang 
258541d5b25fSClaire Chang 	return 0;
258641d5b25fSClaire Chang }
258741d5b25fSClaire Chang 
258841d5b25fSClaire Chang static SIMPLE_DEV_PM_OPS(qca_pm_ops, qca_suspend, qca_resume);
258941d5b25fSClaire Chang 
2590e5d6468fSRocky Liao #ifdef CONFIG_OF
259105ba533cSThierry Escande static const struct of_device_id qca_bluetooth_of_match[] = {
2592a381ee26STim Jiang 	{ .compatible = "qcom,qca2066-bt", .data = &qca_soc_data_qca2066},
259305ba533cSThierry Escande 	{ .compatible = "qcom,qca6174-bt" },
2594e5d6468fSRocky Liao 	{ .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390},
259531d4ab85SChristian Hewitt 	{ .compatible = "qcom,qca9377-bt" },
2596f904feefSLuca Weiss 	{ .compatible = "qcom,wcn3988-bt", .data = &qca_soc_data_wcn3988},
2597523760b7SHarish Bandi 	{ .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990},
25987d250a06SBalakrishna Godavarthi 	{ .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3991},
2599523760b7SHarish Bandi 	{ .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998},
2600d8f97da1SVenkata Lakshmi Narayana Gubba 	{ .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750},
2601095327feSSteev Klimaszewski 	{ .compatible = "qcom,wcn6855-bt", .data = &qca_soc_data_wcn6855},
2602e0c1278aSNeil Armstrong 	{ .compatible = "qcom,wcn7850-bt", .data = &qca_soc_data_wcn7850},
260305ba533cSThierry Escande 	{ /* sentinel */ }
260405ba533cSThierry Escande };
260505ba533cSThierry Escande MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
2606e5d6468fSRocky Liao #endif
2607e5d6468fSRocky Liao 
2608e5d6468fSRocky Liao #ifdef CONFIG_ACPI
2609e5d6468fSRocky Liao static const struct acpi_device_id qca_bluetooth_acpi_match[] = {
2610a381ee26STim Jiang 	{ "QCOM2066", (kernel_ulong_t)&qca_soc_data_qca2066 },
2611e5d6468fSRocky Liao 	{ "QCOM6390", (kernel_ulong_t)&qca_soc_data_qca6390 },
2612e5d6468fSRocky Liao 	{ "DLA16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
2613e5d6468fSRocky Liao 	{ "DLB16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
2614e5d6468fSRocky Liao 	{ "DLB26390", (kernel_ulong_t)&qca_soc_data_qca6390 },
2615e5d6468fSRocky Liao 	{ },
2616e5d6468fSRocky Liao };
2617e5d6468fSRocky Liao MODULE_DEVICE_TABLE(acpi, qca_bluetooth_acpi_match);
2618e5d6468fSRocky Liao #endif
2619e5d6468fSRocky Liao 
26206ce95a30SSai Teja Aluvala #ifdef CONFIG_DEV_COREDUMP
hciqca_coredump(struct device * dev)26216ce95a30SSai Teja Aluvala static void hciqca_coredump(struct device *dev)
26226ce95a30SSai Teja Aluvala {
26236ce95a30SSai Teja Aluvala 	struct serdev_device *serdev = to_serdev_device(dev);
26246ce95a30SSai Teja Aluvala 	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
26256ce95a30SSai Teja Aluvala 	struct hci_uart *hu = &qcadev->serdev_hu;
26266ce95a30SSai Teja Aluvala 	struct hci_dev  *hdev = hu->hdev;
26276ce95a30SSai Teja Aluvala 
26286ce95a30SSai Teja Aluvala 	if (hdev->dump.coredump)
26296ce95a30SSai Teja Aluvala 		hdev->dump.coredump(hdev);
26306ce95a30SSai Teja Aluvala }
26316ce95a30SSai Teja Aluvala #endif
263205ba533cSThierry Escande 
263305ba533cSThierry Escande static struct serdev_device_driver qca_serdev_driver = {
263405ba533cSThierry Escande 	.probe = qca_serdev_probe,
263505ba533cSThierry Escande 	.remove = qca_serdev_remove,
263605ba533cSThierry Escande 	.driver = {
263705ba533cSThierry Escande 		.name = "hci_uart_qca",
2638e5d6468fSRocky Liao 		.of_match_table = of_match_ptr(qca_bluetooth_of_match),
2639e5d6468fSRocky Liao 		.acpi_match_table = ACPI_PTR(qca_bluetooth_acpi_match),
26407e7bbdddSZijun Hu 		.shutdown = qca_serdev_shutdown,
264141d5b25fSClaire Chang 		.pm = &qca_pm_ops,
26426ce95a30SSai Teja Aluvala #ifdef CONFIG_DEV_COREDUMP
26436ce95a30SSai Teja Aluvala 		.coredump = hciqca_coredump,
26446ce95a30SSai Teja Aluvala #endif
264505ba533cSThierry Escande 	},
264605ba533cSThierry Escande };
264705ba533cSThierry Escande 
qca_init(void)26480ff252c1SBen Young Tae Kim int __init qca_init(void)
26490ff252c1SBen Young Tae Kim {
265005ba533cSThierry Escande 	serdev_device_driver_register(&qca_serdev_driver);
265105ba533cSThierry Escande 
26520ff252c1SBen Young Tae Kim 	return hci_uart_register_proto(&qca_proto);
26530ff252c1SBen Young Tae Kim }
26540ff252c1SBen Young Tae Kim 
qca_deinit(void)26550ff252c1SBen Young Tae Kim int __exit qca_deinit(void)
26560ff252c1SBen Young Tae Kim {
265705ba533cSThierry Escande 	serdev_device_driver_unregister(&qca_serdev_driver);
265805ba533cSThierry Escande 
26590ff252c1SBen Young Tae Kim 	return hci_uart_unregister_proto(&qca_proto);
26600ff252c1SBen Young Tae Kim }
2661