2019-05-30 02:57:47 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2010-04-08 22:16:55 +04:00
/*
* Shared Transport driver
* HCI - LL module responsible for TI proprietary HCI_LL protocol
2010-10-06 20:18:14 +04:00
* Copyright ( C ) 2009 - 2010 Texas Instruments
* Author : Pavan Savoy < pavan_savoy @ ti . com >
2010-04-08 22:16:55 +04:00
*/
# define pr_fmt(fmt) "(stll) :" fmt
2010-09-17 20:06:11 +04:00
# include <linux/skbuff.h>
# include <linux/module.h>
2011-08-10 19:18:31 +04:00
# include <linux/platform_device.h>
2010-10-01 00:13:30 +04:00
# include <linux/ti_wilink_st.h>
2010-04-08 22:16:55 +04:00
/**********************************************************************/
/* internal functions */
static void send_ll_cmd ( struct st_data_s * st_data ,
unsigned char cmd )
{
2011-02-04 11:23:12 +03:00
pr_debug ( " %s: writing %x " , __func__ , cmd ) ;
2010-04-08 22:16:55 +04:00
st_int_write ( st_data , & cmd , 1 ) ;
return ;
}
static void ll_device_want_to_sleep ( struct st_data_s * st_data )
{
2011-08-10 19:18:31 +04:00
struct kim_data_s * kim_data ;
struct ti_st_plat_data * pdata ;
2010-07-22 14:32:05 +04:00
pr_debug ( " %s " , __func__ ) ;
2010-04-08 22:16:55 +04:00
/* sanity check */
if ( st_data - > ll_state ! = ST_LL_AWAKE )
pr_err ( " ERR hcill: ST_LL_GO_TO_SLEEP_IND "
" in state %ld " , st_data - > ll_state ) ;
send_ll_cmd ( st_data , LL_SLEEP_ACK ) ;
/* update state */
st_data - > ll_state = ST_LL_ASLEEP ;
2011-08-10 19:18:31 +04:00
/* communicate to platform about chip asleep */
kim_data = st_data - > kim_data ;
2015-07-22 21:17:15 +03:00
pdata = kim_data - > kim_pdev - > dev . platform_data ;
2011-08-10 19:18:31 +04:00
if ( pdata - > chip_asleep )
pdata - > chip_asleep ( NULL ) ;
2010-04-08 22:16:55 +04:00
}
static void ll_device_want_to_wakeup ( struct st_data_s * st_data )
{
2011-08-10 19:18:31 +04:00
struct kim_data_s * kim_data ;
struct ti_st_plat_data * pdata ;
2010-04-08 22:16:55 +04:00
/* diff actions in diff states */
switch ( st_data - > ll_state ) {
case ST_LL_ASLEEP :
send_ll_cmd ( st_data , LL_WAKE_UP_ACK ) ; /* send wake_ack */
break ;
case ST_LL_ASLEEP_TO_AWAKE :
/* duplicate wake_ind */
pr_err ( " duplicate wake_ind while waiting for Wake ack " ) ;
break ;
case ST_LL_AWAKE :
/* duplicate wake_ind */
pr_err ( " duplicate wake_ind already AWAKE " ) ;
break ;
case ST_LL_AWAKE_TO_ASLEEP :
/* duplicate wake_ind */
pr_err ( " duplicate wake_ind " ) ;
break ;
}
/* update state */
st_data - > ll_state = ST_LL_AWAKE ;
2011-08-10 19:18:31 +04:00
/* communicate to platform about chip wakeup */
kim_data = st_data - > kim_data ;
2015-07-22 21:17:15 +03:00
pdata = kim_data - > kim_pdev - > dev . platform_data ;
2012-08-03 00:17:48 +04:00
if ( pdata - > chip_awake )
2011-08-10 19:18:31 +04:00
pdata - > chip_awake ( NULL ) ;
2010-04-08 22:16:55 +04:00
}
/**********************************************************************/
/* functions invoked by ST Core */
/* called when ST Core wants to
* enable ST LL */
void st_ll_enable ( struct st_data_s * ll )
{
ll - > ll_state = ST_LL_AWAKE ;
}
/* called when ST Core /local module wants to
* disable ST LL */
void st_ll_disable ( struct st_data_s * ll )
{
ll - > ll_state = ST_LL_INVALID ;
}
/* called when ST Core wants to update the state */
void st_ll_wakeup ( struct st_data_s * ll )
{
if ( likely ( ll - > ll_state ! = ST_LL_AWAKE ) ) {
send_ll_cmd ( ll , LL_WAKE_UP_IND ) ; /* WAKE_IND */
ll - > ll_state = ST_LL_ASLEEP_TO_AWAKE ;
} else {
/* don't send the duplicate wake_indication */
pr_err ( " Chip already AWAKE " ) ;
}
}
/* called when ST Core wants the state */
unsigned long st_ll_getstate ( struct st_data_s * ll )
{
2010-07-22 14:32:05 +04:00
pr_debug ( " returning state %ld " , ll - > ll_state ) ;
2010-04-08 22:16:55 +04:00
return ll - > ll_state ;
}
/* called from ST Core, when a PM related packet arrives */
unsigned long st_ll_sleep_state ( struct st_data_s * st_data ,
unsigned char cmd )
{
switch ( cmd ) {
case LL_SLEEP_IND : /* sleep ind */
2011-02-04 11:23:12 +03:00
pr_debug ( " sleep indication recvd " ) ;
2010-04-08 22:16:55 +04:00
ll_device_want_to_sleep ( st_data ) ;
break ;
case LL_SLEEP_ACK : /* sleep ack */
pr_err ( " sleep ack rcvd: host shouldn't " ) ;
break ;
case LL_WAKE_UP_IND : /* wake ind */
2011-02-04 11:23:12 +03:00
pr_debug ( " wake indication recvd " ) ;
2010-04-08 22:16:55 +04:00
ll_device_want_to_wakeup ( st_data ) ;
break ;
case LL_WAKE_UP_ACK : /* wake ack */
2011-02-04 11:23:12 +03:00
pr_debug ( " wake ack rcvd " ) ;
2010-04-08 22:16:55 +04:00
st_data - > ll_state = ST_LL_AWAKE ;
break ;
default :
pr_err ( " unknown input/state " ) ;
2011-02-04 11:23:11 +03:00
return - EINVAL ;
2010-04-08 22:16:55 +04:00
}
2010-07-14 17:21:12 +04:00
return 0 ;
2010-04-08 22:16:55 +04:00
}
/* Called from ST CORE to initialize ST LL */
long st_ll_init ( struct st_data_s * ll )
{
/* set state to invalid */
ll - > ll_state = ST_LL_INVALID ;
return 0 ;
}
/* Called from ST CORE to de-initialize ST LL */
long st_ll_deinit ( struct st_data_s * ll )
{
return 0 ;
}