2015-08-11 00:24:17 +03:00
/*
* Bluetooth Software UART Qualcomm protocol
*
* HCI_IBS ( HCI In - Band Sleep ) is Qualcomm ' s power management
* protocol extension to H4 .
*
* Copyright ( C ) 2007 Texas Instruments , Inc .
2018-08-03 15:16:32 +03:00
* Copyright ( c ) 2010 , 2012 , 2018 The Linux Foundation . All rights reserved .
2015-08-11 00:24:17 +03:00
*
* Acknowledgements :
* This file is based on hci_ll . c , which was . . .
* Written by Ohad Ben - Cohen < ohad @ bencohen . org >
* which was in turn based on hci_h4 . c , which was written
* by Maxim Krasnyansky and Marcel Holtmann .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include <linux/kernel.h>
2018-03-29 22:15:24 +03:00
# include <linux/clk.h>
2015-08-11 00:24:17 +03:00
# include <linux/debugfs.h>
2018-08-03 15:16:32 +03:00
# include <linux/delay.h>
# include <linux/device.h>
2018-03-29 22:15:24 +03:00
# include <linux/gpio/consumer.h>
# include <linux/mod_devicetable.h>
# include <linux/module.h>
2018-08-03 15:16:32 +03:00
# include <linux/of_device.h>
# include <linux/platform_device.h>
# include <linux/regulator/consumer.h>
2018-03-29 22:15:24 +03:00
# include <linux/serdev.h>
2018-10-16 17:21:35 +03:00
# include <asm/unaligned.h>
2015-08-11 00:24:17 +03:00
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
# include "hci_uart.h"
# include "btqca.h"
/* HCI_IBS protocol messages */
# define HCI_IBS_SLEEP_IND 0xFE
# define HCI_IBS_WAKE_IND 0xFD
# define HCI_IBS_WAKE_ACK 0xFC
2015-08-31 00:05:32 +03:00
# define HCI_MAX_IBS_SIZE 10
2015-08-11 00:24:17 +03:00
2015-08-31 00:05:32 +03:00
# define IBS_WAKE_RETRANS_TIMEOUT_MS 100
# define IBS_TX_IDLE_TIMEOUT_MS 2000
2019-02-28 02:52:23 +03:00
# define CMD_TRANS_TIMEOUT_MS 100
2015-08-11 00:24:17 +03:00
2018-03-29 22:15:24 +03:00
/* susclk rate */
# define SUSCLK_RATE_32KHZ 32768
2018-10-16 17:21:35 +03:00
/* Controller debug log header */
# define QCA_DEBUG_HANDLE 0x2EDC
2019-04-30 02:21:30 +03:00
enum qca_flags {
QCA_IBS_ENABLED ,
} ;
2015-08-11 00:24:17 +03:00
/* HCI_IBS transmit side sleep protocol states */
enum tx_ibs_states {
HCI_IBS_TX_ASLEEP ,
HCI_IBS_TX_WAKING ,
HCI_IBS_TX_AWAKE ,
} ;
/* HCI_IBS receive side sleep protocol states */
enum rx_states {
HCI_IBS_RX_ASLEEP ,
HCI_IBS_RX_AWAKE ,
} ;
/* HCI_IBS transmit and receive side clock state vote */
enum hci_ibs_clock_state_vote {
HCI_IBS_VOTE_STATS_UPDATE ,
HCI_IBS_TX_VOTE_CLOCK_ON ,
HCI_IBS_TX_VOTE_CLOCK_OFF ,
HCI_IBS_RX_VOTE_CLOCK_ON ,
HCI_IBS_RX_VOTE_CLOCK_OFF ,
} ;
struct qca_data {
struct hci_uart * hu ;
struct sk_buff * rx_skb ;
struct sk_buff_head txq ;
struct sk_buff_head tx_wait_q ; /* HCI_IBS wait queue */
spinlock_t hci_ibs_lock ; /* HCI_IBS state lock */
u8 tx_ibs_state ; /* HCI_IBS transmit side power state*/
u8 rx_ibs_state ; /* HCI_IBS receive side power state */
2015-09-27 01:04:07 +03:00
bool tx_vote ; /* Clock must be on for TX */
bool rx_vote ; /* Clock must be on for RX */
2015-08-11 00:24:17 +03:00
struct timer_list tx_idle_timer ;
u32 tx_idle_delay ;
struct timer_list wake_retrans_timer ;
u32 wake_retrans ;
struct workqueue_struct * workqueue ;
struct work_struct ws_awake_rx ;
struct work_struct ws_awake_device ;
struct work_struct ws_rx_vote_off ;
struct work_struct ws_tx_vote_off ;
unsigned long flags ;
/* For debugging purpose */
u64 ibs_sent_wacks ;
u64 ibs_sent_slps ;
u64 ibs_sent_wakes ;
u64 ibs_recv_wacks ;
u64 ibs_recv_slps ;
u64 ibs_recv_wakes ;
u64 vote_last_jif ;
u32 vote_on_ms ;
u32 vote_off_ms ;
u64 tx_votes_on ;
u64 rx_votes_on ;
u64 tx_votes_off ;
u64 rx_votes_off ;
u64 votes_on ;
u64 votes_off ;
} ;
2018-08-03 15:16:29 +03:00
enum qca_speed_type {
QCA_INIT_SPEED = 1 ,
QCA_OPER_SPEED
} ;
2018-08-03 15:16:32 +03:00
/*
* Voltage regulator information required for configuring the
* QCA Bluetooth chipset
*/
struct qca_vreg {
const char * name ;
unsigned int min_uV ;
unsigned int max_uV ;
unsigned int load_uA ;
} ;
struct qca_vreg_data {
enum qca_btsoc_type soc_type ;
struct qca_vreg * vregs ;
size_t num_vregs ;
} ;
/*
* Platform data for the QCA Bluetooth power driver .
*/
struct qca_power {
struct device * dev ;
const struct qca_vreg_data * vreg_data ;
struct regulator_bulk_data * vreg_bulk ;
bool vregs_on ;
} ;
2018-03-29 22:15:24 +03:00
struct qca_serdev {
struct hci_uart serdev_hu ;
struct gpio_desc * bt_en ;
struct clk * susclk ;
2018-08-03 15:16:32 +03:00
enum qca_btsoc_type btsoc_type ;
struct qca_power * bt_power ;
u32 init_speed ;
u32 oper_speed ;
2018-03-29 22:15:24 +03:00
} ;
2018-08-03 15:16:32 +03:00
static int qca_power_setup ( struct hci_uart * hu , bool on ) ;
2018-08-22 15:20:05 +03:00
static void qca_power_shutdown ( struct hci_uart * hu ) ;
2018-09-24 17:44:45 +03:00
static int qca_power_off ( struct hci_dev * hdev ) ;
2018-08-03 15:16:32 +03:00
2019-03-11 21:38:31 +03:00
static enum qca_btsoc_type qca_soc_type ( struct hci_uart * hu )
{
enum qca_btsoc_type soc_type ;
if ( hu - > serdev ) {
struct qca_serdev * qsd = serdev_device_get_drvdata ( hu - > serdev ) ;
soc_type = qsd - > btsoc_type ;
} else {
soc_type = QCA_ROME ;
}
return soc_type ;
}
2015-08-11 00:24:17 +03:00
static void __serial_clock_on ( struct tty_struct * tty )
{
/* TODO: Some chipset requires to enable UART clock on client
* side to save power consumption or manual work is required .
* Please put your code to control UART clock here if needed
*/
}
static void __serial_clock_off ( struct tty_struct * tty )
{
/* TODO: Some chipset requires to disable UART clock on client
* side to save power consumption or manual work is required .
* Please put your code to control UART clock off here if needed
*/
}
/* serial_clock_vote needs to be called with the ibs lock held */
static void serial_clock_vote ( unsigned long vote , struct hci_uart * hu )
{
struct qca_data * qca = hu - > priv ;
unsigned int diff ;
bool old_vote = ( qca - > tx_vote | qca - > rx_vote ) ;
bool new_vote ;
switch ( vote ) {
case HCI_IBS_VOTE_STATS_UPDATE :
diff = jiffies_to_msecs ( jiffies - qca - > vote_last_jif ) ;
if ( old_vote )
qca - > vote_off_ms + = diff ;
else
qca - > vote_on_ms + = diff ;
return ;
case HCI_IBS_TX_VOTE_CLOCK_ON :
qca - > tx_vote = true ;
qca - > tx_votes_on + + ;
new_vote = true ;
break ;
case HCI_IBS_RX_VOTE_CLOCK_ON :
qca - > rx_vote = true ;
qca - > rx_votes_on + + ;
new_vote = true ;
break ;
case HCI_IBS_TX_VOTE_CLOCK_OFF :
qca - > tx_vote = false ;
qca - > tx_votes_off + + ;
new_vote = qca - > rx_vote | qca - > tx_vote ;
break ;
case HCI_IBS_RX_VOTE_CLOCK_OFF :
qca - > rx_vote = false ;
qca - > rx_votes_off + + ;
new_vote = qca - > rx_vote | qca - > tx_vote ;
break ;
default :
BT_ERR ( " Voting irregularity " ) ;
return ;
}
if ( new_vote ! = old_vote ) {
if ( new_vote )
__serial_clock_on ( hu - > tty ) ;
else
__serial_clock_off ( hu - > tty ) ;
2015-09-15 15:19:45 +03:00
BT_DBG ( " Vote serial clock %s(%s) " , new_vote ? " true " : " false " ,
vote ? " true " : " false " ) ;
2015-08-11 00:24:17 +03:00
diff = jiffies_to_msecs ( jiffies - qca - > vote_last_jif ) ;
if ( new_vote ) {
qca - > votes_on + + ;
qca - > vote_off_ms + = diff ;
} else {
qca - > votes_off + + ;
qca - > vote_on_ms + = diff ;
}
qca - > vote_last_jif = jiffies ;
}
}
/* Builds and sends an HCI_IBS command packet.
* These are very simple packets with only 1 cmd byte .
*/
static int send_hci_ibs_cmd ( u8 cmd , struct hci_uart * hu )
{
int err = 0 ;
struct sk_buff * skb = NULL ;
struct qca_data * qca = hu - > priv ;
BT_DBG ( " hu %p send hci ibs cmd 0x%x " , hu , cmd ) ;
skb = bt_skb_alloc ( 1 , GFP_ATOMIC ) ;
if ( ! skb ) {
BT_ERR ( " Failed to allocate memory for HCI_IBS packet " ) ;
return - ENOMEM ;
}
/* Assign HCI_IBS type */
networking: add and use skb_put_u8()
Joe and Bjørn suggested that it'd be nicer to not have the
cast in the fairly common case of doing
*(u8 *)skb_put(skb, 1) = c;
Add skb_put_u8() for this case, and use it across the code,
using the following spatch:
@@
expression SKB, C, S;
typedef u8;
identifier fn = {skb_put};
fresh identifier fn2 = fn ## "_u8";
@@
- *(u8 *)fn(SKB, S) = C;
+ fn2(SKB, C);
Note that due to the "S", the spatch isn't perfect, it should
have checked that S is 1, but there's also places that use a
sizeof expression like sizeof(var) or sizeof(u8) etc. Turns
out that nobody ever did something like
*(u8 *)skb_put(skb, 2) = c;
which would be wrong anyway since the second byte wouldn't be
initialized.
Suggested-by: Joe Perches <joe@perches.com>
Suggested-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:24 +03:00
skb_put_u8 ( skb , cmd ) ;
2015-08-11 00:24:17 +03:00
skb_queue_tail ( & qca - > txq , skb ) ;
return err ;
}
static void qca_wq_awake_device ( struct work_struct * work )
{
struct qca_data * qca = container_of ( work , struct qca_data ,
ws_awake_device ) ;
struct hci_uart * hu = qca - > hu ;
unsigned long retrans_delay ;
BT_DBG ( " hu %p wq awake device " , hu ) ;
/* Vote for serial clock */
serial_clock_vote ( HCI_IBS_TX_VOTE_CLOCK_ON , hu ) ;
spin_lock ( & qca - > hci_ibs_lock ) ;
/* Send wake indication to device */
if ( send_hci_ibs_cmd ( HCI_IBS_WAKE_IND , hu ) < 0 )
BT_ERR ( " Failed to send WAKE to device " ) ;
qca - > ibs_sent_wakes + + ;
/* Start retransmit timer */
retrans_delay = msecs_to_jiffies ( qca - > wake_retrans ) ;
mod_timer ( & qca - > wake_retrans_timer , jiffies + retrans_delay ) ;
spin_unlock ( & qca - > hci_ibs_lock ) ;
/* Actually send the packets */
hci_uart_tx_wakeup ( hu ) ;
}
static void qca_wq_awake_rx ( struct work_struct * work )
{
struct qca_data * qca = container_of ( work , struct qca_data ,
ws_awake_rx ) ;
struct hci_uart * hu = qca - > hu ;
BT_DBG ( " hu %p wq awake rx " , hu ) ;
serial_clock_vote ( HCI_IBS_RX_VOTE_CLOCK_ON , hu ) ;
spin_lock ( & qca - > hci_ibs_lock ) ;
qca - > rx_ibs_state = HCI_IBS_RX_AWAKE ;
/* Always acknowledge device wake up,
* sending IBS message doesn ' t count as TX ON .
*/
if ( send_hci_ibs_cmd ( HCI_IBS_WAKE_ACK , hu ) < 0 )
BT_ERR ( " Failed to acknowledge device wake up " ) ;
qca - > ibs_sent_wacks + + ;
spin_unlock ( & qca - > hci_ibs_lock ) ;
/* Actually send the packets */
hci_uart_tx_wakeup ( hu ) ;
}
static void qca_wq_serial_rx_clock_vote_off ( struct work_struct * work )
{
struct qca_data * qca = container_of ( work , struct qca_data ,
ws_rx_vote_off ) ;
struct hci_uart * hu = qca - > hu ;
BT_DBG ( " hu %p rx clock vote off " , hu ) ;
serial_clock_vote ( HCI_IBS_RX_VOTE_CLOCK_OFF , hu ) ;
}
static void qca_wq_serial_tx_clock_vote_off ( struct work_struct * work )
{
struct qca_data * qca = container_of ( work , struct qca_data ,
ws_tx_vote_off ) ;
struct hci_uart * hu = qca - > hu ;
BT_DBG ( " hu %p tx clock vote off " , hu ) ;
/* Run HCI tx handling unlocked */
hci_uart_tx_wakeup ( hu ) ;
/* Now that message queued to tty driver, vote for tty clocks off.
* It is up to the tty driver to pend the clocks off until tx done .
*/
serial_clock_vote ( HCI_IBS_TX_VOTE_CLOCK_OFF , hu ) ;
}
2017-10-05 03:54:29 +03:00
static void hci_ibs_tx_idle_timeout ( struct timer_list * t )
2015-08-11 00:24:17 +03:00
{
2017-10-05 03:54:29 +03:00
struct qca_data * qca = from_timer ( qca , t , tx_idle_timer ) ;
struct hci_uart * hu = qca - > hu ;
2015-08-11 00:24:17 +03:00
unsigned long flags ;
BT_DBG ( " hu %p idle timeout in %d state " , hu , qca - > tx_ibs_state ) ;
spin_lock_irqsave_nested ( & qca - > hci_ibs_lock ,
flags , SINGLE_DEPTH_NESTING ) ;
switch ( qca - > tx_ibs_state ) {
case HCI_IBS_TX_AWAKE :
/* TX_IDLE, go to SLEEP */
if ( send_hci_ibs_cmd ( HCI_IBS_SLEEP_IND , hu ) < 0 ) {
BT_ERR ( " Failed to send SLEEP to device " ) ;
break ;
}
qca - > tx_ibs_state = HCI_IBS_TX_ASLEEP ;
qca - > ibs_sent_slps + + ;
queue_work ( qca - > workqueue , & qca - > ws_tx_vote_off ) ;
break ;
case HCI_IBS_TX_ASLEEP :
case HCI_IBS_TX_WAKING :
/* Fall through */
default :
2017-02-17 22:58:10 +03:00
BT_ERR ( " Spurious timeout tx state %d " , qca - > tx_ibs_state ) ;
2015-08-11 00:24:17 +03:00
break ;
}
spin_unlock_irqrestore ( & qca - > hci_ibs_lock , flags ) ;
}
2017-10-05 03:54:29 +03:00
static void hci_ibs_wake_retrans_timeout ( struct timer_list * t )
2015-08-11 00:24:17 +03:00
{
2017-10-05 03:54:29 +03:00
struct qca_data * qca = from_timer ( qca , t , wake_retrans_timer ) ;
struct hci_uart * hu = qca - > hu ;
2015-08-11 00:24:17 +03:00
unsigned long flags , retrans_delay ;
2015-09-28 11:03:24 +03:00
bool retransmit = false ;
2015-08-11 00:24:17 +03:00
BT_DBG ( " hu %p wake retransmit timeout in %d state " ,
hu , qca - > tx_ibs_state ) ;
spin_lock_irqsave_nested ( & qca - > hci_ibs_lock ,
flags , SINGLE_DEPTH_NESTING ) ;
switch ( qca - > tx_ibs_state ) {
case HCI_IBS_TX_WAKING :
/* No WAKE_ACK, retransmit WAKE */
2015-09-28 11:03:24 +03:00
retransmit = true ;
2015-08-11 00:24:17 +03:00
if ( send_hci_ibs_cmd ( HCI_IBS_WAKE_IND , hu ) < 0 ) {
BT_ERR ( " Failed to acknowledge device wake up " ) ;
break ;
}
qca - > ibs_sent_wakes + + ;
retrans_delay = msecs_to_jiffies ( qca - > wake_retrans ) ;
mod_timer ( & qca - > wake_retrans_timer , jiffies + retrans_delay ) ;
break ;
case HCI_IBS_TX_ASLEEP :
case HCI_IBS_TX_AWAKE :
/* Fall through */
default :
2017-02-17 22:58:10 +03:00
BT_ERR ( " Spurious timeout tx state %d " , qca - > tx_ibs_state ) ;
2015-08-11 00:24:17 +03:00
break ;
}
spin_unlock_irqrestore ( & qca - > hci_ibs_lock , flags ) ;
if ( retransmit )
hci_uart_tx_wakeup ( hu ) ;
}
/* Initialize protocol */
static int qca_open ( struct hci_uart * hu )
{
2018-03-29 22:15:24 +03:00
struct qca_serdev * qcadev ;
2015-08-11 00:24:17 +03:00
struct qca_data * qca ;
2018-08-03 15:16:32 +03:00
int ret ;
2015-08-11 00:24:17 +03:00
BT_DBG ( " hu %p qca_open " , hu ) ;
2018-07-23 06:56:51 +03:00
qca = kzalloc ( sizeof ( struct qca_data ) , GFP_KERNEL ) ;
2015-08-11 00:24:17 +03:00
if ( ! qca )
return - ENOMEM ;
skb_queue_head_init ( & qca - > txq ) ;
skb_queue_head_init ( & qca - > tx_wait_q ) ;
spin_lock_init ( & qca - > hci_ibs_lock ) ;
2016-08-30 20:12:53 +03:00
qca - > workqueue = alloc_ordered_workqueue ( " qca_wq " , 0 ) ;
2015-08-11 00:24:17 +03:00
if ( ! qca - > workqueue ) {
BT_ERR ( " QCA Workqueue not initialized properly " ) ;
kfree ( qca ) ;
return - ENOMEM ;
}
INIT_WORK ( & qca - > ws_awake_rx , qca_wq_awake_rx ) ;
INIT_WORK ( & qca - > ws_awake_device , qca_wq_awake_device ) ;
INIT_WORK ( & qca - > ws_rx_vote_off , qca_wq_serial_rx_clock_vote_off ) ;
INIT_WORK ( & qca - > ws_tx_vote_off , qca_wq_serial_tx_clock_vote_off ) ;
qca - > hu = hu ;
/* Assume we start with both sides asleep -- extra wakes OK */
qca - > tx_ibs_state = HCI_IBS_TX_ASLEEP ;
qca - > rx_ibs_state = HCI_IBS_RX_ASLEEP ;
/* clocks actually on, but we start votes off */
qca - > tx_vote = false ;
qca - > rx_vote = false ;
qca - > flags = 0 ;
qca - > ibs_sent_wacks = 0 ;
qca - > ibs_sent_slps = 0 ;
qca - > ibs_sent_wakes = 0 ;
qca - > ibs_recv_wacks = 0 ;
qca - > ibs_recv_slps = 0 ;
qca - > ibs_recv_wakes = 0 ;
qca - > vote_last_jif = jiffies ;
qca - > vote_on_ms = 0 ;
qca - > vote_off_ms = 0 ;
qca - > votes_on = 0 ;
qca - > votes_off = 0 ;
qca - > tx_votes_on = 0 ;
qca - > tx_votes_off = 0 ;
qca - > rx_votes_on = 0 ;
qca - > rx_votes_off = 0 ;
hu - > priv = qca ;
2018-03-29 22:15:24 +03:00
if ( hu - > serdev ) {
qcadev = serdev_device_get_drvdata ( hu - > serdev ) ;
2019-04-26 16:56:01 +03:00
if ( ! qca_is_wcn399x ( qcadev - > btsoc_type ) ) {
2018-08-03 15:16:32 +03:00
gpiod_set_value_cansleep ( qcadev - > bt_en , 1 ) ;
2019-04-01 12:49:08 +03:00
/* Controller needs time to bootup. */
msleep ( 150 ) ;
2018-08-03 15:16:32 +03:00
} else {
hu - > init_speed = qcadev - > init_speed ;
hu - > oper_speed = qcadev - > oper_speed ;
ret = qca_power_setup ( hu , true ) ;
if ( ret ) {
destroy_workqueue ( qca - > workqueue ) ;
kfree_skb ( qca - > rx_skb ) ;
hu - > priv = NULL ;
kfree ( qca ) ;
return ret ;
}
}
2018-03-29 22:15:24 +03:00
}
2018-08-03 15:16:32 +03:00
timer_setup ( & qca - > wake_retrans_timer , hci_ibs_wake_retrans_timeout , 0 ) ;
qca - > wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS ;
timer_setup ( & qca - > tx_idle_timer , hci_ibs_tx_idle_timeout , 0 ) ;
qca - > tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS ;
2015-08-11 00:24:17 +03:00
BT_DBG ( " HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u " ,
qca - > tx_idle_delay , qca - > wake_retrans ) ;
return 0 ;
}
static void qca_debugfs_init ( struct hci_dev * hdev )
{
struct hci_uart * hu = hci_get_drvdata ( hdev ) ;
struct qca_data * qca = hu - > priv ;
struct dentry * ibs_dir ;
umode_t mode ;
if ( ! hdev - > debugfs )
return ;
ibs_dir = debugfs_create_dir ( " ibs " , hdev - > debugfs ) ;
/* read only */
mode = S_IRUGO ;
debugfs_create_u8 ( " tx_ibs_state " , mode , ibs_dir , & qca - > tx_ibs_state ) ;
debugfs_create_u8 ( " rx_ibs_state " , mode , ibs_dir , & qca - > rx_ibs_state ) ;
debugfs_create_u64 ( " ibs_sent_sleeps " , mode , ibs_dir ,
& qca - > ibs_sent_slps ) ;
debugfs_create_u64 ( " ibs_sent_wakes " , mode , ibs_dir ,
& qca - > ibs_sent_wakes ) ;
debugfs_create_u64 ( " ibs_sent_wake_acks " , mode , ibs_dir ,
& qca - > ibs_sent_wacks ) ;
debugfs_create_u64 ( " ibs_recv_sleeps " , mode , ibs_dir ,
& qca - > ibs_recv_slps ) ;
debugfs_create_u64 ( " ibs_recv_wakes " , mode , ibs_dir ,
& qca - > ibs_recv_wakes ) ;
debugfs_create_u64 ( " ibs_recv_wake_acks " , mode , ibs_dir ,
& qca - > ibs_recv_wacks ) ;
2015-08-14 08:09:42 +03:00
debugfs_create_bool ( " tx_vote " , mode , ibs_dir , & qca - > tx_vote ) ;
2015-08-11 00:24:17 +03:00
debugfs_create_u64 ( " tx_votes_on " , mode , ibs_dir , & qca - > tx_votes_on ) ;
debugfs_create_u64 ( " tx_votes_off " , mode , ibs_dir , & qca - > tx_votes_off ) ;
2015-08-14 08:09:42 +03:00
debugfs_create_bool ( " rx_vote " , mode , ibs_dir , & qca - > rx_vote ) ;
2015-08-11 00:24:17 +03:00
debugfs_create_u64 ( " rx_votes_on " , mode , ibs_dir , & qca - > rx_votes_on ) ;
debugfs_create_u64 ( " rx_votes_off " , mode , ibs_dir , & qca - > rx_votes_off ) ;
debugfs_create_u64 ( " votes_on " , mode , ibs_dir , & qca - > votes_on ) ;
debugfs_create_u64 ( " votes_off " , mode , ibs_dir , & qca - > votes_off ) ;
debugfs_create_u32 ( " vote_on_ms " , mode , ibs_dir , & qca - > vote_on_ms ) ;
debugfs_create_u32 ( " vote_off_ms " , mode , ibs_dir , & qca - > vote_off_ms ) ;
/* read/write */
mode = S_IRUGO | S_IWUSR ;
debugfs_create_u32 ( " wake_retrans " , mode , ibs_dir , & qca - > wake_retrans ) ;
debugfs_create_u32 ( " tx_idle_delay " , mode , ibs_dir ,
& qca - > tx_idle_delay ) ;
}
/* Flush protocol data */
static int qca_flush ( struct hci_uart * hu )
{
struct qca_data * qca = hu - > priv ;
BT_DBG ( " hu %p qca flush " , hu ) ;
skb_queue_purge ( & qca - > tx_wait_q ) ;
skb_queue_purge ( & qca - > txq ) ;
return 0 ;
}
/* Close protocol */
static int qca_close ( struct hci_uart * hu )
{
2018-03-29 22:15:24 +03:00
struct qca_serdev * qcadev ;
2015-08-11 00:24:17 +03:00
struct qca_data * qca = hu - > priv ;
BT_DBG ( " hu %p qca close " , hu ) ;
serial_clock_vote ( HCI_IBS_VOTE_STATS_UPDATE , hu ) ;
skb_queue_purge ( & qca - > tx_wait_q ) ;
skb_queue_purge ( & qca - > txq ) ;
del_timer ( & qca - > tx_idle_timer ) ;
del_timer ( & qca - > wake_retrans_timer ) ;
destroy_workqueue ( qca - > workqueue ) ;
qca - > hu = NULL ;
2018-03-29 22:15:24 +03:00
if ( hu - > serdev ) {
qcadev = serdev_device_get_drvdata ( hu - > serdev ) ;
2019-04-26 16:56:01 +03:00
if ( qca_is_wcn399x ( qcadev - > btsoc_type ) )
2018-08-22 15:20:05 +03:00
qca_power_shutdown ( hu ) ;
2018-08-03 15:16:32 +03:00
else
gpiod_set_value_cansleep ( qcadev - > bt_en , 0 ) ;
2018-03-29 22:15:24 +03:00
}
2015-08-11 00:24:17 +03:00
kfree_skb ( qca - > rx_skb ) ;
hu - > priv = NULL ;
kfree ( qca ) ;
return 0 ;
}
/* Called upon a wake-up-indication from the device.
*/
static void device_want_to_wakeup ( struct hci_uart * hu )
{
unsigned long flags ;
struct qca_data * qca = hu - > priv ;
BT_DBG ( " hu %p want to wake up " , hu ) ;
spin_lock_irqsave ( & qca - > hci_ibs_lock , flags ) ;
qca - > ibs_recv_wakes + + ;
switch ( qca - > rx_ibs_state ) {
case HCI_IBS_RX_ASLEEP :
/* Make sure clock is on - we may have turned clock off since
* receiving the wake up indicator awake rx clock .
*/
queue_work ( qca - > workqueue , & qca - > ws_awake_rx ) ;
spin_unlock_irqrestore ( & qca - > hci_ibs_lock , flags ) ;
return ;
case HCI_IBS_RX_AWAKE :
/* Always acknowledge device wake up,
* sending IBS message doesn ' t count as TX ON .
*/
if ( send_hci_ibs_cmd ( HCI_IBS_WAKE_ACK , hu ) < 0 ) {
BT_ERR ( " Failed to acknowledge device wake up " ) ;
break ;
}
qca - > ibs_sent_wacks + + ;
break ;
default :
/* Any other state is illegal */
BT_ERR ( " Received HCI_IBS_WAKE_IND in rx state %d " ,
qca - > rx_ibs_state ) ;
break ;
}
spin_unlock_irqrestore ( & qca - > hci_ibs_lock , flags ) ;
/* Actually send the packets */
hci_uart_tx_wakeup ( hu ) ;
}
/* Called upon a sleep-indication from the device.
*/
static void device_want_to_sleep ( struct hci_uart * hu )
{
unsigned long flags ;
struct qca_data * qca = hu - > priv ;
BT_DBG ( " hu %p want to sleep " , hu ) ;
spin_lock_irqsave ( & qca - > hci_ibs_lock , flags ) ;
qca - > ibs_recv_slps + + ;
switch ( qca - > rx_ibs_state ) {
case HCI_IBS_RX_AWAKE :
/* Update state */
qca - > rx_ibs_state = HCI_IBS_RX_ASLEEP ;
/* Vote off rx clock under workqueue */
queue_work ( qca - > workqueue , & qca - > ws_rx_vote_off ) ;
break ;
case HCI_IBS_RX_ASLEEP :
/* Fall through */
default :
/* Any other state is illegal */
BT_ERR ( " Received HCI_IBS_SLEEP_IND in rx state %d " ,
qca - > rx_ibs_state ) ;
break ;
}
spin_unlock_irqrestore ( & qca - > hci_ibs_lock , flags ) ;
}
/* Called upon wake-up-acknowledgement from the device
*/
static void device_woke_up ( struct hci_uart * hu )
{
unsigned long flags , idle_delay ;
struct qca_data * qca = hu - > priv ;
struct sk_buff * skb = NULL ;
BT_DBG ( " hu %p woke up " , hu ) ;
spin_lock_irqsave ( & qca - > hci_ibs_lock , flags ) ;
qca - > ibs_recv_wacks + + ;
switch ( qca - > tx_ibs_state ) {
case HCI_IBS_TX_AWAKE :
/* Expect one if we send 2 WAKEs */
BT_DBG ( " Received HCI_IBS_WAKE_ACK in tx state %d " ,
qca - > tx_ibs_state ) ;
break ;
case HCI_IBS_TX_WAKING :
/* Send pending packets */
while ( ( skb = skb_dequeue ( & qca - > tx_wait_q ) ) )
skb_queue_tail ( & qca - > txq , skb ) ;
/* Switch timers and change state to HCI_IBS_TX_AWAKE */
del_timer ( & qca - > wake_retrans_timer ) ;
idle_delay = msecs_to_jiffies ( qca - > tx_idle_delay ) ;
mod_timer ( & qca - > tx_idle_timer , jiffies + idle_delay ) ;
qca - > tx_ibs_state = HCI_IBS_TX_AWAKE ;
break ;
case HCI_IBS_TX_ASLEEP :
/* Fall through */
default :
BT_ERR ( " Received HCI_IBS_WAKE_ACK in tx state %d " ,
qca - > tx_ibs_state ) ;
break ;
}
spin_unlock_irqrestore ( & qca - > hci_ibs_lock , flags ) ;
/* Actually send the packets */
hci_uart_tx_wakeup ( hu ) ;
}
/* Enqueue frame for transmittion (padding, crc, etc) may be called from
* two simultaneous tasklets .
*/
static int qca_enqueue ( struct hci_uart * hu , struct sk_buff * skb )
{
unsigned long flags = 0 , idle_delay ;
struct qca_data * qca = hu - > priv ;
BT_DBG ( " hu %p qca enq skb %p tx_ibs_state %d " , hu , skb ,
qca - > tx_ibs_state ) ;
/* Prepend skb with frame type */
2015-11-05 09:33:56 +03:00
memcpy ( skb_push ( skb , 1 ) , & hci_skb_pkt_type ( skb ) , 1 ) ;
2015-08-11 00:24:17 +03:00
2019-02-04 18:06:43 +03:00
spin_lock_irqsave ( & qca - > hci_ibs_lock , flags ) ;
2015-08-11 00:24:17 +03:00
/* Don't go to sleep in middle of patch download or
* Out - Of - Band ( GPIOs control ) sleep is selected .
*/
2019-04-30 02:21:30 +03:00
if ( ! test_bit ( QCA_IBS_ENABLED , & qca - > flags ) ) {
2015-08-11 00:24:17 +03:00
skb_queue_tail ( & qca - > txq , skb ) ;
2019-02-04 18:06:43 +03:00
spin_unlock_irqrestore ( & qca - > hci_ibs_lock , flags ) ;
2015-08-11 00:24:17 +03:00
return 0 ;
}
/* Act according to current state */
switch ( qca - > tx_ibs_state ) {
case HCI_IBS_TX_AWAKE :
BT_DBG ( " Device awake, sending normally " ) ;
skb_queue_tail ( & qca - > txq , skb ) ;
idle_delay = msecs_to_jiffies ( qca - > tx_idle_delay ) ;
mod_timer ( & qca - > tx_idle_timer , jiffies + idle_delay ) ;
break ;
case HCI_IBS_TX_ASLEEP :
BT_DBG ( " Device asleep, waking up and queueing packet " ) ;
/* Save packet for later */
skb_queue_tail ( & qca - > tx_wait_q , skb ) ;
qca - > tx_ibs_state = HCI_IBS_TX_WAKING ;
/* Schedule a work queue to wake up device */
queue_work ( qca - > workqueue , & qca - > ws_awake_device ) ;
break ;
case HCI_IBS_TX_WAKING :
BT_DBG ( " Device waking up, queueing packet " ) ;
/* Transient state; just keep packet for later */
skb_queue_tail ( & qca - > tx_wait_q , skb ) ;
break ;
default :
BT_ERR ( " Illegal tx state: %d (losing packet) " ,
qca - > tx_ibs_state ) ;
kfree_skb ( skb ) ;
break ;
}
spin_unlock_irqrestore ( & qca - > hci_ibs_lock , flags ) ;
return 0 ;
}
static int qca_ibs_sleep_ind ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_uart * hu = hci_get_drvdata ( hdev ) ;
BT_DBG ( " hu %p recv hci ibs cmd 0x%x " , hu , HCI_IBS_SLEEP_IND ) ;
device_want_to_sleep ( hu ) ;
kfree_skb ( skb ) ;
return 0 ;
}
static int qca_ibs_wake_ind ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_uart * hu = hci_get_drvdata ( hdev ) ;
BT_DBG ( " hu %p recv hci ibs cmd 0x%x " , hu , HCI_IBS_WAKE_IND ) ;
device_want_to_wakeup ( hu ) ;
kfree_skb ( skb ) ;
return 0 ;
}
static int qca_ibs_wake_ack ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_uart * hu = hci_get_drvdata ( hdev ) ;
BT_DBG ( " hu %p recv hci ibs cmd 0x%x " , hu , HCI_IBS_WAKE_ACK ) ;
device_woke_up ( hu ) ;
kfree_skb ( skb ) ;
return 0 ;
}
2018-10-16 17:21:35 +03:00
static int qca_recv_acl_data ( struct hci_dev * hdev , struct sk_buff * skb )
{
/* We receive debug logs from chip as an ACL packets.
* Instead of sending the data to ACL to decode the
* received data , we are pushing them to the above layers
* as a diagnostic packet .
*/
if ( get_unaligned_le16 ( skb - > data ) = = QCA_DEBUG_HANDLE )
return hci_recv_diag ( hdev , skb ) ;
return hci_recv_frame ( hdev , skb ) ;
}
2015-08-11 00:24:17 +03:00
# define QCA_IBS_SLEEP_IND_EVENT \
. type = HCI_IBS_SLEEP_IND , \
. hlen = 0 , \
. loff = 0 , \
. lsize = 0 , \
. maxlen = HCI_MAX_IBS_SIZE
# define QCA_IBS_WAKE_IND_EVENT \
. type = HCI_IBS_WAKE_IND , \
. hlen = 0 , \
. loff = 0 , \
. lsize = 0 , \
. maxlen = HCI_MAX_IBS_SIZE
# define QCA_IBS_WAKE_ACK_EVENT \
. type = HCI_IBS_WAKE_ACK , \
. hlen = 0 , \
. loff = 0 , \
. lsize = 0 , \
. maxlen = HCI_MAX_IBS_SIZE
static const struct h4_recv_pkt qca_recv_pkts [ ] = {
2018-10-16 17:21:35 +03:00
{ H4_RECV_ACL , . recv = qca_recv_acl_data } ,
2015-08-11 00:24:17 +03:00
{ H4_RECV_SCO , . recv = hci_recv_frame } ,
{ H4_RECV_EVENT , . recv = hci_recv_frame } ,
{ QCA_IBS_WAKE_IND_EVENT , . recv = qca_ibs_wake_ind } ,
{ QCA_IBS_WAKE_ACK_EVENT , . recv = qca_ibs_wake_ack } ,
{ QCA_IBS_SLEEP_IND_EVENT , . recv = qca_ibs_sleep_ind } ,
} ;
static int qca_recv ( struct hci_uart * hu , const void * data , int count )
{
struct qca_data * qca = hu - > priv ;
if ( ! test_bit ( HCI_UART_REGISTERED , & hu - > flags ) )
return - EUNATCH ;
qca - > rx_skb = h4_recv_buf ( hu - > hdev , qca - > rx_skb , data , count ,
qca_recv_pkts , ARRAY_SIZE ( qca_recv_pkts ) ) ;
if ( IS_ERR ( qca - > rx_skb ) ) {
int err = PTR_ERR ( qca - > rx_skb ) ;
2017-10-30 12:42:59 +03:00
bt_dev_err ( hu - > hdev , " Frame reassembly failed (%d) " , err ) ;
2015-08-11 00:24:17 +03:00
qca - > rx_skb = NULL ;
return err ;
}
return count ;
}
static struct sk_buff * qca_dequeue ( struct hci_uart * hu )
{
struct qca_data * qca = hu - > priv ;
return skb_dequeue ( & qca - > txq ) ;
}
static uint8_t qca_get_baudrate_value ( int speed )
{
2015-09-15 15:19:45 +03:00
switch ( speed ) {
2015-08-11 00:24:17 +03:00
case 9600 :
return QCA_BAUDRATE_9600 ;
case 19200 :
return QCA_BAUDRATE_19200 ;
case 38400 :
return QCA_BAUDRATE_38400 ;
case 57600 :
return QCA_BAUDRATE_57600 ;
case 115200 :
return QCA_BAUDRATE_115200 ;
case 230400 :
return QCA_BAUDRATE_230400 ;
case 460800 :
return QCA_BAUDRATE_460800 ;
case 500000 :
return QCA_BAUDRATE_500000 ;
case 921600 :
return QCA_BAUDRATE_921600 ;
case 1000000 :
return QCA_BAUDRATE_1000000 ;
case 2000000 :
return QCA_BAUDRATE_2000000 ;
case 3000000 :
return QCA_BAUDRATE_3000000 ;
2018-08-03 15:16:30 +03:00
case 3200000 :
return QCA_BAUDRATE_3200000 ;
2015-08-11 00:24:17 +03:00
case 3500000 :
return QCA_BAUDRATE_3500000 ;
default :
return QCA_BAUDRATE_115200 ;
}
}
static int qca_set_baudrate ( struct hci_dev * hdev , uint8_t baudrate )
{
struct hci_uart * hu = hci_get_drvdata ( hdev ) ;
struct qca_data * qca = hu - > priv ;
struct sk_buff * skb ;
u8 cmd [ ] = { 0x01 , 0x48 , 0xFC , 0x01 , 0x00 } ;
2018-08-03 15:16:30 +03:00
if ( baudrate > QCA_BAUDRATE_3200000 )
2015-08-11 00:24:17 +03:00
return - EINVAL ;
cmd [ 4 ] = baudrate ;
2018-07-23 06:56:51 +03:00
skb = bt_skb_alloc ( sizeof ( cmd ) , GFP_KERNEL ) ;
2015-08-11 00:24:17 +03:00
if ( ! skb ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " Failed to allocate baudrate packet " ) ;
2015-08-11 00:24:17 +03:00
return - ENOMEM ;
}
/* Assign commands to change baudrate and packet type. */
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:20 +03:00
skb_put_data ( skb , cmd , sizeof ( cmd ) ) ;
2015-11-05 09:33:56 +03:00
hci_skb_pkt_type ( skb ) = HCI_COMMAND_PKT ;
2015-08-11 00:24:17 +03:00
skb_queue_tail ( & qca - > txq , skb ) ;
hci_uart_tx_wakeup ( hu ) ;
2019-02-28 02:52:23 +03:00
/* Wait for the baudrate change request to be sent */
while ( ! skb_queue_empty ( & qca - > txq ) )
usleep_range ( 100 , 200 ) ;
2019-04-23 21:16:52 +03:00
if ( hu - > serdev )
serdev_device_wait_until_sent ( hu - > serdev ,
2019-02-28 02:52:23 +03:00
msecs_to_jiffies ( CMD_TRANS_TIMEOUT_MS ) ) ;
/* Give the controller time to process the request */
2019-04-26 16:56:01 +03:00
if ( qca_is_wcn399x ( qca_soc_type ( hu ) ) )
2019-02-28 02:52:23 +03:00
msleep ( 10 ) ;
else
msleep ( 300 ) ;
2015-08-11 00:24:17 +03:00
return 0 ;
}
2018-03-29 22:15:24 +03:00
static inline void host_set_baudrate ( struct hci_uart * hu , unsigned int speed )
{
if ( hu - > serdev )
serdev_device_set_baudrate ( hu - > serdev , speed ) ;
else
hci_uart_set_baudrate ( hu , speed ) ;
}
2019-02-26 22:46:45 +03:00
static int qca_send_power_pulse ( struct hci_uart * hu , bool on )
2018-08-03 15:16:32 +03:00
{
2019-02-04 18:06:41 +03:00
int ret ;
2019-02-28 02:52:23 +03:00
int timeout = msecs_to_jiffies ( CMD_TRANS_TIMEOUT_MS ) ;
2019-02-26 22:46:45 +03:00
u8 cmd = on ? QCA_WCN3990_POWERON_PULSE : QCA_WCN3990_POWEROFF_PULSE ;
2018-08-03 15:16:32 +03:00
/* These power pulses are single byte command which are sent
* at required baudrate to wcn3990 . On wcn3990 , we have an external
* circuit at Tx pin which decodes the pulse sent at specific baudrate .
* For example , wcn3990 supports RF COEX antenna for both Wi - Fi / BT
* and also we use the same power inputs to turn on and off for
* Wi - Fi / BT . Powering up the power sources will not enable BT , until
* we send a power on pulse at 115200 bps . This algorithm will help to
* save power . Disabling hardware flow control is mandatory while
* sending power pulses to SoC .
*/
2019-02-04 18:06:41 +03:00
bt_dev_dbg ( hu - > hdev , " sending power pulse %02x to controller " , cmd ) ;
2018-08-03 15:16:32 +03:00
2019-02-04 18:06:41 +03:00
serdev_device_write_flush ( hu - > serdev ) ;
2018-08-03 15:16:32 +03:00
hci_uart_set_flow_control ( hu , true ) ;
2019-02-04 18:06:41 +03:00
ret = serdev_device_write_buf ( hu - > serdev , & cmd , sizeof ( cmd ) ) ;
if ( ret < 0 ) {
bt_dev_err ( hu - > hdev , " failed to send power pulse %02x " , cmd ) ;
return ret ;
}
2018-08-03 15:16:32 +03:00
2019-02-04 18:06:41 +03:00
serdev_device_wait_until_sent ( hu - > serdev , timeout ) ;
2018-08-03 15:16:32 +03:00
hci_uart_set_flow_control ( hu , false ) ;
2019-02-26 22:46:47 +03:00
/* Give to controller time to boot/shutdown */
2019-02-26 22:46:46 +03:00
if ( on )
msleep ( 100 ) ;
2019-02-26 22:46:47 +03:00
else
msleep ( 10 ) ;
2019-02-26 22:46:46 +03:00
2018-08-03 15:16:32 +03:00
return 0 ;
}
2018-08-03 15:16:29 +03:00
static unsigned int qca_get_speed ( struct hci_uart * hu ,
enum qca_speed_type speed_type )
{
unsigned int speed = 0 ;
if ( speed_type = = QCA_INIT_SPEED ) {
if ( hu - > init_speed )
speed = hu - > init_speed ;
else if ( hu - > proto - > init_speed )
speed = hu - > proto - > init_speed ;
} else {
if ( hu - > oper_speed )
speed = hu - > oper_speed ;
else if ( hu - > proto - > oper_speed )
speed = hu - > proto - > oper_speed ;
}
return speed ;
}
static int qca_check_speeds ( struct hci_uart * hu )
{
2019-04-26 16:56:01 +03:00
if ( qca_is_wcn399x ( qca_soc_type ( hu ) ) ) {
2018-08-03 15:16:32 +03:00
if ( ! qca_get_speed ( hu , QCA_INIT_SPEED ) & &
! qca_get_speed ( hu , QCA_OPER_SPEED ) )
return - EINVAL ;
} else {
if ( ! qca_get_speed ( hu , QCA_INIT_SPEED ) | |
! qca_get_speed ( hu , QCA_OPER_SPEED ) )
return - EINVAL ;
}
2018-08-03 15:16:29 +03:00
return 0 ;
}
static int qca_set_speed ( struct hci_uart * hu , enum qca_speed_type speed_type )
{
unsigned int speed , qca_baudrate ;
2019-02-04 18:06:42 +03:00
int ret = 0 ;
2018-08-03 15:16:29 +03:00
if ( speed_type = = QCA_INIT_SPEED ) {
speed = qca_get_speed ( hu , QCA_INIT_SPEED ) ;
if ( speed )
host_set_baudrate ( hu , speed ) ;
} else {
2019-03-11 21:38:31 +03:00
enum qca_btsoc_type soc_type = qca_soc_type ( hu ) ;
2018-08-03 15:16:29 +03:00
speed = qca_get_speed ( hu , QCA_OPER_SPEED ) ;
if ( ! speed )
return 0 ;
2019-02-04 18:06:42 +03:00
/* Disable flow control for wcn3990 to deassert RTS while
* changing the baudrate of chip and host .
*/
2019-04-26 16:56:01 +03:00
if ( qca_is_wcn399x ( soc_type ) )
2019-02-04 18:06:42 +03:00
hci_uart_set_flow_control ( hu , true ) ;
2018-08-03 15:16:29 +03:00
qca_baudrate = qca_get_baudrate_value ( speed ) ;
2018-08-03 15:16:32 +03:00
bt_dev_dbg ( hu - > hdev , " Set UART speed to %d " , speed ) ;
2018-08-03 15:16:29 +03:00
ret = qca_set_baudrate ( hu - > hdev , qca_baudrate ) ;
if ( ret )
2019-02-04 18:06:42 +03:00
goto error ;
2018-08-03 15:16:29 +03:00
host_set_baudrate ( hu , speed ) ;
2019-02-04 18:06:42 +03:00
error :
2019-04-26 16:56:01 +03:00
if ( qca_is_wcn399x ( soc_type ) )
2019-02-04 18:06:42 +03:00
hci_uart_set_flow_control ( hu , false ) ;
2018-08-03 15:16:29 +03:00
}
2019-02-04 18:06:42 +03:00
return ret ;
2018-08-03 15:16:29 +03:00
}
2018-08-03 15:16:32 +03:00
static int qca_wcn3990_init ( struct hci_uart * hu )
{
2018-09-24 17:44:45 +03:00
struct qca_serdev * qcadev ;
2018-08-03 15:16:32 +03:00
int ret ;
2018-09-24 17:44:45 +03:00
/* Check for vregs status, may be hci down has turned
* off the voltage regulator .
*/
qcadev = serdev_device_get_drvdata ( hu - > serdev ) ;
if ( ! qcadev - > bt_power - > vregs_on ) {
serdev_device_close ( hu - > serdev ) ;
ret = qca_power_setup ( hu , true ) ;
if ( ret )
return ret ;
ret = serdev_device_open ( hu - > serdev ) ;
if ( ret ) {
bt_dev_err ( hu - > hdev , " failed to open port " ) ;
return ret ;
}
}
2018-08-03 15:16:32 +03:00
/* Forcefully enable wcn3990 to enter in to boot mode. */
host_set_baudrate ( hu , 2400 ) ;
2019-02-26 22:46:45 +03:00
ret = qca_send_power_pulse ( hu , false ) ;
2018-08-03 15:16:32 +03:00
if ( ret )
return ret ;
qca_set_speed ( hu , QCA_INIT_SPEED ) ;
2019-02-26 22:46:45 +03:00
ret = qca_send_power_pulse ( hu , true ) ;
2018-08-03 15:16:32 +03:00
if ( ret )
return ret ;
/* Now the device is in ready state to communicate with host.
* To sync host with device we need to reopen port .
* Without this , we will have RTS and CTS synchronization
* issues .
*/
serdev_device_close ( hu - > serdev ) ;
ret = serdev_device_open ( hu - > serdev ) ;
if ( ret ) {
bt_dev_err ( hu - > hdev , " failed to open port " ) ;
return ret ;
}
hci_uart_set_flow_control ( hu , false ) ;
return 0 ;
}
2015-08-11 00:24:17 +03:00
static int qca_setup ( struct hci_uart * hu )
{
struct hci_dev * hdev = hu - > hdev ;
struct qca_data * qca = hu - > priv ;
unsigned int speed , qca_baudrate = QCA_BAUDRATE_115200 ;
2019-03-11 21:38:31 +03:00
enum qca_btsoc_type soc_type = qca_soc_type ( hu ) ;
2015-08-11 00:24:17 +03:00
int ret ;
2018-08-03 15:16:28 +03:00
int soc_ver = 0 ;
2015-08-11 00:24:17 +03:00
2018-08-03 15:16:29 +03:00
ret = qca_check_speeds ( hu ) ;
if ( ret )
return ret ;
2015-08-11 00:24:17 +03:00
/* Patch downloading has to be done without IBS mode */
2019-04-30 02:21:30 +03:00
clear_bit ( QCA_IBS_ENABLED , & qca - > flags ) ;
2015-08-11 00:24:17 +03:00
2019-04-26 16:56:01 +03:00
if ( qca_is_wcn399x ( soc_type ) ) {
2018-08-03 15:16:32 +03:00
bt_dev_info ( hdev , " setting up wcn3990 " ) ;
2018-09-24 17:44:45 +03:00
/* Enable NON_PERSISTENT_SETUP QUIRK to ensure to execute
* setup for every hci up .
*/
set_bit ( HCI_QUIRK_NON_PERSISTENT_SETUP , & hdev - > quirks ) ;
2019-02-19 23:05:59 +03:00
set_bit ( HCI_QUIRK_USE_BDADDR_PROPERTY , & hdev - > quirks ) ;
2018-09-24 17:44:45 +03:00
hu - > hdev - > shutdown = qca_power_off ;
2018-08-03 15:16:32 +03:00
ret = qca_wcn3990_init ( hu ) ;
if ( ret )
return ret ;
ret = qca_read_soc_version ( hdev , & soc_ver ) ;
if ( ret )
return ret ;
} else {
bt_dev_info ( hdev , " ROME setup " ) ;
qca_set_speed ( hu , QCA_INIT_SPEED ) ;
}
2015-08-11 00:24:17 +03:00
/* Setup user speed if needed */
2018-08-03 15:16:29 +03:00
speed = qca_get_speed ( hu , QCA_OPER_SPEED ) ;
2015-08-11 00:24:17 +03:00
if ( speed ) {
2018-08-03 15:16:29 +03:00
ret = qca_set_speed ( hu , QCA_OPER_SPEED ) ;
if ( ret )
2015-08-11 00:24:17 +03:00
return ret ;
2018-08-03 15:16:29 +03:00
qca_baudrate = qca_get_baudrate_value ( speed ) ;
2015-08-11 00:24:17 +03:00
}
2019-04-26 16:56:01 +03:00
if ( ! qca_is_wcn399x ( soc_type ) ) {
2018-08-03 15:16:32 +03:00
/* Get QCA version information */
ret = qca_read_soc_version ( hdev , & soc_ver ) ;
if ( ret )
return ret ;
}
2018-08-03 15:16:28 +03:00
bt_dev_info ( hdev , " QCA controller version 0x%08x " , soc_ver ) ;
2015-08-11 00:24:17 +03:00
/* Setup patch / NVM configurations */
2019-03-11 21:38:31 +03:00
ret = qca_uart_setup ( hdev , qca_baudrate , soc_type , soc_ver ) ;
2015-08-11 00:24:17 +03:00
if ( ! ret ) {
2019-04-30 02:21:30 +03:00
set_bit ( QCA_IBS_ENABLED , & qca - > flags ) ;
2015-08-11 00:24:17 +03:00
qca_debugfs_init ( hdev ) ;
2017-11-06 14:16:56 +03:00
} else if ( ret = = - ENOENT ) {
/* No patch/nvm-config found, run with original fw/config */
ret = 0 ;
2018-04-16 09:40:24 +03:00
} else if ( ret = = - EAGAIN ) {
/*
* Userspace firmware loader will return - EAGAIN in case no
* patch / nvm - config is found , so run with original fw / config .
*/
ret = 0 ;
2015-08-11 00:24:17 +03:00
}
/* Setup bdaddr */
2019-04-26 16:56:01 +03:00
if ( qca_is_wcn399x ( soc_type ) )
2019-01-16 15:31:15 +03:00
hu - > hdev - > set_bdaddr = qca_set_bdaddr ;
else
hu - > hdev - > set_bdaddr = qca_set_bdaddr_rome ;
2015-08-11 00:24:17 +03:00
return ret ;
}
static struct hci_uart_proto qca_proto = {
. id = HCI_UART_QCA ,
. name = " QCA " ,
2015-10-20 22:30:45 +03:00
. manufacturer = 29 ,
2015-08-11 00:24:17 +03:00
. init_speed = 115200 ,
. oper_speed = 3000000 ,
. open = qca_open ,
. close = qca_close ,
. flush = qca_flush ,
. setup = qca_setup ,
. recv = qca_recv ,
. enqueue = qca_enqueue ,
. dequeue = qca_dequeue ,
} ;
2019-04-26 16:56:01 +03:00
static const struct qca_vreg_data qca_soc_data_wcn3990 = {
2018-08-03 15:16:32 +03:00
. soc_type = QCA_WCN3990 ,
. vregs = ( struct qca_vreg [ ] ) {
{ " vddio " , 1800000 , 1900000 , 15000 } ,
{ " vddxo " , 1800000 , 1900000 , 80000 } ,
{ " vddrf " , 1300000 , 1350000 , 300000 } ,
{ " vddch0 " , 3300000 , 3400000 , 450000 } ,
} ,
. num_vregs = 4 ,
} ;
2019-04-26 16:56:01 +03:00
static const struct qca_vreg_data qca_soc_data_wcn3998 = {
. soc_type = QCA_WCN3998 ,
. vregs = ( struct qca_vreg [ ] ) {
{ " vddio " , 1800000 , 1900000 , 10000 } ,
{ " vddxo " , 1800000 , 1900000 , 80000 } ,
{ " vddrf " , 1300000 , 1352000 , 300000 } ,
{ " vddch0 " , 3300000 , 3300000 , 450000 } ,
} ,
. num_vregs = 4 ,
} ;
2018-08-22 15:20:05 +03:00
static void qca_power_shutdown ( struct hci_uart * hu )
2018-08-03 15:16:32 +03:00
{
2019-02-04 18:06:43 +03:00
struct qca_data * qca = hu - > priv ;
unsigned long flags ;
/* From this point we go into power off state. But serial port is
* still open , stop queueing the IBS data and flush all the buffered
* data in skb ' s .
*/
spin_lock_irqsave ( & qca - > hci_ibs_lock , flags ) ;
2019-04-30 02:21:30 +03:00
clear_bit ( QCA_IBS_ENABLED , & qca - > flags ) ;
2019-02-04 18:06:43 +03:00
qca_flush ( hu ) ;
spin_unlock_irqrestore ( & qca - > hci_ibs_lock , flags ) ;
2018-08-03 15:16:32 +03:00
host_set_baudrate ( hu , 2400 ) ;
2019-02-26 22:46:45 +03:00
qca_send_power_pulse ( hu , false ) ;
2018-08-03 15:16:32 +03:00
qca_power_setup ( hu , false ) ;
}
2018-09-24 17:44:45 +03:00
static int qca_power_off ( struct hci_dev * hdev )
{
struct hci_uart * hu = hci_get_drvdata ( hdev ) ;
qca_power_shutdown ( hu ) ;
return 0 ;
}
2018-08-03 15:16:32 +03:00
static int qca_enable_regulator ( struct qca_vreg vregs ,
struct regulator * regulator )
{
int ret ;
ret = regulator_set_voltage ( regulator , vregs . min_uV ,
vregs . max_uV ) ;
if ( ret )
return ret ;
if ( vregs . load_uA )
ret = regulator_set_load ( regulator ,
vregs . load_uA ) ;
if ( ret )
return ret ;
return regulator_enable ( regulator ) ;
}
static void qca_disable_regulator ( struct qca_vreg vregs ,
struct regulator * regulator )
{
regulator_disable ( regulator ) ;
regulator_set_voltage ( regulator , 0 , vregs . max_uV ) ;
if ( vregs . load_uA )
regulator_set_load ( regulator , 0 ) ;
}
static int qca_power_setup ( struct hci_uart * hu , bool on )
{
struct qca_vreg * vregs ;
struct regulator_bulk_data * vreg_bulk ;
struct qca_serdev * qcadev ;
int i , num_vregs , ret = 0 ;
qcadev = serdev_device_get_drvdata ( hu - > serdev ) ;
if ( ! qcadev | | ! qcadev - > bt_power | | ! qcadev - > bt_power - > vreg_data | |
! qcadev - > bt_power - > vreg_bulk )
return - EINVAL ;
vregs = qcadev - > bt_power - > vreg_data - > vregs ;
vreg_bulk = qcadev - > bt_power - > vreg_bulk ;
num_vregs = qcadev - > bt_power - > vreg_data - > num_vregs ;
BT_DBG ( " on: %d " , on ) ;
if ( on & & ! qcadev - > bt_power - > vregs_on ) {
for ( i = 0 ; i < num_vregs ; i + + ) {
ret = qca_enable_regulator ( vregs [ i ] ,
vreg_bulk [ i ] . consumer ) ;
if ( ret )
break ;
}
if ( ret ) {
BT_ERR ( " failed to enable regulator:%s " , vregs [ i ] . name ) ;
/* turn off regulators which are enabled */
for ( i = i - 1 ; i > = 0 ; i - - )
qca_disable_regulator ( vregs [ i ] ,
vreg_bulk [ i ] . consumer ) ;
} else {
qcadev - > bt_power - > vregs_on = true ;
}
} else if ( ! on & & qcadev - > bt_power - > vregs_on ) {
/* turn off regulator in reverse order */
i = qcadev - > bt_power - > vreg_data - > num_vregs - 1 ;
for ( ; i > = 0 ; i - - )
qca_disable_regulator ( vregs [ i ] , vreg_bulk [ i ] . consumer ) ;
qcadev - > bt_power - > vregs_on = false ;
}
return ret ;
}
static int qca_init_regulators ( struct qca_power * qca ,
const struct qca_vreg * vregs , size_t num_vregs )
{
int i ;
treewide: Replace more open-coded allocation size multiplications
As done treewide earlier, this catches several more open-coded
allocation size calculations that were added to the kernel during the
merge window. This performs the following mechanical transformations
using Coccinelle:
kvmalloc(a * b, ...) -> kvmalloc_array(a, b, ...)
kvzalloc(a * b, ...) -> kvcalloc(a, b, ...)
devm_kzalloc(..., a * b, ...) -> devm_kcalloc(..., a, b, ...)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-10-06 02:21:46 +03:00
qca - > vreg_bulk = devm_kcalloc ( qca - > dev , num_vregs ,
2018-08-03 15:16:32 +03:00
sizeof ( struct regulator_bulk_data ) ,
GFP_KERNEL ) ;
if ( ! qca - > vreg_bulk )
return - ENOMEM ;
for ( i = 0 ; i < num_vregs ; i + + )
qca - > vreg_bulk [ i ] . supply = vregs [ i ] . name ;
return devm_regulator_bulk_get ( qca - > dev , num_vregs , qca - > vreg_bulk ) ;
}
2018-03-29 22:15:24 +03:00
static int qca_serdev_probe ( struct serdev_device * serdev )
{
struct qca_serdev * qcadev ;
2018-08-03 15:16:32 +03:00
const struct qca_vreg_data * data ;
2018-03-29 22:15:24 +03:00
int err ;
qcadev = devm_kzalloc ( & serdev - > dev , sizeof ( * qcadev ) , GFP_KERNEL ) ;
if ( ! qcadev )
return - ENOMEM ;
qcadev - > serdev_hu . serdev = serdev ;
2018-08-03 15:16:32 +03:00
data = of_device_get_match_data ( & serdev - > dev ) ;
2018-03-29 22:15:24 +03:00
serdev_device_set_drvdata ( serdev , qcadev ) ;
2019-04-26 16:56:01 +03:00
if ( data & & qca_is_wcn399x ( data - > soc_type ) ) {
qcadev - > btsoc_type = data - > soc_type ;
2018-08-03 15:16:32 +03:00
qcadev - > bt_power = devm_kzalloc ( & serdev - > dev ,
sizeof ( struct qca_power ) ,
GFP_KERNEL ) ;
if ( ! qcadev - > bt_power )
return - ENOMEM ;
qcadev - > bt_power - > dev = & serdev - > dev ;
qcadev - > bt_power - > vreg_data = data ;
err = qca_init_regulators ( qcadev - > bt_power , data - > vregs ,
data - > num_vregs ) ;
if ( err ) {
BT_ERR ( " Failed to init regulators:%d " , err ) ;
goto out ;
}
2018-03-29 22:15:24 +03:00
2018-08-03 15:16:32 +03:00
qcadev - > bt_power - > vregs_on = false ;
2018-03-29 22:15:24 +03:00
2018-08-03 15:16:32 +03:00
device_property_read_u32 ( & serdev - > dev , " max-speed " ,
& qcadev - > oper_speed ) ;
if ( ! qcadev - > oper_speed )
BT_DBG ( " UART will pick default operating speed " ) ;
2018-03-29 22:15:24 +03:00
2018-08-03 15:16:32 +03:00
err = hci_uart_register_device ( & qcadev - > serdev_hu , & qca_proto ) ;
if ( err ) {
BT_ERR ( " wcn3990 serdev registration failed " ) ;
goto out ;
}
} else {
qcadev - > btsoc_type = QCA_ROME ;
qcadev - > bt_en = devm_gpiod_get ( & serdev - > dev , " enable " ,
GPIOD_OUT_LOW ) ;
if ( IS_ERR ( qcadev - > bt_en ) ) {
dev_err ( & serdev - > dev , " failed to acquire enable gpio \n " ) ;
return PTR_ERR ( qcadev - > bt_en ) ;
}
2018-03-29 22:15:24 +03:00
2018-08-03 15:16:32 +03:00
qcadev - > susclk = devm_clk_get ( & serdev - > dev , NULL ) ;
if ( IS_ERR ( qcadev - > susclk ) ) {
dev_err ( & serdev - > dev , " failed to acquire clk \n " ) ;
return PTR_ERR ( qcadev - > susclk ) ;
}
2018-03-29 22:15:24 +03:00
2018-08-03 15:16:32 +03:00
err = clk_set_rate ( qcadev - > susclk , SUSCLK_RATE_32KHZ ) ;
if ( err )
return err ;
err = clk_prepare_enable ( qcadev - > susclk ) ;
if ( err )
return err ;
err = hci_uart_register_device ( & qcadev - > serdev_hu , & qca_proto ) ;
if ( err )
clk_disable_unprepare ( qcadev - > susclk ) ;
}
out : return err ;
2018-03-29 22:15:24 +03:00
}
static void qca_serdev_remove ( struct serdev_device * serdev )
{
struct qca_serdev * qcadev = serdev_device_get_drvdata ( serdev ) ;
2019-04-26 16:56:01 +03:00
if ( qca_is_wcn399x ( qcadev - > btsoc_type ) )
2018-08-22 15:20:05 +03:00
qca_power_shutdown ( & qcadev - > serdev_hu ) ;
2018-08-03 15:16:32 +03:00
else
clk_disable_unprepare ( qcadev - > susclk ) ;
2018-03-29 22:15:24 +03:00
2018-08-03 15:16:32 +03:00
hci_uart_unregister_device ( & qcadev - > serdev_hu ) ;
2018-03-29 22:15:24 +03:00
}
static const struct of_device_id qca_bluetooth_of_match [ ] = {
{ . compatible = " qcom,qca6174-bt " } ,
2019-04-26 16:56:01 +03:00
{ . compatible = " qcom,wcn3990-bt " , . data = & qca_soc_data_wcn3990 } ,
{ . compatible = " qcom,wcn3998-bt " , . data = & qca_soc_data_wcn3998 } ,
2018-03-29 22:15:24 +03:00
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , qca_bluetooth_of_match ) ;
static struct serdev_device_driver qca_serdev_driver = {
. probe = qca_serdev_probe ,
. remove = qca_serdev_remove ,
. driver = {
. name = " hci_uart_qca " ,
. of_match_table = qca_bluetooth_of_match ,
} ,
} ;
2015-08-11 00:24:17 +03:00
int __init qca_init ( void )
{
2018-03-29 22:15:24 +03:00
serdev_device_driver_register ( & qca_serdev_driver ) ;
2015-08-11 00:24:17 +03:00
return hci_uart_register_proto ( & qca_proto ) ;
}
int __exit qca_deinit ( void )
{
2018-03-29 22:15:24 +03:00
serdev_device_driver_unregister ( & qca_serdev_driver ) ;
2015-08-11 00:24:17 +03:00
return hci_uart_unregister_proto ( & qca_proto ) ;
}