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