2010-04-08 13:16:54 -05:00
/*
* Shared Transport Line discipline driver Core
* Init Manager module responsible for GPIO control
* and firmware download
2010-10-06 12:18:14 -04:00
* Copyright ( C ) 2009 - 2010 Texas Instruments
* Author : Pavan Savoy < pavan_savoy @ ti . com >
2010-04-08 13:16:54 -05:00
*
* 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
*
*/
# define pr_fmt(fmt) "(stk) :" fmt
# include <linux/platform_device.h>
# include <linux/jiffies.h>
# include <linux/firmware.h>
# include <linux/delay.h>
# include <linux/wait.h>
# include <linux/gpio.h>
2010-07-28 02:25:59 -05:00
# include <linux/debugfs.h>
# include <linux/seq_file.h>
2010-04-08 13:16:54 -05:00
# include <linux/sched.h>
2011-04-26 09:18:51 -07:00
# include <linux/sysfs.h>
2011-02-04 02:23:10 -06:00
# include <linux/tty.h>
2010-04-08 13:16:54 -05:00
2011-02-04 02:23:09 -06:00
# include <linux/skbuff.h>
2010-09-30 16:13:30 -04:00
# include <linux/ti_wilink_st.h>
2011-07-03 15:14:56 -04:00
# include <linux/module.h>
2010-04-08 13:16:54 -05:00
2010-08-19 14:08:51 -04:00
# define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */
2010-10-12 16:27:38 -04:00
static struct platform_device * st_kim_devices [ MAX_ST_DEVICES ] ;
2010-04-08 13:16:54 -05:00
/**********************************************************************/
/* internal functions */
2010-08-19 14:08:51 -04:00
/**
* st_get_plat_device -
* function which returns the reference to the platform device
* requested by id . As of now only 1 such device exists ( id = 0 )
* the context requesting for reference can get the id to be
* requested by a . The protocol driver which is registering or
* b . the tty device which is opened .
*/
static struct platform_device * st_get_plat_device ( int id )
{
return st_kim_devices [ id ] ;
}
2010-07-22 05:32:06 -05:00
/**
* validate_firmware_response -
* function to return whether the firmware response was proper
* in case of error don ' t complete so that waiting for proper
* response times out
2010-04-08 13:16:54 -05:00
*/
2012-08-03 14:49:40 -05:00
static void validate_firmware_response ( struct kim_data_s * kim_gdata )
2010-04-08 13:16:54 -05:00
{
2010-07-08 08:55:17 -05:00
struct sk_buff * skb = kim_gdata - > rx_skb ;
2012-08-03 14:49:43 -05:00
if ( ! skb )
return ;
/* these magic numbers are the position in the response buffer which
* allows us to distinguish whether the response is for the read
* version info . command
*/
if ( skb - > data [ 2 ] = = 0x01 & & skb - > data [ 3 ] = = 0x01 & &
skb - > data [ 4 ] = = 0x10 & & skb - > data [ 5 ] = = 0x00 ) {
/* fw version response */
memcpy ( kim_gdata - > resp_buffer ,
kim_gdata - > rx_skb - > data ,
kim_gdata - > rx_skb - > len ) ;
kim_gdata - > rx_state = ST_W4_PACKET_TYPE ;
kim_gdata - > rx_skb = NULL ;
kim_gdata - > rx_count = 0 ;
} else if ( unlikely ( skb - > data [ 5 ] ! = 0 ) ) {
2010-04-08 13:16:54 -05:00
pr_err ( " no proper response during fw download " ) ;
pr_err ( " data6 %x " , skb - > data [ 5 ] ) ;
2011-08-10 10:18:36 -05:00
kfree_skb ( skb ) ;
2010-04-08 13:16:54 -05:00
return ; /* keep waiting for the proper response */
}
/* becos of all the script being downloaded */
complete_all ( & kim_gdata - > kim_rcvd ) ;
kfree_skb ( skb ) ;
}
/* check for data len received inside kim_int_recv
* most often hit the last case to update state to waiting for data
*/
2010-07-08 08:55:17 -05:00
static inline int kim_check_data_len ( struct kim_data_s * kim_gdata , int len )
2010-04-08 13:16:54 -05:00
{
register int room = skb_tailroom ( kim_gdata - > rx_skb ) ;
2010-07-22 05:32:05 -05:00
pr_debug ( " len %d room %d " , len , room ) ;
2010-04-08 13:16:54 -05:00
if ( ! len ) {
2010-07-08 08:55:17 -05:00
validate_firmware_response ( kim_gdata ) ;
2010-04-08 13:16:54 -05:00
} else if ( len > room ) {
/* Received packet's payload length is larger.
* We can ' t accommodate it in created skb .
*/
pr_err ( " Data length is too large len %d room %d " , len ,
room ) ;
kfree_skb ( kim_gdata - > rx_skb ) ;
} else {
/* Packet header has non-zero payload length and
* we have enough space in created skb . Lets read
* payload data */
2011-02-04 02:23:09 -06:00
kim_gdata - > rx_state = ST_W4_DATA ;
2010-04-08 13:16:54 -05:00
kim_gdata - > rx_count = len ;
return len ;
}
/* Change ST LL state to continue to process next
* packet */
kim_gdata - > rx_state = ST_W4_PACKET_TYPE ;
kim_gdata - > rx_skb = NULL ;
kim_gdata - > rx_count = 0 ;
return 0 ;
}
2010-07-22 05:32:06 -05:00
/**
* kim_int_recv - receive function called during firmware download
* firmware download responses on different UART drivers
* have been observed to come in bursts of different
* tty_receive and hence the logic
2010-04-08 13:16:54 -05:00
*/
2012-08-03 14:49:40 -05:00
static void kim_int_recv ( struct kim_data_s * kim_gdata ,
2010-07-08 08:55:17 -05:00
const unsigned char * data , long count )
2010-04-08 13:16:54 -05:00
{
2010-10-12 16:27:38 -04:00
const unsigned char * ptr ;
2018-07-03 08:32:49 +01:00
int len = 0 ;
2011-02-04 02:23:09 -06:00
unsigned char * plen ;
2010-04-08 13:16:54 -05:00
2010-07-22 05:32:05 -05:00
pr_debug ( " %s " , __func__ ) ;
2010-04-08 13:16:54 -05:00
/* Decode received bytes here */
2010-10-12 16:27:38 -04:00
ptr = data ;
2010-04-08 13:16:54 -05:00
if ( unlikely ( ptr = = NULL ) ) {
pr_err ( " received null from TTY " ) ;
return ;
}
2010-10-12 16:27:38 -04:00
2010-04-08 13:16:54 -05:00
while ( count ) {
if ( kim_gdata - > rx_count ) {
len = min_t ( unsigned int , kim_gdata - > rx_count , count ) ;
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 14:29:20 +02:00
skb_put_data ( kim_gdata - > rx_skb , ptr , len ) ;
2010-04-08 13:16:54 -05:00
kim_gdata - > rx_count - = len ;
count - = len ;
ptr + = len ;
if ( kim_gdata - > rx_count )
continue ;
/* Check ST RX state machine , where are we? */
switch ( kim_gdata - > rx_state ) {
/* Waiting for complete packet ? */
2011-02-04 02:23:09 -06:00
case ST_W4_DATA :
2010-07-22 05:32:05 -05:00
pr_debug ( " Complete pkt received " ) ;
2010-07-08 08:55:17 -05:00
validate_firmware_response ( kim_gdata ) ;
2010-04-08 13:16:54 -05:00
kim_gdata - > rx_state = ST_W4_PACKET_TYPE ;
kim_gdata - > rx_skb = NULL ;
continue ;
/* Waiting for Bluetooth event header ? */
2011-02-04 02:23:09 -06:00
case ST_W4_HEADER :
plen =
( unsigned char * ) & kim_gdata - > rx_skb - > data [ 1 ] ;
pr_debug ( " event hdr: plen 0x%02x \n " , * plen ) ;
kim_check_data_len ( kim_gdata , * plen ) ;
2010-04-08 13:16:54 -05:00
continue ;
} /* end of switch */
} /* end of if rx_state */
switch ( * ptr ) {
/* Bluetooth event packet? */
2011-02-04 02:23:09 -06:00
case 0x04 :
kim_gdata - > rx_state = ST_W4_HEADER ;
kim_gdata - > rx_count = 2 ;
2010-04-08 13:16:54 -05:00
break ;
default :
pr_info ( " unknown packet " ) ;
ptr + + ;
count - - ;
continue ;
2010-07-22 05:32:06 -05:00
}
2010-04-08 13:16:54 -05:00
ptr + + ;
count - - ;
kim_gdata - > rx_skb =
2011-02-04 02:23:09 -06:00
alloc_skb ( 1024 + 8 , GFP_ATOMIC ) ;
2010-04-08 13:16:54 -05:00
if ( ! kim_gdata - > rx_skb ) {
pr_err ( " can't allocate mem for new packet " ) ;
kim_gdata - > rx_state = ST_W4_PACKET_TYPE ;
kim_gdata - > rx_count = 0 ;
return ;
2010-07-22 05:32:06 -05:00
}
2011-02-04 02:23:09 -06:00
skb_reserve ( kim_gdata - > rx_skb , 8 ) ;
kim_gdata - > rx_skb - > cb [ 0 ] = 4 ;
kim_gdata - > rx_skb - > cb [ 1 ] = 0 ;
2010-07-22 05:32:06 -05:00
}
2010-04-08 13:16:54 -05:00
return ;
}
2010-07-08 08:55:17 -05:00
static long read_local_version ( struct kim_data_s * kim_gdata , char * bts_scr_name )
2010-04-08 13:16:54 -05:00
{
unsigned short version = 0 , chip = 0 , min_ver = 0 , maj_ver = 0 ;
2018-11-29 23:15:56 +00:00
static const char read_ver_cmd [ ] = { 0x01 , 0x01 , 0x10 , 0x00 } ;
2015-01-20 06:27:45 +01:00
long timeout ;
2010-04-08 13:16:54 -05:00
2010-07-22 05:32:05 -05:00
pr_debug ( " %s " , __func__ ) ;
2010-04-08 13:16:54 -05:00
2013-11-14 14:32:02 -08:00
reinit_completion ( & kim_gdata - > kim_rcvd ) ;
2010-04-08 13:16:54 -05:00
if ( 4 ! = st_int_write ( kim_gdata - > core_data , read_ver_cmd , 4 ) ) {
pr_err ( " kim: couldn't write 4 bytes " ) ;
2011-02-04 02:23:11 -06:00
return - EIO ;
2010-04-08 13:16:54 -05:00
}
2015-01-20 06:27:45 +01:00
timeout = wait_for_completion_interruptible_timeout (
& kim_gdata - > kim_rcvd , msecs_to_jiffies ( CMD_RESP_TIME ) ) ;
if ( timeout < = 0 ) {
pr_err ( " waiting for ver info- timed out or received signal " ) ;
return timeout ? - ERESTARTSYS : - ETIMEDOUT ;
2010-04-08 13:16:54 -05:00
}
2013-11-14 14:32:02 -08:00
reinit_completion ( & kim_gdata - > kim_rcvd ) ;
2012-08-03 14:49:43 -05:00
/* the positions 12 & 13 in the response buffer provide with the
* chip , major & minor numbers
*/
2010-04-08 13:16:54 -05:00
version =
2012-08-03 14:49:43 -05:00
MAKEWORD ( kim_gdata - > resp_buffer [ 12 ] ,
kim_gdata - > resp_buffer [ 13 ] ) ;
2010-04-08 13:16:54 -05:00
chip = ( version & 0x7C00 ) > > 10 ;
min_ver = ( version & 0x007F ) ;
maj_ver = ( version & 0x0380 ) > > 7 ;
if ( version & 0x8000 )
maj_ver | = 0x0008 ;
2014-07-22 13:08:38 +02:00
sprintf ( bts_scr_name , " ti-connectivity/TIInit_%d.%d.%d.bts " ,
chip , maj_ver , min_ver ) ;
2010-06-09 03:45:33 -05:00
/* to be accessed later via sysfs entry */
kim_gdata - > version . full = version ;
kim_gdata - > version . chip = chip ;
kim_gdata - > version . maj_ver = maj_ver ;
kim_gdata - > version . min_ver = min_ver ;
2010-04-08 13:16:54 -05:00
pr_info ( " %s " , bts_scr_name ) ;
2010-07-14 08:21:12 -05:00
return 0 ;
2010-04-08 13:16:54 -05:00
}
2012-08-03 14:49:40 -05:00
static void skip_change_remote_baud ( unsigned char * * ptr , long * len )
2011-02-04 02:23:13 -06:00
{
unsigned char * nxt_action , * cur_action ;
cur_action = * ptr ;
nxt_action = cur_action + sizeof ( struct bts_action ) +
( ( struct bts_action * ) cur_action ) - > size ;
if ( ( ( struct bts_action * ) nxt_action ) - > type ! = ACTION_WAIT_EVENT ) {
pr_err ( " invalid action after change remote baud command " ) ;
} else {
* ptr = * ptr + sizeof ( struct bts_action ) +
2011-05-23 11:36:11 +03:00
( ( struct bts_action * ) cur_action ) - > size ;
2011-02-04 02:23:13 -06:00
* len = * len - ( sizeof ( struct bts_action ) +
2011-05-23 11:36:11 +03:00
( ( struct bts_action * ) cur_action ) - > size ) ;
2011-02-04 02:23:13 -06:00
/* warn user on not commenting these in firmware */
pr_warn ( " skipping the wait event of change remote baud " ) ;
}
}
2010-07-22 05:32:06 -05:00
/**
* download_firmware -
* internal function which parses through the . bts firmware
* script file intreprets SEND , DELAY actions only as of now
2010-04-08 13:16:54 -05:00
*/
2010-07-08 08:55:17 -05:00
static long download_firmware ( struct kim_data_s * kim_gdata )
2010-04-08 13:16:54 -05:00
{
2010-07-14 08:21:12 -05:00
long err = 0 ;
2010-04-08 13:16:54 -05:00
long len = 0 ;
2010-10-12 16:27:38 -04:00
unsigned char * ptr = NULL ;
unsigned char * action_ptr = NULL ;
2014-07-22 13:08:38 +02:00
unsigned char bts_scr_name [ 40 ] = { 0 } ; /* 40 char long bts scr name? */
2011-02-04 02:23:13 -06:00
int wr_room_space ;
int cmd_size ;
unsigned long timeout ;
2010-04-08 13:16:54 -05:00
2010-07-08 08:55:17 -05:00
err = read_local_version ( kim_gdata , bts_scr_name ) ;
2010-07-14 08:21:12 -05:00
if ( err ! = 0 ) {
2010-04-08 13:16:54 -05:00
pr_err ( " kim: failed to read local ver " ) ;
return err ;
}
err =
request_firmware ( & kim_gdata - > fw_entry , bts_scr_name ,
& kim_gdata - > kim_pdev - > dev ) ;
if ( unlikely ( ( err ! = 0 ) | | ( kim_gdata - > fw_entry - > data = = NULL ) | |
( kim_gdata - > fw_entry - > size = = 0 ) ) ) {
pr_err ( " request_firmware failed(errno %ld) for %s " , err ,
bts_scr_name ) ;
2011-02-04 02:23:11 -06:00
return - EINVAL ;
2010-04-08 13:16:54 -05:00
}
ptr = ( void * ) kim_gdata - > fw_entry - > data ;
len = kim_gdata - > fw_entry - > size ;
/* bts_header to remove out magic number and
* version
*/
ptr + = sizeof ( struct bts_header ) ;
len - = sizeof ( struct bts_header ) ;
while ( len > 0 & & ptr ) {
2010-07-22 05:32:05 -05:00
pr_debug ( " action size %d, type %d " ,
2010-04-08 13:16:54 -05:00
( ( struct bts_action * ) ptr ) - > size ,
( ( struct bts_action * ) ptr ) - > type ) ;
switch ( ( ( struct bts_action * ) ptr ) - > type ) {
case ACTION_SEND_COMMAND : /* action send */
2011-08-10 10:18:34 -05:00
pr_debug ( " S " ) ;
2010-04-08 13:16:54 -05:00
action_ptr = & ( ( ( struct bts_action * ) ptr ) - > data [ 0 ] ) ;
if ( unlikely
( ( ( struct hci_command * ) action_ptr ) - > opcode = =
0xFF36 ) ) {
/* ignore remote change
* baud rate HCI VS command */
2011-02-04 02:23:13 -06:00
pr_warn ( " change remote baud "
2010-07-22 05:32:05 -05:00
" rate command in firmware " ) ;
2011-02-04 02:23:13 -06:00
skip_change_remote_baud ( & ptr , & len ) ;
2010-04-08 13:16:54 -05:00
break ;
}
2011-02-04 02:23:13 -06:00
/*
* Make sure we have enough free space in uart
* tx buffer to write current firmware command
*/
cmd_size = ( ( struct bts_action * ) ptr ) - > size ;
timeout = jiffies + msecs_to_jiffies ( CMD_WR_TIME ) ;
do {
wr_room_space =
st_get_uart_wr_room ( kim_gdata - > core_data ) ;
if ( wr_room_space < 0 ) {
pr_err ( " Unable to get free "
" space info from uart tx buffer " ) ;
release_firmware ( kim_gdata - > fw_entry ) ;
return wr_room_space ;
}
mdelay ( 1 ) ; /* wait 1ms before checking room */
} while ( ( wr_room_space < cmd_size ) & &
time_before ( jiffies , timeout ) ) ;
/* Timeout happened ? */
if ( time_after_eq ( jiffies , timeout ) ) {
pr_err ( " Timeout while waiting for free "
" free space in uart tx buffer " ) ;
release_firmware ( kim_gdata - > fw_entry ) ;
return - ETIMEDOUT ;
}
2011-08-10 10:18:34 -05:00
/* reinit completion before sending for the
* relevant wait
*/
2013-11-14 14:32:02 -08:00
reinit_completion ( & kim_gdata - > kim_rcvd ) ;
2010-04-08 13:16:54 -05:00
2011-02-04 02:23:13 -06:00
/*
* Free space found in uart buffer , call st_int_write
* to send current firmware command to the uart tx
* buffer .
*/
2010-04-08 13:16:54 -05:00
err = st_int_write ( kim_gdata - > core_data ,
( ( struct bts_action_send * ) action_ptr ) - > data ,
( ( struct bts_action * ) ptr ) - > size ) ;
if ( unlikely ( err < 0 ) ) {
release_firmware ( kim_gdata - > fw_entry ) ;
2011-02-04 02:23:11 -06:00
return err ;
2010-04-08 13:16:54 -05:00
}
2011-02-04 02:23:13 -06:00
/*
* Check number of bytes written to the uart tx buffer
* and requested command write size
*/
if ( err ! = cmd_size ) {
pr_err ( " Number of bytes written to uart "
" tx buffer are not matching with "
" requested cmd write size " ) ;
release_firmware ( kim_gdata - > fw_entry ) ;
return - EIO ;
}
break ;
case ACTION_WAIT_EVENT : /* wait */
2011-08-10 10:18:34 -05:00
pr_debug ( " W " ) ;
2015-01-20 06:27:45 +01:00
err = wait_for_completion_interruptible_timeout (
2012-08-03 14:49:42 -05:00
& kim_gdata - > kim_rcvd ,
2015-01-20 06:27:45 +01:00
msecs_to_jiffies ( CMD_RESP_TIME ) ) ;
if ( err < = 0 ) {
pr_err ( " response timeout/signaled during fw download " ) ;
2010-04-08 13:16:54 -05:00
/* timed out */
release_firmware ( kim_gdata - > fw_entry ) ;
2015-01-20 06:27:45 +01:00
return err ? - ERESTARTSYS : - ETIMEDOUT ;
2010-04-08 13:16:54 -05:00
}
2013-11-14 14:32:02 -08:00
reinit_completion ( & kim_gdata - > kim_rcvd ) ;
2010-04-08 13:16:54 -05:00
break ;
case ACTION_DELAY : /* sleep */
pr_info ( " sleep command in scr " ) ;
action_ptr = & ( ( ( struct bts_action * ) ptr ) - > data [ 0 ] ) ;
mdelay ( ( ( struct bts_action_delay * ) action_ptr ) - > msec ) ;
break ;
}
len =
len - ( sizeof ( struct bts_action ) +
( ( struct bts_action * ) ptr ) - > size ) ;
ptr =
ptr + sizeof ( struct bts_action ) +
( ( struct bts_action * ) ptr ) - > size ;
}
/* fw download complete */
release_firmware ( kim_gdata - > fw_entry ) ;
2010-07-14 08:21:12 -05:00
return 0 ;
2010-04-08 13:16:54 -05:00
}
/**********************************************************************/
/* functions called from ST core */
/* called from ST Core, when REG_IN_PROGRESS (registration in progress)
* can be because of
* 1. response to read local version
* 2. during send / recv ' s of firmware download
*/
void st_kim_recv ( void * disc_data , const unsigned char * data , long count )
{
2010-07-08 08:55:17 -05:00
struct st_data_s * st_gdata = ( struct st_data_s * ) disc_data ;
struct kim_data_s * kim_gdata = st_gdata - > kim_data ;
2012-08-03 14:49:43 -05:00
/* proceed to gather all data and distinguish read fw version response
* from other fw responses when data gathering is complete
*/
kim_int_recv ( kim_gdata , data , count ) ;
2010-04-08 13:16:54 -05:00
return ;
}
/* to signal completion of line discipline installation
* called from ST Core , upon tty_open
*/
2010-07-08 08:55:17 -05:00
void st_kim_complete ( void * kim_data )
2010-04-08 13:16:54 -05:00
{
2010-07-08 08:55:17 -05:00
struct kim_data_s * kim_gdata = ( struct kim_data_s * ) kim_data ;
2010-04-08 13:16:54 -05:00
complete ( & kim_gdata - > ldisc_installed ) ;
}
2010-07-22 05:32:06 -05:00
/**
* st_kim_start - called from ST Core upon 1 st registration
* This involves toggling the chip enable gpio , reading
* the firmware version from chip , forming the fw file name
* based on the chip version , requesting the fw , parsing it
* and perform download ( send / recv ) .
*/
2010-07-08 08:55:17 -05:00
long st_kim_start ( void * kim_data )
2010-04-08 13:16:54 -05:00
{
2010-07-14 08:21:12 -05:00
long err = 0 ;
2010-04-08 13:16:54 -05:00
long retry = POR_RETRY_COUNT ;
2011-08-10 10:18:31 -05:00
struct ti_st_plat_data * pdata ;
2010-07-08 08:55:17 -05:00
struct kim_data_s * kim_gdata = ( struct kim_data_s * ) kim_data ;
2010-04-08 13:16:54 -05:00
pr_info ( " %s " , __func__ ) ;
2015-07-22 13:17:15 -05:00
pdata = kim_gdata - > kim_pdev - > dev . platform_data ;
2010-04-08 13:16:54 -05:00
do {
2011-08-10 10:18:31 -05:00
/* platform specific enabling code here */
if ( pdata - > chip_enable )
pdata - > chip_enable ( kim_gdata ) ;
2013-01-21 13:12:42 +02:00
/* Configure BT nShutdown to HIGH state */
2015-06-24 12:24:06 +02:00
gpio_set_value_cansleep ( kim_gdata - > nshutdown , GPIO_LOW ) ;
2013-01-21 13:12:42 +02:00
mdelay ( 5 ) ; /* FIXME: a proper toggle */
2015-06-24 12:24:06 +02:00
gpio_set_value_cansleep ( kim_gdata - > nshutdown , GPIO_HIGH ) ;
2013-01-21 13:12:42 +02:00
mdelay ( 100 ) ;
2010-04-08 13:16:54 -05:00
/* re-initialize the completion */
2013-11-14 14:32:02 -08:00
reinit_completion ( & kim_gdata - > ldisc_installed ) ;
2011-02-04 02:23:10 -06:00
/* send notification to UIM */
kim_gdata - > ldisc_install = 1 ;
pr_info ( " ldisc_install = 1 " ) ;
sysfs_notify ( & kim_gdata - > kim_pdev - > dev . kobj ,
NULL , " install " ) ;
2010-04-08 13:16:54 -05:00
/* wait for ldisc to be installed */
2012-08-03 14:49:42 -05:00
err = wait_for_completion_interruptible_timeout (
& kim_gdata - > ldisc_installed , msecs_to_jiffies ( LDISC_TIME ) ) ;
2011-12-15 10:38:21 -06:00
if ( ! err ) {
/* ldisc installation timeout,
* flush uart , power cycle BT_EN */
pr_err ( " ldisc installation timeout " ) ;
err = st_kim_stop ( kim_gdata ) ;
2010-04-08 13:16:54 -05:00
continue ;
} else {
/* ldisc installed now */
2011-12-15 10:38:21 -06:00
pr_info ( " line discipline installed " ) ;
2010-07-08 08:55:17 -05:00
err = download_firmware ( kim_gdata ) ;
2010-07-14 08:21:12 -05:00
if ( err ! = 0 ) {
2011-12-15 10:38:21 -06:00
/* ldisc installed but fw download failed,
* flush uart & power cycle BT_EN */
2010-04-08 13:16:54 -05:00
pr_err ( " download firmware failed " ) ;
2011-12-15 10:38:21 -06:00
err = st_kim_stop ( kim_gdata ) ;
2010-04-08 13:16:54 -05:00
continue ;
} else { /* on success don't retry */
break ;
}
}
} while ( retry - - ) ;
return err ;
}
2010-07-22 05:32:06 -05:00
/**
2011-12-15 10:38:21 -06:00
* st_kim_stop - stop communication with chip .
* This can be called from ST Core / KIM , on the -
* ( a ) last un - register when chip need not be powered there - after ,
* ( b ) upon failure to either install ldisc or download firmware .
* The function is responsible to ( a ) notify UIM about un - installation ,
* ( b ) flush UART if the ldisc was installed .
2013-01-21 13:12:42 +02:00
* ( c ) reset BT_EN - pull down nshutdown at the end .
* ( d ) invoke platform ' s chip disabling routine .
2010-07-22 05:32:06 -05:00
*/
2010-07-08 08:55:17 -05:00
long st_kim_stop ( void * kim_data )
2010-04-08 13:16:54 -05:00
{
2010-07-14 08:21:12 -05:00
long err = 0 ;
2010-07-08 08:55:17 -05:00
struct kim_data_s * kim_gdata = ( struct kim_data_s * ) kim_data ;
2015-07-22 13:17:15 -05:00
struct ti_st_plat_data * pdata =
kim_gdata - > kim_pdev - > dev . platform_data ;
2011-12-15 10:38:21 -06:00
struct tty_struct * tty = kim_gdata - > core_data - > tty ;
2010-04-08 13:16:54 -05:00
2013-11-14 14:32:02 -08:00
reinit_completion ( & kim_gdata - > ldisc_installed ) ;
2011-02-04 02:23:10 -06:00
2011-12-15 10:38:21 -06:00
if ( tty ) { /* can be called before ldisc is installed */
/* Flush any pending characters in the driver and discipline. */
tty_ldisc_flush ( tty ) ;
tty_driver_flush_buffer ( tty ) ;
}
2011-02-04 02:23:10 -06:00
/* send uninstall notification to UIM */
pr_info ( " ldisc_install = 0 " ) ;
kim_gdata - > ldisc_install = 0 ;
sysfs_notify ( & kim_gdata - > kim_pdev - > dev . kobj , NULL , " install " ) ;
2010-04-08 13:16:54 -05:00
/* wait for ldisc to be un-installed */
2012-08-03 14:49:42 -05:00
err = wait_for_completion_interruptible_timeout (
& kim_gdata - > ldisc_installed , msecs_to_jiffies ( LDISC_TIME ) ) ;
2010-04-08 13:16:54 -05:00
if ( ! err ) { /* timeout */
pr_err ( " timed out waiting for ldisc to be un-installed " ) ;
2012-08-03 14:49:41 -05:00
err = - ETIMEDOUT ;
2010-04-08 13:16:54 -05:00
}
2013-01-21 13:12:42 +02:00
/* By default configure BT nShutdown to LOW state */
2015-06-24 12:24:06 +02:00
gpio_set_value_cansleep ( kim_gdata - > nshutdown , GPIO_LOW ) ;
2013-01-21 13:12:42 +02:00
mdelay ( 1 ) ;
2015-06-24 12:24:06 +02:00
gpio_set_value_cansleep ( kim_gdata - > nshutdown , GPIO_HIGH ) ;
2013-01-21 13:12:42 +02:00
mdelay ( 1 ) ;
2015-06-24 12:24:06 +02:00
gpio_set_value_cansleep ( kim_gdata - > nshutdown , GPIO_LOW ) ;
2013-01-21 13:12:42 +02:00
2011-08-10 10:18:31 -05:00
/* platform specific disable */
if ( pdata - > chip_disable )
pdata - > chip_disable ( kim_gdata ) ;
2010-04-08 13:16:54 -05:00
return err ;
}
/**********************************************************************/
/* functions called from subsystems */
2010-07-28 02:25:59 -05:00
/* called when debugfs entry is read from */
2010-06-09 03:45:33 -05:00
2018-12-01 12:05:30 -05:00
static int version_show ( struct seq_file * s , void * unused )
2010-06-09 03:45:33 -05:00
{
2010-07-28 02:25:59 -05:00
struct kim_data_s * kim_gdata = ( struct kim_data_s * ) s - > private ;
seq_printf ( s , " %04X %d.%d.%d \n " , kim_gdata - > version . full ,
2010-06-09 03:45:33 -05:00
kim_gdata - > version . chip , kim_gdata - > version . maj_ver ,
kim_gdata - > version . min_ver ) ;
2010-07-28 02:25:59 -05:00
return 0 ;
2010-04-08 13:16:54 -05:00
}
2018-12-01 12:05:30 -05:00
static int list_show ( struct seq_file * s , void * unused )
2010-04-08 13:16:54 -05:00
{
2010-07-28 02:25:59 -05:00
struct kim_data_s * kim_gdata = ( struct kim_data_s * ) s - > private ;
kim_st_list_protocols ( kim_gdata - > core_data , s ) ;
return 0 ;
2010-04-08 13:16:54 -05:00
}
2011-02-04 02:23:10 -06:00
static ssize_t show_install ( struct device * dev ,
struct device_attribute * attr , char * buf )
2010-04-08 13:16:54 -05:00
{
2011-02-04 02:23:10 -06:00
struct kim_data_s * kim_data = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %d \n " , kim_data - > ldisc_install ) ;
}
2010-04-08 13:16:54 -05:00
2011-12-15 10:38:22 -06:00
# ifdef DEBUG
static ssize_t store_dev_name ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct kim_data_s * kim_data = dev_get_drvdata ( dev ) ;
pr_debug ( " storing dev name >%s< " , buf ) ;
strncpy ( kim_data - > dev_name , buf , count ) ;
pr_debug ( " stored dev name >%s< " , kim_data - > dev_name ) ;
return count ;
}
static ssize_t store_baud_rate ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct kim_data_s * kim_data = dev_get_drvdata ( dev ) ;
pr_debug ( " storing baud rate >%s< " , buf ) ;
sscanf ( buf , " %ld " , & kim_data - > baud_rate ) ;
pr_debug ( " stored baud rate >%ld< " , kim_data - > baud_rate ) ;
return count ;
}
# endif /* if DEBUG */
2011-02-04 02:23:10 -06:00
static ssize_t show_dev_name ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct kim_data_s * kim_data = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %s \n " , kim_data - > dev_name ) ;
}
static ssize_t show_baud_rate ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct kim_data_s * kim_data = dev_get_drvdata ( dev ) ;
2015-01-15 14:42:27 +03:00
return sprintf ( buf , " %d \n " , kim_data - > baud_rate ) ;
2011-02-04 02:23:10 -06:00
}
static ssize_t show_flow_cntrl ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct kim_data_s * kim_data = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %d \n " , kim_data - > flow_cntrl ) ;
2010-04-08 13:16:54 -05:00
}
2011-02-04 02:23:10 -06:00
/* structures specific for sysfs entries */
static struct kobj_attribute ldisc_install =
__ATTR ( install , 0444 , ( void * ) show_install , NULL ) ;
static struct kobj_attribute uart_dev_name =
2011-12-15 10:38:22 -06:00
# ifdef DEBUG /* TODO: move this to debug-fs if possible */
__ATTR ( dev_name , 0644 , ( void * ) show_dev_name , ( void * ) store_dev_name ) ;
# else
2011-02-04 02:23:10 -06:00
__ATTR ( dev_name , 0444 , ( void * ) show_dev_name , NULL ) ;
2011-12-15 10:38:22 -06:00
# endif
2011-02-04 02:23:10 -06:00
static struct kobj_attribute uart_baud_rate =
2011-12-15 10:38:22 -06:00
# ifdef DEBUG /* TODO: move to debugfs */
__ATTR ( baud_rate , 0644 , ( void * ) show_baud_rate , ( void * ) store_baud_rate ) ;
# else
2011-02-04 02:23:10 -06:00
__ATTR ( baud_rate , 0444 , ( void * ) show_baud_rate , NULL ) ;
2011-12-15 10:38:22 -06:00
# endif
2011-02-04 02:23:10 -06:00
static struct kobj_attribute uart_flow_cntrl =
__ATTR ( flow_cntrl , 0444 , ( void * ) show_flow_cntrl , NULL ) ;
static struct attribute * uim_attrs [ ] = {
& ldisc_install . attr ,
& uart_dev_name . attr ,
& uart_baud_rate . attr ,
& uart_flow_cntrl . attr ,
NULL ,
} ;
2017-08-04 12:07:57 +05:30
static const struct attribute_group uim_attr_grp = {
2011-02-04 02:23:10 -06:00
. attrs = uim_attrs ,
} ;
2010-07-22 05:32:06 -05:00
/**
* st_kim_ref - reference the core ' s data
* This references the per - ST platform device in the arch / xx /
* board - xx . c file .
* This would enable multiple such platform devices to exist
* on a given platform
*/
2010-08-19 14:08:51 -04:00
void st_kim_ref ( struct st_data_s * * core_data , int id )
2010-04-08 13:16:54 -05:00
{
2010-07-08 08:55:17 -05:00
struct platform_device * pdev ;
struct kim_data_s * kim_gdata ;
/* get kim_gdata reference from platform device */
2010-08-19 14:08:51 -04:00
pdev = st_get_plat_device ( id ) ;
2015-01-09 03:48:29 +00:00
if ( ! pdev )
goto err ;
2013-05-23 19:35:23 +09:00
kim_gdata = platform_get_drvdata ( pdev ) ;
2015-01-09 03:48:29 +00:00
if ( ! kim_gdata )
goto err ;
2010-04-08 13:16:54 -05:00
* core_data = kim_gdata - > core_data ;
2015-01-09 03:48:29 +00:00
return ;
err :
* core_data = NULL ;
2010-04-08 13:16:54 -05:00
}
2018-12-01 12:05:30 -05:00
DEFINE_SHOW_ATTRIBUTE ( version ) ;
DEFINE_SHOW_ATTRIBUTE ( list ) ;
2010-07-28 02:25:59 -05:00
2010-04-08 13:16:54 -05:00
/**********************************************************************/
/* functions called from platform device driver subsystem
* need to have a relevant platform device entry in the platform ' s
* board - * . c file
*/
2012-08-03 14:49:40 -05:00
static struct dentry * kim_debugfs_dir ;
2010-04-08 13:16:54 -05:00
static int kim_probe ( struct platform_device * pdev )
{
2010-07-08 08:55:17 -05:00
struct kim_data_s * kim_gdata ;
2015-07-22 13:17:15 -05:00
struct ti_st_plat_data * pdata = pdev - > dev . platform_data ;
2012-11-22 23:26:14 +01:00
int err ;
2010-07-08 08:55:17 -05:00
2010-09-10 15:58:55 -04:00
if ( ( pdev - > id ! = - 1 ) & & ( pdev - > id < MAX_ST_DEVICES ) ) {
/* multiple devices could exist */
st_kim_devices [ pdev - > id ] = pdev ;
} else {
2011-03-30 22:57:33 -03:00
/* platform's sure about existence of 1 device */
2010-09-10 15:58:55 -04:00
st_kim_devices [ 0 ] = pdev ;
}
2018-04-11 11:07:32 +08:00
kim_gdata = kzalloc ( sizeof ( struct kim_data_s ) , GFP_KERNEL ) ;
2010-07-08 08:55:17 -05:00
if ( ! kim_gdata ) {
pr_err ( " no mem to allocate " ) ;
return - ENOMEM ;
}
2013-05-23 19:35:23 +09:00
platform_set_drvdata ( pdev , kim_gdata ) ;
2010-04-08 13:16:54 -05:00
2012-11-22 23:26:14 +01:00
err = st_core_init ( & kim_gdata - > core_data ) ;
if ( err ! = 0 ) {
2010-04-08 13:16:54 -05:00
pr_err ( " ST core init failed " ) ;
2012-11-22 23:26:14 +01:00
err = - EIO ;
goto err_core_init ;
2010-04-08 13:16:54 -05:00
}
2010-07-08 08:55:17 -05:00
/* refer to itself */
kim_gdata - > core_data - > kim_data = kim_gdata ;
2010-04-08 13:16:54 -05:00
2013-01-21 13:12:42 +02:00
/* Claim the chip enable nShutdown gpio from the system */
kim_gdata - > nshutdown = pdata - > nshutdown_gpio ;
err = gpio_request ( kim_gdata - > nshutdown , " kim " ) ;
if ( unlikely ( err ) ) {
2015-01-15 14:42:27 +03:00
pr_err ( " gpio %d request failed " , kim_gdata - > nshutdown ) ;
2018-07-27 18:45:36 +03:00
goto err_sysfs_group ;
2013-01-21 13:12:42 +02:00
}
/* Configure nShutdown GPIO as output=0 */
err = gpio_direction_output ( kim_gdata - > nshutdown , 0 ) ;
if ( unlikely ( err ) ) {
2015-01-15 14:42:27 +03:00
pr_err ( " unable to configure gpio %d " , kim_gdata - > nshutdown ) ;
2018-07-27 18:45:36 +03:00
goto err_sysfs_group ;
2013-01-21 13:12:42 +02:00
}
2010-04-08 13:16:54 -05:00
/* get reference of pdev for request_firmware
*/
kim_gdata - > kim_pdev = pdev ;
init_completion ( & kim_gdata - > kim_rcvd ) ;
init_completion ( & kim_gdata - > ldisc_installed ) ;
2010-06-09 03:45:32 -05:00
2012-11-22 23:26:14 +01:00
err = sysfs_create_group ( & pdev - > dev . kobj , & uim_attr_grp ) ;
if ( err ) {
2011-02-04 02:23:10 -06:00
pr_err ( " failed to create sysfs entries " ) ;
2012-11-22 23:26:14 +01:00
goto err_sysfs_group ;
2010-04-08 13:16:54 -05:00
}
2010-06-09 03:45:33 -05:00
2011-02-04 02:23:10 -06:00
/* copying platform data */
strncpy ( kim_gdata - > dev_name , pdata - > dev_name , UART_DEV_NAME_LEN ) ;
kim_gdata - > flow_cntrl = pdata - > flow_cntrl ;
kim_gdata - > baud_rate = pdata - > baud_rate ;
pr_info ( " sysfs entries created \n " ) ;
2010-07-28 02:25:59 -05:00
kim_debugfs_dir = debugfs_create_dir ( " ti-st " , NULL ) ;
2014-06-16 16:38:56 +02:00
if ( ! kim_debugfs_dir ) {
2010-07-28 02:25:59 -05:00
pr_err ( " debugfs entries creation failed " ) ;
2015-01-09 03:47:51 +00:00
return 0 ;
2010-06-09 03:45:33 -05:00
}
2010-07-28 02:25:59 -05:00
debugfs_create_file ( " version " , S_IRUGO , kim_debugfs_dir ,
2018-12-01 12:05:30 -05:00
kim_gdata , & version_fops ) ;
2010-07-28 02:25:59 -05:00
debugfs_create_file ( " protocols " , S_IRUGO , kim_debugfs_dir ,
2018-12-01 12:05:30 -05:00
kim_gdata , & list_fops ) ;
2010-07-14 08:21:12 -05:00
return 0 ;
2012-11-22 23:26:14 +01:00
err_sysfs_group :
st_core_exit ( kim_gdata - > core_data ) ;
err_core_init :
kfree ( kim_gdata ) ;
return err ;
2010-04-08 13:16:54 -05:00
}
static int kim_remove ( struct platform_device * pdev )
{
2013-01-21 13:12:42 +02:00
/* free the GPIOs requested */
2015-07-22 13:17:15 -05:00
struct ti_st_plat_data * pdata = pdev - > dev . platform_data ;
2010-07-08 08:55:17 -05:00
struct kim_data_s * kim_gdata ;
2013-05-23 19:35:23 +09:00
kim_gdata = platform_get_drvdata ( pdev ) ;
2010-04-08 13:16:54 -05:00
2013-01-21 13:12:42 +02:00
/* Free the Bluetooth/FM/GPIO
* nShutdown gpio from the system
*/
gpio_free ( pdata - > nshutdown_gpio ) ;
pr_info ( " nshutdown GPIO Freed " ) ;
2011-02-04 02:23:15 -06:00
debugfs_remove_recursive ( kim_debugfs_dir ) ;
2011-02-04 02:23:10 -06:00
sysfs_remove_group ( & pdev - > dev . kobj , & uim_attr_grp ) ;
2011-02-04 02:23:15 -06:00
pr_info ( " sysfs entries removed " ) ;
2010-04-08 13:16:54 -05:00
kim_gdata - > kim_pdev = NULL ;
st_core_exit ( kim_gdata - > core_data ) ;
2010-07-08 08:55:17 -05:00
kfree ( kim_gdata ) ;
kim_gdata = NULL ;
2010-07-14 08:21:12 -05:00
return 0 ;
2010-04-08 13:16:54 -05:00
}
2012-08-03 14:49:40 -05:00
static int kim_suspend ( struct platform_device * pdev , pm_message_t state )
2011-02-04 02:23:10 -06:00
{
2015-07-22 13:17:15 -05:00
struct ti_st_plat_data * pdata = pdev - > dev . platform_data ;
2011-02-04 02:23:10 -06:00
if ( pdata - > suspend )
return pdata - > suspend ( pdev , state ) ;
2015-01-09 03:46:24 +00:00
return 0 ;
2011-02-04 02:23:10 -06:00
}
2012-08-03 14:49:40 -05:00
static int kim_resume ( struct platform_device * pdev )
2011-02-04 02:23:10 -06:00
{
2015-07-22 13:17:15 -05:00
struct ti_st_plat_data * pdata = pdev - > dev . platform_data ;
2011-02-04 02:23:10 -06:00
if ( pdata - > resume )
return pdata - > resume ( pdev ) ;
2015-01-09 03:46:24 +00:00
return 0 ;
2011-02-04 02:23:10 -06:00
}
2010-04-08 13:16:54 -05:00
/**********************************************************************/
/* entry point for ST KIM module, called in from ST Core */
2011-02-04 02:23:10 -06:00
static struct platform_driver kim_platform_driver = {
. probe = kim_probe ,
. remove = kim_remove ,
. suspend = kim_suspend ,
. resume = kim_resume ,
. driver = {
. name = " kim " ,
} ,
} ;
2010-04-08 13:16:54 -05:00
2012-01-22 15:33:49 +08:00
module_platform_driver ( kim_platform_driver ) ;
2010-04-08 13:16:54 -05:00
MODULE_AUTHOR ( " Pavan Savoy <pavan_savoy@ti.com> " ) ;
MODULE_DESCRIPTION ( " Shared Transport Driver for TI BT/FM/GPS combo chips " ) ;
MODULE_LICENSE ( " GPL " ) ;