2017-12-14 08:49:34 +03:00
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
// Copyright(c) 2015-17 Intel Corporation.
# include <linux/acpi.h>
2020-01-15 03:08:43 +03:00
# include <linux/delay.h>
2017-12-14 08:49:34 +03:00
# include <linux/mod_devicetable.h>
2017-12-14 08:49:37 +03:00
# include <linux/pm_runtime.h>
# include <linux/soundwire/sdw_registers.h>
2017-12-14 08:49:34 +03:00
# include <linux/soundwire/sdw.h>
# include "bus.h"
2020-05-18 23:35:51 +03:00
# include "sysfs_local.h"
2017-12-14 08:49:34 +03:00
2020-05-18 20:43:20 +03:00
static DEFINE_IDA ( sdw_ida ) ;
static int sdw_get_id ( struct sdw_bus * bus )
{
int rc = ida_alloc ( & sdw_ida , GFP_KERNEL ) ;
if ( rc < 0 )
return rc ;
bus - > id = rc ;
return 0 ;
}
2017-12-14 08:49:34 +03:00
/**
2020-05-18 20:43:18 +03:00
* sdw_bus_master_add ( ) - add a bus Master instance
2017-12-14 08:49:34 +03:00
* @ bus : bus instance
2020-05-18 20:43:18 +03:00
* @ parent : parent device
* @ fwnode : firmware node handle
2017-12-14 08:49:34 +03:00
*
* Initializes the bus instance , read properties and create child
* devices .
*/
2020-05-18 20:43:18 +03:00
int sdw_bus_master_add ( struct sdw_bus * bus , struct device * parent ,
struct fwnode_handle * fwnode )
2017-12-14 08:49:34 +03:00
{
2018-04-26 16:08:33 +03:00
struct sdw_master_prop * prop = NULL ;
2017-12-14 08:49:34 +03:00
int ret ;
2020-05-18 20:43:21 +03:00
if ( ! parent ) {
pr_err ( " SoundWire parent device is not set \n " ) ;
2017-12-14 08:49:34 +03:00
return - ENODEV ;
}
2020-05-18 20:43:20 +03:00
ret = sdw_get_id ( bus ) ;
if ( ret ) {
2020-05-18 20:43:21 +03:00
dev_err ( parent , " Failed to get bus id \n " ) ;
return ret ;
}
ret = sdw_master_device_add ( bus , parent , fwnode ) ;
if ( ret ) {
dev_err ( parent , " Failed to add master device at link %d \n " ,
bus - > link_id ) ;
2020-05-18 20:43:20 +03:00
return ret ;
}
2017-12-14 08:49:37 +03:00
if ( ! bus - > ops ) {
2019-05-01 18:57:45 +03:00
dev_err ( bus - > dev , " SoundWire Bus ops are not set \n " ) ;
2017-12-14 08:49:37 +03:00
return - EINVAL ;
}
mutex_init ( & bus - > msg_lock ) ;
2017-12-14 08:49:34 +03:00
mutex_init ( & bus - > bus_lock ) ;
INIT_LIST_HEAD ( & bus - > slaves ) ;
2018-04-26 16:08:08 +03:00
INIT_LIST_HEAD ( & bus - > m_rt_list ) ;
2017-12-14 08:49:34 +03:00
2018-07-27 12:14:16 +03:00
/*
* Initialize multi_link flag
* TODO : populate this flag by reading property from FW node
*/
bus - > multi_link = false ;
2017-12-14 08:49:35 +03:00
if ( bus - > ops - > read_prop ) {
ret = bus - > ops - > read_prop ( bus ) ;
if ( ret < 0 ) {
2019-05-02 13:59:24 +03:00
dev_err ( bus - > dev ,
" Bus read properties failed:%d \n " , ret ) ;
2017-12-14 08:49:35 +03:00
return ret ;
}
}
2019-08-21 21:58:18 +03:00
sdw_bus_debugfs_init ( bus ) ;
2017-12-14 08:49:34 +03:00
/*
2019-05-01 18:57:28 +03:00
* Device numbers in SoundWire are 0 through 15. Enumeration device
2017-12-14 08:49:34 +03:00
* number ( 0 ) , Broadcast device number ( 15 ) , Group numbers ( 12 and
* 13 ) and Master device number ( 14 ) are not used for assignment so
* mask these and other higher bits .
*/
/* Set higher order bits */
* bus - > assigned = ~ GENMASK ( SDW_BROADCAST_DEV_NUM , SDW_ENUM_DEV_NUM ) ;
/* Set enumuration device number and broadcast device number */
set_bit ( SDW_ENUM_DEV_NUM , bus - > assigned ) ;
set_bit ( SDW_BROADCAST_DEV_NUM , bus - > assigned ) ;
/* Set group device numbers and master device number */
set_bit ( SDW_GROUP12_DEV_NUM , bus - > assigned ) ;
set_bit ( SDW_GROUP13_DEV_NUM , bus - > assigned ) ;
set_bit ( SDW_MASTER_DEV_NUM , bus - > assigned ) ;
/*
* SDW is an enumerable bus , but devices can be powered off . So ,
* they won ' t be able to report as present .
*
* Create Slave devices based on Slaves described in
* the respective firmware ( ACPI / DT )
*/
if ( IS_ENABLED ( CONFIG_ACPI ) & & ACPI_HANDLE ( bus - > dev ) )
ret = sdw_acpi_find_slaves ( bus ) ;
2019-08-29 19:35:12 +03:00
else if ( IS_ENABLED ( CONFIG_OF ) & & bus - > dev - > of_node )
ret = sdw_of_find_slaves ( bus ) ;
2017-12-14 08:49:34 +03:00
else
ret = - ENOTSUPP ; /* No ACPI/DT so error out */
if ( ret ) {
dev_err ( bus - > dev , " Finding slaves failed:%d \n " , ret ) ;
return ret ;
}
2018-04-26 16:08:28 +03:00
/*
2018-04-26 16:08:33 +03:00
* Initialize clock values based on Master properties . The max
2019-05-22 22:47:22 +03:00
* frequency is read from max_clk_freq property . Current assumption
2018-04-26 16:08:33 +03:00
* is that the bus will start at highest clock frequency when
* powered on .
*
2018-04-26 16:08:28 +03:00
* Default active bank will be 0 as out of reset the Slaves have
* to start with bank 0 ( Table 40 of Spec )
*/
2018-04-26 16:08:33 +03:00
prop = & bus - > prop ;
2019-05-22 22:47:22 +03:00
bus - > params . max_dr_freq = prop - > max_clk_freq * SDW_DOUBLE_RATE_FACTOR ;
2018-04-26 16:08:33 +03:00
bus - > params . curr_dr_freq = bus - > params . max_dr_freq ;
2018-04-26 16:08:28 +03:00
bus - > params . curr_bank = SDW_BANK0 ;
bus - > params . next_bank = SDW_BANK1 ;
2017-12-14 08:49:34 +03:00
return 0 ;
}
2020-05-18 20:43:18 +03:00
EXPORT_SYMBOL ( sdw_bus_master_add ) ;
2017-12-14 08:49:34 +03:00
static int sdw_delete_slave ( struct device * dev , void * data )
{
struct sdw_slave * slave = dev_to_sdw_dev ( dev ) ;
struct sdw_bus * bus = slave - > bus ;
2020-01-15 03:08:41 +03:00
pm_runtime_disable ( dev ) ;
2019-08-21 21:58:18 +03:00
sdw_slave_debugfs_exit ( slave ) ;
2017-12-14 08:49:34 +03:00
mutex_lock ( & bus - > bus_lock ) ;
if ( slave - > dev_num ) /* clear dev_num if assigned */
clear_bit ( slave - > dev_num , bus - > assigned ) ;
list_del_init ( & slave - > node ) ;
mutex_unlock ( & bus - > bus_lock ) ;
device_unregister ( dev ) ;
return 0 ;
}
/**
2020-05-18 20:43:18 +03:00
* sdw_bus_master_delete ( ) - delete the bus master instance
2017-12-14 08:49:34 +03:00
* @ bus : bus to be deleted
*
* Remove the instance , delete the child devices .
*/
2020-05-18 20:43:18 +03:00
void sdw_bus_master_delete ( struct sdw_bus * bus )
2017-12-14 08:49:34 +03:00
{
device_for_each_child ( bus - > dev , NULL , sdw_delete_slave ) ;
2020-05-18 20:43:21 +03:00
sdw_master_device_del ( bus ) ;
2019-08-21 21:58:18 +03:00
sdw_bus_debugfs_exit ( bus ) ;
2020-05-18 20:43:20 +03:00
ida_free ( & sdw_ida , bus - > id ) ;
2017-12-14 08:49:34 +03:00
}
2020-05-18 20:43:18 +03:00
EXPORT_SYMBOL ( sdw_bus_master_delete ) ;
2017-12-14 08:49:34 +03:00
2017-12-14 08:49:37 +03:00
/*
* SDW IO Calls
*/
static inline int find_response_code ( enum sdw_command_response resp )
{
switch ( resp ) {
case SDW_CMD_OK :
return 0 ;
case SDW_CMD_IGNORED :
return - ENODATA ;
case SDW_CMD_TIMEOUT :
return - ETIMEDOUT ;
default :
return - EIO ;
}
}
static inline int do_transfer ( struct sdw_bus * bus , struct sdw_msg * msg )
{
int retry = bus - > prop . err_threshold ;
enum sdw_command_response resp ;
int ret = 0 , i ;
for ( i = 0 ; i < = retry ; i + + ) {
resp = bus - > ops - > xfer_msg ( bus , msg ) ;
ret = find_response_code ( resp ) ;
/* if cmd is ok or ignored return */
if ( ret = = 0 | | ret = = - ENODATA )
return ret ;
}
return ret ;
}
static inline int do_transfer_defer ( struct sdw_bus * bus ,
2019-05-01 18:57:27 +03:00
struct sdw_msg * msg ,
struct sdw_defer * defer )
2017-12-14 08:49:37 +03:00
{
int retry = bus - > prop . err_threshold ;
enum sdw_command_response resp ;
int ret = 0 , i ;
defer - > msg = msg ;
defer - > length = msg - > len ;
2018-07-27 12:14:12 +03:00
init_completion ( & defer - > complete ) ;
2017-12-14 08:49:37 +03:00
for ( i = 0 ; i < = retry ; i + + ) {
resp = bus - > ops - > xfer_msg_defer ( bus , msg , defer ) ;
ret = find_response_code ( resp ) ;
/* if cmd is ok or ignored return */
if ( ret = = 0 | | ret = = - ENODATA )
return ret ;
}
return ret ;
}
static int sdw_reset_page ( struct sdw_bus * bus , u16 dev_num )
{
int retry = bus - > prop . err_threshold ;
enum sdw_command_response resp ;
int ret = 0 , i ;
for ( i = 0 ; i < = retry ; i + + ) {
resp = bus - > ops - > reset_page_addr ( bus , dev_num ) ;
ret = find_response_code ( resp ) ;
/* if cmd is ok or ignored return */
if ( ret = = 0 | | ret = = - ENODATA )
return ret ;
}
return ret ;
}
/**
* sdw_transfer ( ) - Synchronous transfer message to a SDW Slave device
* @ bus : SDW bus
* @ msg : SDW message to be xfered
*/
int sdw_transfer ( struct sdw_bus * bus , struct sdw_msg * msg )
{
int ret ;
mutex_lock ( & bus - > msg_lock ) ;
ret = do_transfer ( bus , msg ) ;
if ( ret ! = 0 & & ret ! = - ENODATA )
dev_err ( bus - > dev , " trf on Slave %d failed:%d \n " ,
2019-05-01 18:57:27 +03:00
msg - > dev_num , ret ) ;
2017-12-14 08:49:37 +03:00
if ( msg - > page )
sdw_reset_page ( bus , msg - > dev_num ) ;
mutex_unlock ( & bus - > msg_lock ) ;
return ret ;
}
/**
* sdw_transfer_defer ( ) - Asynchronously transfer message to a SDW Slave device
* @ bus : SDW bus
* @ msg : SDW message to be xfered
* @ defer : Defer block for signal completion
*
* Caller needs to hold the msg_lock lock while calling this
*/
int sdw_transfer_defer ( struct sdw_bus * bus , struct sdw_msg * msg ,
2019-05-01 18:57:27 +03:00
struct sdw_defer * defer )
2017-12-14 08:49:37 +03:00
{
int ret ;
if ( ! bus - > ops - > xfer_msg_defer )
return - ENOTSUPP ;
ret = do_transfer_defer ( bus , msg , defer ) ;
if ( ret ! = 0 & & ret ! = - ENODATA )
dev_err ( bus - > dev , " Defer trf on Slave %d failed:%d \n " ,
2019-05-01 18:57:27 +03:00
msg - > dev_num , ret ) ;
2017-12-14 08:49:37 +03:00
if ( msg - > page )
sdw_reset_page ( bus , msg - > dev_num ) ;
return ret ;
}
int sdw_fill_msg ( struct sdw_msg * msg , struct sdw_slave * slave ,
2019-05-01 18:57:27 +03:00
u32 addr , size_t count , u16 dev_num , u8 flags , u8 * buf )
2017-12-14 08:49:37 +03:00
{
memset ( msg , 0 , sizeof ( * msg ) ) ;
msg - > addr = addr ; /* addr is 16 bit and truncated here */
msg - > len = count ;
msg - > dev_num = dev_num ;
msg - > flags = flags ;
msg - > buf = buf ;
2020-05-08 03:30:45 +03:00
if ( addr < SDW_REG_NO_PAGE ) /* no paging area */
2017-12-14 08:49:37 +03:00
return 0 ;
2020-05-08 03:30:45 +03:00
if ( addr > = SDW_REG_MAX ) { /* illegal addr */
2017-12-14 08:49:37 +03:00
pr_err ( " SDW: Invalid address %x passed \n " , addr ) ;
return - EINVAL ;
}
if ( addr < SDW_REG_OPTIONAL_PAGE ) { /* 32k but no page */
if ( slave & & ! slave - > prop . paging_support )
return 0 ;
2019-05-01 18:57:28 +03:00
/* no need for else as that will fall-through to paging */
2017-12-14 08:49:37 +03:00
}
/* paging mandatory */
if ( dev_num = = SDW_ENUM_DEV_NUM | | dev_num = = SDW_BROADCAST_DEV_NUM ) {
pr_err ( " SDW: Invalid device for paging :%d \n " , dev_num ) ;
return - EINVAL ;
}
if ( ! slave ) {
pr_err ( " SDW: No slave for paging addr \n " ) ;
return - EINVAL ;
2020-05-08 03:30:45 +03:00
}
if ( ! slave - > prop . paging_support ) {
2017-12-14 08:49:37 +03:00
dev_err ( & slave - > dev ,
2019-05-01 18:57:45 +03:00
" address %x needs paging but no support \n " , addr ) ;
2017-12-14 08:49:37 +03:00
return - EINVAL ;
}
msg - > addr_page1 = ( addr > > SDW_REG_SHIFT ( SDW_SCP_ADDRPAGE1_MASK ) ) ;
msg - > addr_page2 = ( addr > > SDW_REG_SHIFT ( SDW_SCP_ADDRPAGE2_MASK ) ) ;
msg - > addr | = BIT ( 15 ) ;
msg - > page = true ;
return 0 ;
}
2020-01-15 03:08:38 +03:00
/*
* Read / Write IO functions .
* no_pm versions can only be called by the bus , e . g . while enumerating or
* handling suspend - resume sequences .
* all clients need to use the pm versions
*/
static int
sdw_nread_no_pm ( struct sdw_slave * slave , u32 addr , size_t count , u8 * val )
{
struct sdw_msg msg ;
int ret ;
ret = sdw_fill_msg ( & msg , slave , addr , count ,
slave - > dev_num , SDW_MSG_FLAG_READ , val ) ;
if ( ret < 0 )
return ret ;
return sdw_transfer ( slave - > bus , & msg ) ;
}
static int
sdw_nwrite_no_pm ( struct sdw_slave * slave , u32 addr , size_t count , u8 * val )
{
struct sdw_msg msg ;
int ret ;
ret = sdw_fill_msg ( & msg , slave , addr , count ,
slave - > dev_num , SDW_MSG_FLAG_WRITE , val ) ;
if ( ret < 0 )
return ret ;
return sdw_transfer ( slave - > bus , & msg ) ;
}
static int sdw_write_no_pm ( struct sdw_slave * slave , u32 addr , u8 value )
{
return sdw_nwrite_no_pm ( slave , addr , 1 , & value ) ;
}
2020-01-15 03:08:43 +03:00
static int
sdw_bread_no_pm ( struct sdw_bus * bus , u16 dev_num , u32 addr )
{
struct sdw_msg msg ;
u8 buf ;
int ret ;
ret = sdw_fill_msg ( & msg , NULL , addr , 1 , dev_num ,
SDW_MSG_FLAG_READ , & buf ) ;
if ( ret )
return ret ;
ret = sdw_transfer ( bus , & msg ) ;
if ( ret < 0 )
return ret ;
2020-05-08 03:30:45 +03:00
return buf ;
2020-01-15 03:08:43 +03:00
}
static int
sdw_bwrite_no_pm ( struct sdw_bus * bus , u16 dev_num , u32 addr , u8 value )
{
struct sdw_msg msg ;
int ret ;
ret = sdw_fill_msg ( & msg , NULL , addr , 1 , dev_num ,
SDW_MSG_FLAG_WRITE , & value ) ;
if ( ret )
return ret ;
return sdw_transfer ( bus , & msg ) ;
}
static int
sdw_read_no_pm ( struct sdw_slave * slave , u32 addr )
{
u8 buf ;
int ret ;
ret = sdw_nread_no_pm ( slave , addr , 1 , & buf ) ;
if ( ret < 0 )
return ret ;
else
return buf ;
}
2017-12-14 08:49:37 +03:00
/**
* sdw_nread ( ) - Read " n " contiguous SDW Slave registers
* @ slave : SDW Slave
* @ addr : Register address
* @ count : length
* @ val : Buffer for values to be read
*/
int sdw_nread ( struct sdw_slave * slave , u32 addr , size_t count , u8 * val )
{
int ret ;
ret = pm_runtime_get_sync ( slave - > bus - > dev ) ;
2020-01-15 03:08:38 +03:00
if ( ret < 0 & & ret ! = - EACCES ) {
pm_runtime_put_noidle ( slave - > bus - > dev ) ;
2017-12-14 08:49:37 +03:00
return ret ;
2020-01-15 03:08:38 +03:00
}
ret = sdw_nread_no_pm ( slave , addr , count , val ) ;
2017-12-14 08:49:37 +03:00
2020-01-15 03:08:38 +03:00
pm_runtime_mark_last_busy ( slave - > bus - > dev ) ;
2017-12-14 08:49:37 +03:00
pm_runtime_put ( slave - > bus - > dev ) ;
return ret ;
}
EXPORT_SYMBOL ( sdw_nread ) ;
/**
* sdw_nwrite ( ) - Write " n " contiguous SDW Slave registers
* @ slave : SDW Slave
* @ addr : Register address
* @ count : length
* @ val : Buffer for values to be read
*/
int sdw_nwrite ( struct sdw_slave * slave , u32 addr , size_t count , u8 * val )
{
int ret ;
ret = pm_runtime_get_sync ( slave - > bus - > dev ) ;
2020-01-15 03:08:38 +03:00
if ( ret < 0 & & ret ! = - EACCES ) {
pm_runtime_put_noidle ( slave - > bus - > dev ) ;
2017-12-14 08:49:37 +03:00
return ret ;
2020-01-15 03:08:38 +03:00
}
ret = sdw_nwrite_no_pm ( slave , addr , count , val ) ;
2017-12-14 08:49:37 +03:00
2020-01-15 03:08:38 +03:00
pm_runtime_mark_last_busy ( slave - > bus - > dev ) ;
2017-12-14 08:49:37 +03:00
pm_runtime_put ( slave - > bus - > dev ) ;
return ret ;
}
EXPORT_SYMBOL ( sdw_nwrite ) ;
/**
* sdw_read ( ) - Read a SDW Slave register
* @ slave : SDW Slave
* @ addr : Register address
*/
int sdw_read ( struct sdw_slave * slave , u32 addr )
{
u8 buf ;
int ret ;
ret = sdw_nread ( slave , addr , 1 , & buf ) ;
if ( ret < 0 )
return ret ;
2020-05-08 03:30:45 +03:00
return buf ;
2017-12-14 08:49:37 +03:00
}
EXPORT_SYMBOL ( sdw_read ) ;
/**
* sdw_write ( ) - Write a SDW Slave register
* @ slave : SDW Slave
* @ addr : Register address
* @ value : Register value
*/
int sdw_write ( struct sdw_slave * slave , u32 addr , u8 value )
{
return sdw_nwrite ( slave , addr , 1 , & value ) ;
}
EXPORT_SYMBOL ( sdw_write ) ;
2017-12-14 08:49:39 +03:00
/*
* SDW alert handling
*/
/* called with bus_lock held */
static struct sdw_slave * sdw_get_slave ( struct sdw_bus * bus , int i )
{
struct sdw_slave * slave = NULL ;
list_for_each_entry ( slave , & bus - > slaves , node ) {
if ( slave - > dev_num = = i )
return slave ;
}
return NULL ;
}
static int sdw_compare_devid ( struct sdw_slave * slave , struct sdw_slave_id id )
{
2019-10-23 02:48:08 +03:00
if ( slave - > id . mfg_id ! = id . mfg_id | |
2019-05-01 18:57:29 +03:00
slave - > id . part_id ! = id . part_id | |
2019-10-23 02:48:08 +03:00
slave - > id . class_id ! = id . class_id | |
( slave - > id . unique_id ! = SDW_IGNORED_UNIQUE_ID & &
slave - > id . unique_id ! = id . unique_id ) )
2017-12-14 08:49:39 +03:00
return - ENODEV ;
return 0 ;
}
/* called with bus_lock held */
static int sdw_get_device_num ( struct sdw_slave * slave )
{
int bit ;
bit = find_first_zero_bit ( slave - > bus - > assigned , SDW_MAX_DEVICES ) ;
if ( bit = = SDW_MAX_DEVICES ) {
bit = - ENODEV ;
goto err ;
}
/*
* Do not update dev_num in Slave data structure here ,
* Update once program dev_num is successful
*/
set_bit ( bit , slave - > bus - > assigned ) ;
err :
return bit ;
}
static int sdw_assign_device_num ( struct sdw_slave * slave )
{
int ret , dev_num ;
2020-01-14 01:56:37 +03:00
bool new_device = false ;
2017-12-14 08:49:39 +03:00
/* check first if device number is assigned, if so reuse that */
if ( ! slave - > dev_num ) {
2020-01-14 01:56:37 +03:00
if ( ! slave - > dev_num_sticky ) {
mutex_lock ( & slave - > bus - > bus_lock ) ;
dev_num = sdw_get_device_num ( slave ) ;
mutex_unlock ( & slave - > bus - > bus_lock ) ;
if ( dev_num < 0 ) {
dev_err ( slave - > bus - > dev , " Get dev_num failed: %d \n " ,
dev_num ) ;
return dev_num ;
}
slave - > dev_num = dev_num ;
slave - > dev_num_sticky = dev_num ;
new_device = true ;
} else {
slave - > dev_num = slave - > dev_num_sticky ;
2017-12-14 08:49:39 +03:00
}
2020-01-14 01:56:37 +03:00
}
if ( ! new_device )
2020-04-19 21:51:17 +03:00
dev_dbg ( slave - > bus - > dev ,
" Slave already registered, reusing dev_num:%d \n " ,
slave - > dev_num ) ;
2017-12-14 08:49:39 +03:00
2020-01-14 01:56:37 +03:00
/* Clear the slave->dev_num to transfer message on device 0 */
dev_num = slave - > dev_num ;
slave - > dev_num = 0 ;
2017-12-14 08:49:39 +03:00
2020-01-15 03:08:39 +03:00
ret = sdw_write_no_pm ( slave , SDW_SCP_DEVNUMBER , dev_num ) ;
2017-12-14 08:49:39 +03:00
if ( ret < 0 ) {
2019-08-06 03:55:09 +03:00
dev_err ( & slave - > dev , " Program device_num %d failed: %d \n " ,
dev_num , ret ) ;
2017-12-14 08:49:39 +03:00
return ret ;
}
/* After xfer of msg, restore dev_num */
2020-01-14 01:56:37 +03:00
slave - > dev_num = slave - > dev_num_sticky ;
2017-12-14 08:49:39 +03:00
return 0 ;
}
2017-12-14 08:49:34 +03:00
void sdw_extract_slave_id ( struct sdw_bus * bus ,
2019-05-01 18:57:27 +03:00
u64 addr , struct sdw_slave_id * id )
2017-12-14 08:49:34 +03:00
{
2019-05-01 18:57:45 +03:00
dev_dbg ( bus - > dev , " SDW Slave Addr: %llx \n " , addr ) ;
2017-12-14 08:49:34 +03:00
2020-02-25 20:00:41 +03:00
id - > sdw_version = SDW_VERSION ( addr ) ;
id - > unique_id = SDW_UNIQUE_ID ( addr ) ;
id - > mfg_id = SDW_MFG_ID ( addr ) ;
id - > part_id = SDW_PART_ID ( addr ) ;
id - > class_id = SDW_CLASS_ID ( addr ) ;
2017-12-14 08:49:34 +03:00
dev_dbg ( bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW Slave class_id %x, part_id %x, mfg_id %x, unique_id %x, version %x \n " ,
2017-12-14 08:49:34 +03:00
id - > class_id , id - > part_id , id - > mfg_id ,
id - > unique_id , id - > sdw_version ) ;
}
2017-12-14 08:49:39 +03:00
static int sdw_program_device_num ( struct sdw_bus * bus )
{
u8 buf [ SDW_NUM_DEV_ID_REGISTERS ] = { 0 } ;
struct sdw_slave * slave , * _s ;
struct sdw_slave_id id ;
struct sdw_msg msg ;
bool found = false ;
int count = 0 , ret ;
u64 addr ;
/* No Slave, so use raw xfer api */
ret = sdw_fill_msg ( & msg , NULL , SDW_SCP_DEVID_0 ,
2019-05-01 18:57:27 +03:00
SDW_NUM_DEV_ID_REGISTERS , 0 , SDW_MSG_FLAG_READ , buf ) ;
2017-12-14 08:49:39 +03:00
if ( ret < 0 )
return ret ;
do {
ret = sdw_transfer ( bus , & msg ) ;
if ( ret = = - ENODATA ) { /* end of device id reads */
2019-08-06 03:55:09 +03:00
dev_dbg ( bus - > dev , " No more devices to enumerate \n " ) ;
2017-12-14 08:49:39 +03:00
ret = 0 ;
break ;
}
if ( ret < 0 ) {
dev_err ( bus - > dev , " DEVID read fail:%d \n " , ret ) ;
break ;
}
/*
* Construct the addr and extract . Cast the higher shift
* bits to avoid truncation due to size limit .
*/
addr = buf [ 5 ] | ( buf [ 4 ] < < 8 ) | ( buf [ 3 ] < < 16 ) |
2018-01-08 19:52:42 +03:00
( ( u64 ) buf [ 2 ] < < 24 ) | ( ( u64 ) buf [ 1 ] < < 32 ) |
( ( u64 ) buf [ 0 ] < < 40 ) ;
2017-12-14 08:49:39 +03:00
sdw_extract_slave_id ( bus , addr , & id ) ;
/* Now compare with entries */
list_for_each_entry_safe ( slave , _s , & bus - > slaves , node ) {
if ( sdw_compare_devid ( slave , id ) = = 0 ) {
found = true ;
/*
* Assign a new dev_num to this Slave and
* not mark it present . It will be marked
* present after it reports ATTACHED on new
* dev_num
*/
ret = sdw_assign_device_num ( slave ) ;
if ( ret ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" Assign dev_num failed:%d \n " ,
2017-12-14 08:49:39 +03:00
ret ) ;
return ret ;
}
break ;
}
}
2019-05-01 18:57:30 +03:00
if ( ! found ) {
2017-12-14 08:49:39 +03:00
/* TODO: Park this device in Group 13 */
2019-05-01 18:57:45 +03:00
dev_err ( bus - > dev , " Slave Entry not found \n " ) ;
2017-12-14 08:49:39 +03:00
}
count + + ;
/*
* Check till error out or retry ( count ) exhausts .
* Device can drop off and rejoin during enumeration
* so count till twice the bound .
*/
} while ( ret = = 0 & & count < ( SDW_MAX_DEVICES * 2 ) ) ;
return ret ;
}
static void sdw_modify_slave_status ( struct sdw_slave * slave ,
2019-05-01 18:57:27 +03:00
enum sdw_slave_status status )
2017-12-14 08:49:39 +03:00
{
mutex_lock ( & slave - > bus - > bus_lock ) ;
2020-01-15 03:08:36 +03:00
dev_vdbg ( & slave - > dev ,
" %s: changing status slave %d status %d new status %d \n " ,
__func__ , slave - > dev_num , slave - > status , status ) ;
if ( status = = SDW_SLAVE_UNATTACHED ) {
dev_dbg ( & slave - > dev ,
" %s: initializing completion for Slave %d \n " ,
__func__ , slave - > dev_num ) ;
init_completion ( & slave - > enumeration_complete ) ;
2020-01-15 03:08:37 +03:00
init_completion ( & slave - > initialization_complete ) ;
2020-01-15 03:08:36 +03:00
} else if ( ( status = = SDW_SLAVE_ATTACHED ) & &
( slave - > status = = SDW_SLAVE_UNATTACHED ) ) {
dev_dbg ( & slave - > dev ,
" %s: signaling completion for Slave %d \n " ,
__func__ , slave - > dev_num ) ;
complete ( & slave - > enumeration_complete ) ;
}
2017-12-14 08:49:39 +03:00
slave - > status = status ;
mutex_unlock ( & slave - > bus - > bus_lock ) ;
}
2020-01-15 03:08:43 +03:00
static enum sdw_clk_stop_mode sdw_get_clk_stop_mode ( struct sdw_slave * slave )
{
enum sdw_clk_stop_mode mode ;
/*
* Query for clock stop mode if Slave implements
* ops - > get_clk_stop_mode , else read from property .
*/
if ( slave - > ops & & slave - > ops - > get_clk_stop_mode ) {
mode = slave - > ops - > get_clk_stop_mode ( slave ) ;
} else {
if ( slave - > prop . clk_stop_mode1 )
mode = SDW_CLK_STOP_MODE1 ;
else
mode = SDW_CLK_STOP_MODE0 ;
}
return mode ;
}
static int sdw_slave_clk_stop_callback ( struct sdw_slave * slave ,
enum sdw_clk_stop_mode mode ,
enum sdw_clk_stop_type type )
{
int ret ;
if ( slave - > ops & & slave - > ops - > clk_stop ) {
ret = slave - > ops - > clk_stop ( slave , mode , type ) ;
if ( ret < 0 ) {
dev_err ( & slave - > dev ,
" Clk Stop type =%d failed: %d \n " , type , ret ) ;
return ret ;
}
}
return 0 ;
}
static int sdw_slave_clk_stop_prepare ( struct sdw_slave * slave ,
enum sdw_clk_stop_mode mode ,
bool prepare )
{
bool wake_en ;
u32 val = 0 ;
int ret ;
wake_en = slave - > prop . wake_capable ;
if ( prepare ) {
val = SDW_SCP_SYSTEMCTRL_CLK_STP_PREP ;
if ( mode = = SDW_CLK_STOP_MODE1 )
val | = SDW_SCP_SYSTEMCTRL_CLK_STP_MODE1 ;
if ( wake_en )
val | = SDW_SCP_SYSTEMCTRL_WAKE_UP_EN ;
} else {
val = sdw_read_no_pm ( slave , SDW_SCP_SYSTEMCTRL ) ;
val & = ~ ( SDW_SCP_SYSTEMCTRL_CLK_STP_PREP ) ;
}
ret = sdw_write_no_pm ( slave , SDW_SCP_SYSTEMCTRL , val ) ;
if ( ret ! = 0 )
dev_err ( & slave - > dev ,
" Clock Stop prepare failed for slave: %d " , ret ) ;
return ret ;
}
static int sdw_bus_wait_for_clk_prep_deprep ( struct sdw_bus * bus , u16 dev_num )
{
int retry = bus - > clk_stop_timeout ;
int val ;
do {
val = sdw_bread_no_pm ( bus , dev_num , SDW_SCP_STAT ) &
SDW_SCP_STAT_CLK_STP_NF ;
if ( ! val ) {
dev_info ( bus - > dev , " clock stop prep/de-prep done slave:%d " ,
dev_num ) ;
return 0 ;
}
usleep_range ( 1000 , 1500 ) ;
retry - - ;
} while ( retry ) ;
dev_err ( bus - > dev , " clock stop prep/de-prep failed slave:%d " ,
dev_num ) ;
return - ETIMEDOUT ;
}
/**
* sdw_bus_prep_clk_stop : prepare Slave ( s ) for clock stop
*
* @ bus : SDW bus instance
*
* Query Slave for clock stop mode and prepare for that mode .
*/
int sdw_bus_prep_clk_stop ( struct sdw_bus * bus )
{
enum sdw_clk_stop_mode slave_mode ;
bool simple_clk_stop = true ;
struct sdw_slave * slave ;
bool is_slave = false ;
int ret = 0 ;
/*
* In order to save on transition time , prepare
* each Slave and then wait for all Slave ( s ) to be
* prepared for clock stop .
*/
list_for_each_entry ( slave , & bus - > slaves , node ) {
if ( ! slave - > dev_num )
continue ;
if ( slave - > status ! = SDW_SLAVE_ATTACHED & &
slave - > status ! = SDW_SLAVE_ALERT )
continue ;
2020-05-31 18:18:06 +03:00
/* Identify if Slave(s) are available on Bus */
is_slave = true ;
2020-01-15 03:08:43 +03:00
slave_mode = sdw_get_clk_stop_mode ( slave ) ;
slave - > curr_clk_stop_mode = slave_mode ;
ret = sdw_slave_clk_stop_callback ( slave , slave_mode ,
SDW_CLK_PRE_PREPARE ) ;
if ( ret < 0 ) {
dev_err ( & slave - > dev ,
" pre-prepare failed:%d " , ret ) ;
return ret ;
}
ret = sdw_slave_clk_stop_prepare ( slave ,
slave_mode , true ) ;
if ( ret < 0 ) {
dev_err ( & slave - > dev ,
" pre-prepare failed:%d " , ret ) ;
return ret ;
}
if ( slave_mode = = SDW_CLK_STOP_MODE1 )
simple_clk_stop = false ;
}
if ( is_slave & & ! simple_clk_stop ) {
ret = sdw_bus_wait_for_clk_prep_deprep ( bus ,
SDW_BROADCAST_DEV_NUM ) ;
if ( ret < 0 )
return ret ;
}
2020-05-31 18:18:06 +03:00
/* Don't need to inform slaves if there is no slave attached */
if ( ! is_slave )
return ret ;
2020-01-15 03:08:43 +03:00
/* Inform slaves that prep is done */
list_for_each_entry ( slave , & bus - > slaves , node ) {
if ( ! slave - > dev_num )
continue ;
if ( slave - > status ! = SDW_SLAVE_ATTACHED & &
slave - > status ! = SDW_SLAVE_ALERT )
continue ;
slave_mode = slave - > curr_clk_stop_mode ;
if ( slave_mode = = SDW_CLK_STOP_MODE1 ) {
ret = sdw_slave_clk_stop_callback ( slave ,
slave_mode ,
SDW_CLK_POST_PREPARE ) ;
if ( ret < 0 ) {
dev_err ( & slave - > dev ,
" post-prepare failed:%d " , ret ) ;
}
}
}
return ret ;
}
EXPORT_SYMBOL ( sdw_bus_prep_clk_stop ) ;
/**
* sdw_bus_clk_stop : stop bus clock
*
* @ bus : SDW bus instance
*
* After preparing the Slaves for clock stop , stop the clock by broadcasting
* write to SCP_CTRL register .
*/
int sdw_bus_clk_stop ( struct sdw_bus * bus )
{
int ret ;
/*
* broadcast clock stop now , attached Slaves will ACK this ,
* unattached will ignore
*/
ret = sdw_bwrite_no_pm ( bus , SDW_BROADCAST_DEV_NUM ,
SDW_SCP_CTRL , SDW_SCP_CTRL_CLK_STP_NOW ) ;
if ( ret < 0 ) {
2020-01-15 03:08:44 +03:00
if ( ret = = - ENODATA )
dev_dbg ( bus - > dev ,
" ClockStopNow Broadcast msg ignored %d " , ret ) ;
else
dev_err ( bus - > dev ,
" ClockStopNow Broadcast msg failed %d " , ret ) ;
2020-01-15 03:08:43 +03:00
return ret ;
}
return 0 ;
}
EXPORT_SYMBOL ( sdw_bus_clk_stop ) ;
/**
* sdw_bus_exit_clk_stop : Exit clock stop mode
*
* @ bus : SDW bus instance
*
* This De - prepares the Slaves by exiting Clock Stop Mode 0. For the Slaves
* exiting Clock Stop Mode 1 , they will be de - prepared after they enumerate
* back .
*/
int sdw_bus_exit_clk_stop ( struct sdw_bus * bus )
{
enum sdw_clk_stop_mode mode ;
bool simple_clk_stop = true ;
struct sdw_slave * slave ;
bool is_slave = false ;
int ret ;
/*
* In order to save on transition time , de - prepare
* each Slave and then wait for all Slave ( s ) to be
* de - prepared after clock resume .
*/
list_for_each_entry ( slave , & bus - > slaves , node ) {
if ( ! slave - > dev_num )
continue ;
if ( slave - > status ! = SDW_SLAVE_ATTACHED & &
slave - > status ! = SDW_SLAVE_ALERT )
continue ;
2020-05-31 18:18:06 +03:00
/* Identify if Slave(s) are available on Bus */
is_slave = true ;
2020-01-15 03:08:43 +03:00
mode = slave - > curr_clk_stop_mode ;
if ( mode = = SDW_CLK_STOP_MODE1 ) {
simple_clk_stop = false ;
continue ;
}
ret = sdw_slave_clk_stop_callback ( slave , mode ,
SDW_CLK_PRE_DEPREPARE ) ;
if ( ret < 0 )
dev_warn ( & slave - > dev ,
" clk stop deprep failed:%d " , ret ) ;
ret = sdw_slave_clk_stop_prepare ( slave , mode ,
false ) ;
if ( ret < 0 )
dev_warn ( & slave - > dev ,
" clk stop deprep failed:%d " , ret ) ;
}
if ( is_slave & & ! simple_clk_stop )
sdw_bus_wait_for_clk_prep_deprep ( bus , SDW_BROADCAST_DEV_NUM ) ;
2020-05-31 18:18:06 +03:00
/*
* Don ' t need to call slave callback function if there is no slave
* attached
*/
if ( ! is_slave )
return 0 ;
2020-01-15 03:08:43 +03:00
list_for_each_entry ( slave , & bus - > slaves , node ) {
if ( ! slave - > dev_num )
continue ;
if ( slave - > status ! = SDW_SLAVE_ATTACHED & &
slave - > status ! = SDW_SLAVE_ALERT )
continue ;
mode = slave - > curr_clk_stop_mode ;
sdw_slave_clk_stop_callback ( slave , mode ,
SDW_CLK_POST_DEPREPARE ) ;
}
return 0 ;
}
EXPORT_SYMBOL ( sdw_bus_exit_clk_stop ) ;
2018-04-26 16:08:23 +03:00
int sdw_configure_dpn_intr ( struct sdw_slave * slave ,
2019-05-01 18:57:27 +03:00
int port , bool enable , int mask )
2018-04-26 16:08:23 +03:00
{
u32 addr ;
int ret ;
u8 val = 0 ;
addr = SDW_DPN_INTMASK ( port ) ;
/* Set/Clear port ready interrupt mask */
if ( enable ) {
val | = mask ;
val | = SDW_DPN_INT_PORT_READY ;
} else {
val & = ~ ( mask ) ;
val & = ~ SDW_DPN_INT_PORT_READY ;
}
ret = sdw_update ( slave , addr , ( mask | SDW_DPN_INT_PORT_READY ) , val ) ;
if ( ret < 0 )
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_DPN_INTMASK write failed:%d \n " , val ) ;
2018-04-26 16:08:23 +03:00
return ret ;
}
2020-06-08 23:54:36 +03:00
static int sdw_slave_set_frequency ( struct sdw_slave * slave )
{
u32 mclk_freq = slave - > bus - > prop . mclk_freq ;
u32 curr_freq = slave - > bus - > params . curr_dr_freq > > 1 ;
unsigned int scale ;
u8 scale_index ;
u8 base ;
int ret ;
/*
* frequency base and scale registers are required for SDCA
* devices . They may also be used for 1.2 + / non - SDCA devices ,
* but we will need a DisCo property to cover this case
*/
if ( ! slave - > id . class_id )
return 0 ;
if ( ! mclk_freq ) {
dev_err ( & slave - > dev ,
" no bus MCLK, cannot set SDW_SCP_BUS_CLOCK_BASE \n " ) ;
return - EINVAL ;
}
/*
* map base frequency using Table 89 of SoundWire 1.2 spec .
* The order of the tests just follows the specification , this
* is not a selection between possible values or a search for
* the best value but just a mapping . Only one case per platform
* is relevant .
* Some BIOS have inconsistent values for mclk_freq but a
* correct root so we force the mclk_freq to avoid variations .
*/
if ( ! ( 19200000 % mclk_freq ) ) {
mclk_freq = 19200000 ;
base = SDW_SCP_BASE_CLOCK_19200000_HZ ;
} else if ( ! ( 24000000 % mclk_freq ) ) {
mclk_freq = 24000000 ;
base = SDW_SCP_BASE_CLOCK_24000000_HZ ;
} else if ( ! ( 24576000 % mclk_freq ) ) {
mclk_freq = 24576000 ;
base = SDW_SCP_BASE_CLOCK_24576000_HZ ;
} else if ( ! ( 22579200 % mclk_freq ) ) {
mclk_freq = 22579200 ;
base = SDW_SCP_BASE_CLOCK_22579200_HZ ;
} else if ( ! ( 32000000 % mclk_freq ) ) {
mclk_freq = 32000000 ;
base = SDW_SCP_BASE_CLOCK_32000000_HZ ;
} else {
dev_err ( & slave - > dev ,
" Unsupported clock base, mclk %d \n " ,
mclk_freq ) ;
return - EINVAL ;
}
if ( mclk_freq % curr_freq ) {
dev_err ( & slave - > dev ,
" mclk %d is not multiple of bus curr_freq %d \n " ,
mclk_freq , curr_freq ) ;
return - EINVAL ;
}
scale = mclk_freq / curr_freq ;
/*
* map scale to Table 90 of SoundWire 1.2 spec - and check
* that the scale is a power of two and maximum 64
*/
scale_index = ilog2 ( scale ) ;
if ( BIT ( scale_index ) ! = scale | | scale_index > 6 ) {
dev_err ( & slave - > dev ,
" No match found for scale %d, bus mclk %d curr_freq %d \n " ,
scale , mclk_freq , curr_freq ) ;
return - EINVAL ;
}
scale_index + + ;
ret = sdw_write ( slave , SDW_SCP_BUS_CLOCK_BASE , base ) ;
if ( ret < 0 ) {
dev_err ( & slave - > dev ,
" SDW_SCP_BUS_CLOCK_BASE write failed:%d \n " , ret ) ;
return ret ;
}
/* initialize scale for both banks */
ret = sdw_write ( slave , SDW_SCP_BUSCLOCK_SCALE_B0 , scale_index ) ;
if ( ret < 0 ) {
dev_err ( & slave - > dev ,
" SDW_SCP_BUSCLOCK_SCALE_B0 write failed:%d \n " , ret ) ;
return ret ;
}
ret = sdw_write ( slave , SDW_SCP_BUSCLOCK_SCALE_B1 , scale_index ) ;
if ( ret < 0 )
dev_err ( & slave - > dev ,
" SDW_SCP_BUSCLOCK_SCALE_B1 write failed:%d \n " , ret ) ;
dev_dbg ( & slave - > dev ,
" Configured bus base %d, scale %d, mclk %d, curr_freq %d \n " ,
base , scale_index , mclk_freq , curr_freq ) ;
return ret ;
}
2017-12-14 08:49:39 +03:00
static int sdw_initialize_slave ( struct sdw_slave * slave )
{
struct sdw_slave_prop * prop = & slave - > prop ;
int ret ;
u8 val ;
2020-06-08 23:54:36 +03:00
ret = sdw_slave_set_frequency ( slave ) ;
if ( ret < 0 )
return ret ;
2017-12-14 08:49:39 +03:00
/*
* Set bus clash , parity and SCP implementation
* defined interrupt mask
* TODO : Read implementation defined interrupt mask
* from Slave property
*/
val = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH |
SDW_SCP_INT1_PARITY ;
/* Enable SCP interrupts */
ret = sdw_update ( slave , SDW_SCP_INTMASK1 , val , val ) ;
if ( ret < 0 ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_SCP_INTMASK1 write failed:%d \n " , ret ) ;
2017-12-14 08:49:39 +03:00
return ret ;
}
/* No need to continue if DP0 is not present */
if ( ! slave - > prop . dp0_prop )
return 0 ;
/* Enable DP0 interrupts */
2019-05-22 22:47:25 +03:00
val = prop - > dp0_prop - > imp_def_interrupts ;
2017-12-14 08:49:39 +03:00
val | = SDW_DP0_INT_PORT_READY | SDW_DP0_INT_BRA_FAILURE ;
ret = sdw_update ( slave , SDW_DP0_INTMASK , val , val ) ;
2020-02-28 01:09:49 +03:00
if ( ret < 0 )
2017-12-14 08:49:39 +03:00
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_DP0_INTMASK read failed:%d \n " , ret ) ;
2020-02-28 01:09:49 +03:00
return ret ;
2017-12-14 08:49:39 +03:00
}
2017-12-14 08:49:40 +03:00
static int sdw_handle_dp0_interrupt ( struct sdw_slave * slave , u8 * slave_status )
{
u8 clear = 0 , impl_int_mask ;
int status , status2 , ret , count = 0 ;
status = sdw_read ( slave , SDW_DP0_INT ) ;
if ( status < 0 ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_DP0_INT read failed:%d \n " , status ) ;
2017-12-14 08:49:40 +03:00
return status ;
}
do {
if ( status & SDW_DP0_INT_TEST_FAIL ) {
2019-05-01 18:57:45 +03:00
dev_err ( & slave - > dev , " Test fail for port 0 \n " ) ;
2017-12-14 08:49:40 +03:00
clear | = SDW_DP0_INT_TEST_FAIL ;
}
/*
* Assumption : PORT_READY interrupt will be received only for
* ports implementing Channel Prepare state machine ( CP_SM )
*/
if ( status & SDW_DP0_INT_PORT_READY ) {
complete ( & slave - > port_ready [ 0 ] ) ;
clear | = SDW_DP0_INT_PORT_READY ;
}
if ( status & SDW_DP0_INT_BRA_FAILURE ) {
2019-05-01 18:57:45 +03:00
dev_err ( & slave - > dev , " BRA failed \n " ) ;
2017-12-14 08:49:40 +03:00
clear | = SDW_DP0_INT_BRA_FAILURE ;
}
impl_int_mask = SDW_DP0_INT_IMPDEF1 |
SDW_DP0_INT_IMPDEF2 | SDW_DP0_INT_IMPDEF3 ;
if ( status & impl_int_mask ) {
clear | = impl_int_mask ;
* slave_status = clear ;
}
/* clear the interrupt */
ret = sdw_write ( slave , SDW_DP0_INT , clear ) ;
if ( ret < 0 ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_DP0_INT write failed:%d \n " , ret ) ;
2017-12-14 08:49:40 +03:00
return ret ;
}
/* Read DP0 interrupt again */
status2 = sdw_read ( slave , SDW_DP0_INT ) ;
if ( status2 < 0 ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_DP0_INT read failed:%d \n " , status2 ) ;
2018-01-08 19:52:44 +03:00
return status2 ;
2017-12-14 08:49:40 +03:00
}
status & = status2 ;
count + + ;
/* we can get alerts while processing so keep retrying */
} while ( status ! = 0 & & count < SDW_READ_INTR_CLEAR_RETRY ) ;
if ( count = = SDW_READ_INTR_CLEAR_RETRY )
2019-05-01 18:57:45 +03:00
dev_warn ( slave - > bus - > dev , " Reached MAX_RETRY on DP0 read \n " ) ;
2017-12-14 08:49:40 +03:00
return ret ;
}
static int sdw_handle_port_interrupt ( struct sdw_slave * slave ,
2019-05-01 18:57:27 +03:00
int port , u8 * slave_status )
2017-12-14 08:49:40 +03:00
{
u8 clear = 0 , impl_int_mask ;
int status , status2 , ret , count = 0 ;
u32 addr ;
if ( port = = 0 )
return sdw_handle_dp0_interrupt ( slave , slave_status ) ;
addr = SDW_DPN_INT ( port ) ;
status = sdw_read ( slave , addr ) ;
if ( status < 0 ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_DPN_INT read failed:%d \n " , status ) ;
2017-12-14 08:49:40 +03:00
return status ;
}
do {
if ( status & SDW_DPN_INT_TEST_FAIL ) {
2019-05-01 18:57:45 +03:00
dev_err ( & slave - > dev , " Test fail for port:%d \n " , port ) ;
2017-12-14 08:49:40 +03:00
clear | = SDW_DPN_INT_TEST_FAIL ;
}
/*
* Assumption : PORT_READY interrupt will be received only
* for ports implementing CP_SM .
*/
if ( status & SDW_DPN_INT_PORT_READY ) {
complete ( & slave - > port_ready [ port ] ) ;
clear | = SDW_DPN_INT_PORT_READY ;
}
impl_int_mask = SDW_DPN_INT_IMPDEF1 |
SDW_DPN_INT_IMPDEF2 | SDW_DPN_INT_IMPDEF3 ;
if ( status & impl_int_mask ) {
clear | = impl_int_mask ;
* slave_status = clear ;
}
/* clear the interrupt */
ret = sdw_write ( slave , addr , clear ) ;
if ( ret < 0 ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_DPN_INT write failed:%d \n " , ret ) ;
2017-12-14 08:49:40 +03:00
return ret ;
}
/* Read DPN interrupt again */
status2 = sdw_read ( slave , addr ) ;
2018-01-08 19:52:44 +03:00
if ( status2 < 0 ) {
2017-12-14 08:49:40 +03:00
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_DPN_INT read failed:%d \n " , status2 ) ;
2018-01-08 19:52:44 +03:00
return status2 ;
2017-12-14 08:49:40 +03:00
}
status & = status2 ;
count + + ;
/* we can get alerts while processing so keep retrying */
} while ( status ! = 0 & & count < SDW_READ_INTR_CLEAR_RETRY ) ;
if ( count = = SDW_READ_INTR_CLEAR_RETRY )
dev_warn ( slave - > bus - > dev , " Reached MAX_RETRY on port read " ) ;
return ret ;
}
static int sdw_handle_slave_alerts ( struct sdw_slave * slave )
{
struct sdw_slave_intr_status slave_intr ;
2019-08-29 21:11:35 +03:00
u8 clear = 0 , bit , port_status [ 15 ] = { 0 } ;
2017-12-14 08:49:40 +03:00
int port_num , stat , ret , count = 0 ;
unsigned long port ;
bool slave_notify = false ;
u8 buf , buf2 [ 2 ] , _buf , _buf2 [ 2 ] ;
sdw_modify_slave_status ( slave , SDW_SLAVE_ALERT ) ;
2020-01-15 03:08:42 +03:00
ret = pm_runtime_get_sync ( & slave - > dev ) ;
if ( ret < 0 & & ret ! = - EACCES ) {
dev_err ( & slave - > dev , " Failed to resume device: %d \n " , ret ) ;
pm_runtime_put_noidle ( slave - > bus - > dev ) ;
return ret ;
}
2020-08-18 01:09:33 +03:00
/* Read Intstat 1, Intstat 2 and Intstat 3 registers */
2019-05-02 13:59:26 +03:00
ret = sdw_read ( slave , SDW_SCP_INT1 ) ;
2017-12-14 08:49:40 +03:00
if ( ret < 0 ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_SCP_INT1 read failed:%d \n " , ret ) ;
2020-01-15 03:08:42 +03:00
goto io_err ;
2017-12-14 08:49:40 +03:00
}
2019-05-02 13:59:26 +03:00
buf = ret ;
2017-12-14 08:49:40 +03:00
ret = sdw_nread ( slave , SDW_SCP_INTSTAT2 , 2 , buf2 ) ;
if ( ret < 0 ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_SCP_INT2/3 read failed:%d \n " , ret ) ;
2020-01-15 03:08:42 +03:00
goto io_err ;
2017-12-14 08:49:40 +03:00
}
do {
/*
* Check parity , bus clash and Slave ( impl defined )
* interrupt
*/
if ( buf & SDW_SCP_INT1_PARITY ) {
2019-05-01 18:57:45 +03:00
dev_err ( & slave - > dev , " Parity error detected \n " ) ;
2017-12-14 08:49:40 +03:00
clear | = SDW_SCP_INT1_PARITY ;
}
if ( buf & SDW_SCP_INT1_BUS_CLASH ) {
2019-05-01 18:57:45 +03:00
dev_err ( & slave - > dev , " Bus clash error detected \n " ) ;
2017-12-14 08:49:40 +03:00
clear | = SDW_SCP_INT1_BUS_CLASH ;
}
/*
* When bus clash or parity errors are detected , such errors
* are unlikely to be recoverable errors .
* TODO : In such scenario , reset bus . Make this configurable
* via sysfs property with bus reset being the default .
*/
if ( buf & SDW_SCP_INT1_IMPL_DEF ) {
dev_dbg ( & slave - > dev , " Slave impl defined interrupt \n " ) ;
clear | = SDW_SCP_INT1_IMPL_DEF ;
slave_notify = true ;
}
/* Check port 0 - 3 interrupts */
port = buf & SDW_SCP_INT1_PORT0_3 ;
/* To get port number corresponding to bits, shift it */
port = port > > SDW_REG_SHIFT ( SDW_SCP_INT1_PORT0_3 ) ;
for_each_set_bit ( bit , & port , 8 ) {
sdw_handle_port_interrupt ( slave , bit ,
2019-05-01 18:57:27 +03:00
& port_status [ bit ] ) ;
2017-12-14 08:49:40 +03:00
}
/* Check if cascade 2 interrupt is present */
if ( buf & SDW_SCP_INT1_SCP2_CASCADE ) {
port = buf2 [ 0 ] & SDW_SCP_INTSTAT2_PORT4_10 ;
for_each_set_bit ( bit , & port , 8 ) {
/* scp2 ports start from 4 */
port_num = bit + 3 ;
sdw_handle_port_interrupt ( slave ,
port_num ,
& port_status [ port_num ] ) ;
}
}
/* now check last cascade */
if ( buf2 [ 0 ] & SDW_SCP_INTSTAT2_SCP3_CASCADE ) {
port = buf2 [ 1 ] & SDW_SCP_INTSTAT3_PORT11_14 ;
for_each_set_bit ( bit , & port , 8 ) {
/* scp3 ports start from 11 */
port_num = bit + 10 ;
sdw_handle_port_interrupt ( slave ,
port_num ,
& port_status [ port_num ] ) ;
}
}
/* Update the Slave driver */
2019-05-01 18:57:29 +03:00
if ( slave_notify & & slave - > ops & &
slave - > ops - > interrupt_callback ) {
2017-12-14 08:49:40 +03:00
slave_intr . control_port = clear ;
memcpy ( slave_intr . port , & port_status ,
2019-05-01 18:57:27 +03:00
sizeof ( slave_intr . port ) ) ;
2017-12-14 08:49:40 +03:00
slave - > ops - > interrupt_callback ( slave , & slave_intr ) ;
}
/* Ack interrupt */
ret = sdw_write ( slave , SDW_SCP_INT1 , clear ) ;
if ( ret < 0 ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_SCP_INT1 write failed:%d \n " , ret ) ;
2020-01-15 03:08:42 +03:00
goto io_err ;
2017-12-14 08:49:40 +03:00
}
/*
* Read status again to ensure no new interrupts arrived
* while servicing interrupts .
*/
2019-05-02 13:59:26 +03:00
ret = sdw_read ( slave , SDW_SCP_INT1 ) ;
2017-12-14 08:49:40 +03:00
if ( ret < 0 ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_SCP_INT1 read failed:%d \n " , ret ) ;
2020-01-15 03:08:42 +03:00
goto io_err ;
2017-12-14 08:49:40 +03:00
}
2019-05-02 13:59:26 +03:00
_buf = ret ;
2017-12-14 08:49:40 +03:00
ret = sdw_nread ( slave , SDW_SCP_INTSTAT2 , 2 , _buf2 ) ;
if ( ret < 0 ) {
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" SDW_SCP_INT2/3 read failed:%d \n " , ret ) ;
2020-01-15 03:08:42 +03:00
goto io_err ;
2017-12-14 08:49:40 +03:00
}
/* Make sure no interrupts are pending */
buf & = _buf ;
buf2 [ 0 ] & = _buf2 [ 0 ] ;
buf2 [ 1 ] & = _buf2 [ 1 ] ;
stat = buf | | buf2 [ 0 ] | | buf2 [ 1 ] ;
/*
* Exit loop if Slave is continuously in ALERT state even
* after servicing the interrupt multiple times .
*/
count + + ;
/* we can get alerts while processing so keep retrying */
} while ( stat ! = 0 & & count < SDW_READ_INTR_CLEAR_RETRY ) ;
if ( count = = SDW_READ_INTR_CLEAR_RETRY )
2019-05-01 18:57:45 +03:00
dev_warn ( slave - > bus - > dev , " Reached MAX_RETRY on alert read \n " ) ;
2017-12-14 08:49:40 +03:00
2020-01-15 03:08:42 +03:00
io_err :
pm_runtime_mark_last_busy ( & slave - > dev ) ;
pm_runtime_put_autosuspend ( & slave - > dev ) ;
2017-12-14 08:49:40 +03:00
return ret ;
}
static int sdw_update_slave_status ( struct sdw_slave * slave ,
2019-05-01 18:57:27 +03:00
enum sdw_slave_status status )
2017-12-14 08:49:40 +03:00
{
2020-01-15 03:08:35 +03:00
unsigned long time ;
2017-12-14 08:49:40 +03:00
2020-01-15 03:08:35 +03:00
if ( ! slave - > probed ) {
/*
* the slave status update is typically handled in an
* interrupt thread , which can race with the driver
* probe , e . g . when a module needs to be loaded .
*
* make sure the probe is complete before updating
* status .
*/
time = wait_for_completion_timeout ( & slave - > probe_complete ,
msecs_to_jiffies ( DEFAULT_PROBE_TIMEOUT ) ) ;
if ( ! time ) {
dev_err ( & slave - > dev , " Probe not complete, timed out \n " ) ;
return - ETIMEDOUT ;
}
}
if ( ! slave - > ops | | ! slave - > ops - > update_status )
return 0 ;
return slave - > ops - > update_status ( slave , status ) ;
2017-12-14 08:49:40 +03:00
}
/**
* sdw_handle_slave_status ( ) - Handle Slave status
* @ bus : SDW bus instance
* @ status : Status for all Slave ( s )
*/
int sdw_handle_slave_status ( struct sdw_bus * bus ,
2019-05-01 18:57:27 +03:00
enum sdw_slave_status status [ ] )
2017-12-14 08:49:40 +03:00
{
enum sdw_slave_status prev_status ;
struct sdw_slave * slave ;
2020-01-15 03:08:37 +03:00
bool attached_initializing ;
2017-12-14 08:49:40 +03:00
int i , ret = 0 ;
2020-01-11 00:57:31 +03:00
/* first check if any Slaves fell off the bus */
for ( i = 1 ; i < = SDW_MAX_DEVICES ; i + + ) {
mutex_lock ( & bus - > bus_lock ) ;
if ( test_bit ( i , bus - > assigned ) = = false ) {
mutex_unlock ( & bus - > bus_lock ) ;
continue ;
}
mutex_unlock ( & bus - > bus_lock ) ;
slave = sdw_get_slave ( bus , i ) ;
if ( ! slave )
continue ;
if ( status [ i ] = = SDW_SLAVE_UNATTACHED & &
slave - > status ! = SDW_SLAVE_UNATTACHED )
sdw_modify_slave_status ( slave , SDW_SLAVE_UNATTACHED ) ;
}
2017-12-14 08:49:40 +03:00
if ( status [ 0 ] = = SDW_SLAVE_ATTACHED ) {
2019-08-06 03:55:09 +03:00
dev_dbg ( bus - > dev , " Slave attached, programming device number \n " ) ;
2017-12-14 08:49:40 +03:00
ret = sdw_program_device_num ( bus ) ;
if ( ret )
2019-05-01 18:57:45 +03:00
dev_err ( bus - > dev , " Slave attach failed: %d \n " , ret ) ;
2019-07-26 02:40:10 +03:00
/*
* programming a device number will have side effects ,
* so we deal with other devices at a later time
*/
return ret ;
2017-12-14 08:49:40 +03:00
}
/* Continue to check other slave statuses */
for ( i = 1 ; i < = SDW_MAX_DEVICES ; i + + ) {
mutex_lock ( & bus - > bus_lock ) ;
if ( test_bit ( i , bus - > assigned ) = = false ) {
mutex_unlock ( & bus - > bus_lock ) ;
continue ;
}
mutex_unlock ( & bus - > bus_lock ) ;
slave = sdw_get_slave ( bus , i ) ;
if ( ! slave )
continue ;
2020-01-15 03:08:37 +03:00
attached_initializing = false ;
2017-12-14 08:49:40 +03:00
switch ( status [ i ] ) {
case SDW_SLAVE_UNATTACHED :
if ( slave - > status = = SDW_SLAVE_UNATTACHED )
break ;
sdw_modify_slave_status ( slave , SDW_SLAVE_UNATTACHED ) ;
break ;
case SDW_SLAVE_ALERT :
ret = sdw_handle_slave_alerts ( slave ) ;
if ( ret )
dev_err ( bus - > dev ,
2019-05-01 18:57:45 +03:00
" Slave %d alert handling failed: %d \n " ,
2017-12-14 08:49:40 +03:00
i , ret ) ;
break ;
case SDW_SLAVE_ATTACHED :
if ( slave - > status = = SDW_SLAVE_ATTACHED )
break ;
prev_status = slave - > status ;
sdw_modify_slave_status ( slave , SDW_SLAVE_ATTACHED ) ;
if ( prev_status = = SDW_SLAVE_ALERT )
break ;
2020-01-15 03:08:37 +03:00
attached_initializing = true ;
2017-12-14 08:49:40 +03:00
ret = sdw_initialize_slave ( slave ) ;
if ( ret )
dev_err ( bus - > dev ,
2019-05-01 18:57:45 +03:00
" Slave %d initialization failed: %d \n " ,
2017-12-14 08:49:40 +03:00
i , ret ) ;
break ;
default :
2019-05-01 18:57:45 +03:00
dev_err ( bus - > dev , " Invalid slave %d status:%d \n " ,
2019-05-01 18:57:27 +03:00
i , status [ i ] ) ;
2017-12-14 08:49:40 +03:00
break ;
}
ret = sdw_update_slave_status ( slave , status [ i ] ) ;
if ( ret )
dev_err ( slave - > bus - > dev ,
2019-05-01 18:57:45 +03:00
" Update Slave status failed:%d \n " , ret ) ;
2020-01-15 03:08:37 +03:00
if ( attached_initializing )
complete ( & slave - > initialization_complete ) ;
2017-12-14 08:49:40 +03:00
}
return ret ;
}
EXPORT_SYMBOL ( sdw_handle_slave_status ) ;
2020-01-15 03:08:40 +03:00
void sdw_clear_slave_status ( struct sdw_bus * bus , u32 request )
{
struct sdw_slave * slave ;
int i ;
/* Check all non-zero devices */
for ( i = 1 ; i < = SDW_MAX_DEVICES ; i + + ) {
mutex_lock ( & bus - > bus_lock ) ;
if ( test_bit ( i , bus - > assigned ) = = false ) {
mutex_unlock ( & bus - > bus_lock ) ;
continue ;
}
mutex_unlock ( & bus - > bus_lock ) ;
slave = sdw_get_slave ( bus , i ) ;
if ( ! slave )
continue ;
if ( slave - > status ! = SDW_SLAVE_UNATTACHED )
sdw_modify_slave_status ( slave , SDW_SLAVE_UNATTACHED ) ;
/* keep track of request, used in pm_runtime resume */
slave - > unattach_request = request ;
}
}
EXPORT_SYMBOL ( sdw_clear_slave_status ) ;