2017-11-07 16:58:41 +03:00
// SPDX-License-Identifier: GPL-2.0
2014-10-02 06:54:11 +04:00
/*
2014-12-20 01:56:31 +03:00
* Greybus interface code
2014-10-02 06:54:11 +04:00
*
* Copyright 2014 Google Inc .
2014-12-12 21:08:42 +03:00
* Copyright 2014 Linaro Ltd .
2014-10-02 06:54:11 +04:00
*/
2016-07-14 23:13:00 +03:00
# include <linux/delay.h>
2019-08-25 08:54:27 +03:00
# include <linux/greybus.h>
2016-07-14 23:13:00 +03:00
2016-05-24 07:05:32 +03:00
# include "greybus_trace.h"
2016-03-30 01:56:00 +03:00
2016-05-30 10:35:10 +03:00
# define GB_INTERFACE_MODE_SWITCH_TIMEOUT 2000
2016-05-27 18:26:40 +03:00
2016-03-30 01:56:06 +03:00
# define GB_INTERFACE_DEVICE_ID_BAD 0xff
2016-07-14 23:13:00 +03:00
# define GB_INTERFACE_AUTOSUSPEND_MS 3000
/* Time required for interface to enter standby before disabling REFCLK */
# define GB_INTERFACE_SUSPEND_HIBERNATE_DELAY_MS 20
2016-03-30 01:56:11 +03:00
/* Don't-care selector index */
# define DME_SELECTOR_INDEX_NULL 0
2016-03-30 01:56:08 +03:00
/* DME attributes */
2016-03-30 01:56:11 +03:00
/* FIXME: remove ES2 support and DME_T_TST_SRC_INCREMENT */
# define DME_T_TST_SRC_INCREMENT 0x4083
2016-03-30 01:56:08 +03:00
# define DME_DDBL1_MANUFACTURERID 0x5003
# define DME_DDBL1_PRODUCTID 0x5004
2016-07-28 12:40:53 +03:00
# define DME_TOSHIBA_GMP_VID 0x6000
# define DME_TOSHIBA_GMP_PID 0x6001
# define DME_TOSHIBA_GMP_SN0 0x6002
# define DME_TOSHIBA_GMP_SN1 0x6003
# define DME_TOSHIBA_GMP_INIT_STATUS 0x6101
2016-03-30 01:56:08 +03:00
/* DDBL1 Manufacturer and Product ids */
# define TOSHIBA_DMID 0x0126
# define TOSHIBA_ES2_BRIDGE_DPID 0x1000
# define TOSHIBA_ES3_APBRIDGE_DPID 0x1001
2016-05-19 18:52:39 +03:00
# define TOSHIBA_ES3_GBPHY_DPID 0x1002
2016-03-30 01:56:08 +03:00
2016-07-14 23:13:00 +03:00
static int gb_interface_hibernate_link ( struct gb_interface * intf ) ;
static int gb_interface_refclk_set ( struct gb_interface * intf , bool enable ) ;
2016-03-30 01:56:08 +03:00
static int gb_interface_dme_attr_get ( struct gb_interface * intf ,
2017-07-23 20:51:46 +03:00
u16 attr , u32 * val )
2016-03-30 01:56:08 +03:00
{
return gb_svc_dme_peer_get ( intf - > hd - > svc , intf - > interface_id ,
2016-03-30 01:56:11 +03:00
attr , DME_SELECTOR_INDEX_NULL , val ) ;
2016-03-30 01:56:08 +03:00
}
static int gb_interface_read_ara_dme ( struct gb_interface * intf )
{
2016-03-30 01:56:12 +03:00
u32 sn0 , sn1 ;
2016-03-30 01:56:08 +03:00
int ret ;
/*
* Unless this is a Toshiba bridge , bail out until we have defined
2016-07-28 12:40:53 +03:00
* standard GMP attributes .
2016-03-30 01:56:08 +03:00
*/
if ( intf - > ddbl1_manufacturer_id ! = TOSHIBA_DMID ) {
dev_err ( & intf - > dev , " unknown manufacturer %08x \n " ,
2017-07-23 20:51:46 +03:00
intf - > ddbl1_manufacturer_id ) ;
2016-03-30 01:56:08 +03:00
return - ENODEV ;
}
2016-07-28 12:40:53 +03:00
ret = gb_interface_dme_attr_get ( intf , DME_TOSHIBA_GMP_VID ,
2016-03-30 01:56:08 +03:00
& intf - > vendor_id ) ;
if ( ret )
return ret ;
2016-07-28 12:40:53 +03:00
ret = gb_interface_dme_attr_get ( intf , DME_TOSHIBA_GMP_PID ,
2016-03-30 01:56:08 +03:00
& intf - > product_id ) ;
if ( ret )
return ret ;
2016-07-28 12:40:53 +03:00
ret = gb_interface_dme_attr_get ( intf , DME_TOSHIBA_GMP_SN0 , & sn0 ) ;
2016-03-30 01:56:12 +03:00
if ( ret )
return ret ;
2016-07-28 12:40:53 +03:00
ret = gb_interface_dme_attr_get ( intf , DME_TOSHIBA_GMP_SN1 , & sn1 ) ;
2016-03-30 01:56:12 +03:00
if ( ret )
return ret ;
intf - > serial_number = ( u64 ) sn1 < < 32 | sn0 ;
2016-03-30 01:56:08 +03:00
return 0 ;
}
static int gb_interface_read_dme ( struct gb_interface * intf )
{
int ret ;
2016-07-20 17:40:21 +03:00
/* DME attributes have already been read */
if ( intf - > dme_read )
return 0 ;
2016-03-30 01:56:08 +03:00
ret = gb_interface_dme_attr_get ( intf , DME_DDBL1_MANUFACTURERID ,
& intf - > ddbl1_manufacturer_id ) ;
if ( ret )
return ret ;
ret = gb_interface_dme_attr_get ( intf , DME_DDBL1_PRODUCTID ,
& intf - > ddbl1_product_id ) ;
if ( ret )
return ret ;
2016-03-30 01:56:09 +03:00
if ( intf - > ddbl1_manufacturer_id = = TOSHIBA_DMID & &
2017-07-23 20:51:46 +03:00
intf - > ddbl1_product_id = = TOSHIBA_ES2_BRIDGE_DPID ) {
2016-07-28 12:40:53 +03:00
intf - > quirks | = GB_INTERFACE_QUIRK_NO_GMP_IDS ;
2016-03-30 01:56:09 +03:00
intf - > quirks | = GB_INTERFACE_QUIRK_NO_INIT_STATUS ;
}
2016-07-20 17:40:21 +03:00
ret = gb_interface_read_ara_dme ( intf ) ;
if ( ret )
return ret ;
intf - > dme_read = true ;
return 0 ;
2016-03-30 01:56:08 +03:00
}
2016-03-30 01:56:06 +03:00
2016-03-30 01:56:04 +03:00
static int gb_interface_route_create ( struct gb_interface * intf )
{
struct gb_svc * svc = intf - > hd - > svc ;
u8 intf_id = intf - > interface_id ;
u8 device_id ;
int ret ;
2016-03-30 01:56:06 +03:00
/* Allocate an interface device id. */
2016-03-30 01:56:04 +03:00
ret = ida_simple_get ( & svc - > device_id_map ,
2016-03-30 01:56:06 +03:00
GB_SVC_DEVICE_ID_MIN , GB_SVC_DEVICE_ID_MAX + 1 ,
GFP_KERNEL ) ;
2016-03-30 01:56:04 +03:00
if ( ret < 0 ) {
dev_err ( & intf - > dev , " failed to allocate device id: %d \n " , ret ) ;
return ret ;
}
device_id = ret ;
ret = gb_svc_intf_device_id ( svc , intf_id , device_id ) ;
if ( ret ) {
dev_err ( & intf - > dev , " failed to set device id %u: %d \n " ,
2017-07-23 20:51:46 +03:00
device_id , ret ) ;
2016-03-30 01:56:04 +03:00
goto err_ida_remove ;
}
2016-03-30 01:56:06 +03:00
/* FIXME: Hard-coded AP device id. */
ret = gb_svc_route_create ( svc , svc - > ap_intf_id , GB_SVC_DEVICE_ID_AP ,
2016-03-30 01:56:04 +03:00
intf_id , device_id ) ;
if ( ret ) {
dev_err ( & intf - > dev , " failed to create route: %d \n " , ret ) ;
goto err_svc_id_free ;
}
intf - > device_id = device_id ;
return 0 ;
err_svc_id_free :
/*
* XXX Should we tell SVC that this id doesn ' t belong to interface
* XXX anymore .
*/
err_ida_remove :
ida_simple_remove ( & svc - > device_id_map , device_id ) ;
return ret ;
}
static void gb_interface_route_destroy ( struct gb_interface * intf )
{
struct gb_svc * svc = intf - > hd - > svc ;
2016-03-30 01:56:06 +03:00
if ( intf - > device_id = = GB_INTERFACE_DEVICE_ID_BAD )
2016-03-30 01:56:04 +03:00
return ;
gb_svc_route_destroy ( svc , svc - > ap_intf_id , intf - > interface_id ) ;
ida_simple_remove ( & svc - > device_id_map , intf - > device_id ) ;
2016-03-30 01:56:06 +03:00
intf - > device_id = GB_INTERFACE_DEVICE_ID_BAD ;
2016-03-30 01:56:04 +03:00
}
2016-05-27 18:26:40 +03:00
/* Locking: Caller holds the interface mutex. */
static int gb_interface_legacy_mode_switch ( struct gb_interface * intf )
{
int ret ;
dev_info ( & intf - > dev , " legacy mode switch detected \n " ) ;
/* Mark as disconnected to prevent I/O during disable. */
intf - > disconnected = true ;
gb_interface_disable ( intf ) ;
intf - > disconnected = false ;
ret = gb_interface_enable ( intf ) ;
if ( ret ) {
dev_err ( & intf - > dev , " failed to re-enable interface: %d \n " , ret ) ;
gb_interface_deactivate ( intf ) ;
}
return ret ;
}
void gb_interface_mailbox_event ( struct gb_interface * intf , u16 result ,
2017-07-23 20:51:46 +03:00
u32 mailbox )
2016-05-27 18:26:40 +03:00
{
mutex_lock ( & intf - > mutex ) ;
if ( result ) {
dev_warn ( & intf - > dev ,
2017-07-23 20:51:46 +03:00
" mailbox event with UniPro error: 0x%04x \n " ,
result ) ;
2016-05-27 18:26:40 +03:00
goto err_disable ;
}
if ( mailbox ! = GB_SVC_INTF_MAILBOX_GREYBUS ) {
dev_warn ( & intf - > dev ,
2017-07-23 20:51:46 +03:00
" mailbox event with unexpected value: 0x%08x \n " ,
mailbox ) ;
2016-05-27 18:26:40 +03:00
goto err_disable ;
}
if ( intf - > quirks & GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH ) {
gb_interface_legacy_mode_switch ( intf ) ;
goto out_unlock ;
}
if ( ! intf - > mode_switch ) {
dev_warn ( & intf - > dev , " unexpected mailbox event: 0x%08x \n " ,
2017-07-23 20:51:46 +03:00
mailbox ) ;
2016-05-27 18:26:40 +03:00
goto err_disable ;
}
dev_info ( & intf - > dev , " mode switch detected \n " ) ;
complete ( & intf - > mode_switch_completion ) ;
out_unlock :
mutex_unlock ( & intf - > mutex ) ;
return ;
err_disable :
gb_interface_disable ( intf ) ;
gb_interface_deactivate ( intf ) ;
mutex_unlock ( & intf - > mutex ) ;
}
static void gb_interface_mode_switch_work ( struct work_struct * work )
{
struct gb_interface * intf ;
struct gb_control * control ;
unsigned long timeout ;
int ret ;
intf = container_of ( work , struct gb_interface , mode_switch_work ) ;
mutex_lock ( & intf - > mutex ) ;
/* Make sure interface is still enabled. */
if ( ! intf - > enabled ) {
dev_dbg ( & intf - > dev , " mode switch aborted \n " ) ;
intf - > mode_switch = false ;
mutex_unlock ( & intf - > mutex ) ;
goto out_interface_put ;
}
/*
* Prepare the control device for mode switch and make sure to get an
* extra reference before it goes away during interface disable .
*/
control = gb_control_get ( intf - > control ) ;
gb_control_mode_switch_prepare ( control ) ;
gb_interface_disable ( intf ) ;
mutex_unlock ( & intf - > mutex ) ;
timeout = msecs_to_jiffies ( GB_INTERFACE_MODE_SWITCH_TIMEOUT ) ;
ret = wait_for_completion_interruptible_timeout (
& intf - > mode_switch_completion , timeout ) ;
/* Finalise control-connection mode switch. */
gb_control_mode_switch_complete ( control ) ;
gb_control_put ( control ) ;
if ( ret < 0 ) {
dev_err ( & intf - > dev , " mode switch interrupted \n " ) ;
goto err_deactivate ;
} else if ( ret = = 0 ) {
dev_err ( & intf - > dev , " mode switch timed out \n " ) ;
goto err_deactivate ;
}
/* Re-enable (re-enumerate) interface if still active. */
mutex_lock ( & intf - > mutex ) ;
intf - > mode_switch = false ;
if ( intf - > active ) {
ret = gb_interface_enable ( intf ) ;
if ( ret ) {
dev_err ( & intf - > dev , " failed to re-enable interface: %d \n " ,
2017-07-23 20:51:46 +03:00
ret ) ;
2016-05-27 18:26:40 +03:00
gb_interface_deactivate ( intf ) ;
}
}
mutex_unlock ( & intf - > mutex ) ;
out_interface_put :
gb_interface_put ( intf ) ;
return ;
err_deactivate :
mutex_lock ( & intf - > mutex ) ;
intf - > mode_switch = false ;
gb_interface_deactivate ( intf ) ;
mutex_unlock ( & intf - > mutex ) ;
gb_interface_put ( intf ) ;
}
int gb_interface_request_mode_switch ( struct gb_interface * intf )
{
int ret = 0 ;
mutex_lock ( & intf - > mutex ) ;
if ( intf - > mode_switch ) {
ret = - EBUSY ;
goto out_unlock ;
}
intf - > mode_switch = true ;
reinit_completion ( & intf - > mode_switch_completion ) ;
/*
* Get a reference to the interface device , which will be put once the
* mode switch is complete .
*/
get_device ( & intf - > dev ) ;
if ( ! queue_work ( system_long_wq , & intf - > mode_switch_work ) ) {
put_device ( & intf - > dev ) ;
ret = - EBUSY ;
goto out_unlock ;
}
out_unlock :
mutex_unlock ( & intf - > mutex ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( gb_interface_request_mode_switch ) ;
2016-03-30 01:56:00 +03:00
/*
2016-03-30 01:56:02 +03:00
* T_TstSrcIncrement is written by the module on ES2 as a stand - in for the
2016-03-30 01:56:11 +03:00
* init - status attribute DME_TOSHIBA_INIT_STATUS . The AP needs to read and
* clear it after reading a non - zero value from it .
2016-03-30 01:56:00 +03:00
*
* FIXME : This is module - hardware dependent and needs to be extended for every
* type of module we want to support .
*/
2016-03-30 01:56:02 +03:00
static int gb_interface_read_and_clear_init_status ( struct gb_interface * intf )
2016-03-30 01:56:00 +03:00
{
struct gb_host_device * hd = intf - > hd ;
2016-05-27 18:26:23 +03:00
unsigned long bootrom_quirks ;
2016-07-26 23:41:04 +03:00
unsigned long s2l_quirks ;
2016-03-30 01:56:00 +03:00
int ret ;
u32 value ;
u16 attr ;
u8 init_status ;
/*
2016-03-30 01:56:02 +03:00
* ES2 bridges use T_TstSrcIncrement for the init status .
*
* FIXME : Remove ES2 support
2016-03-30 01:56:00 +03:00
*/
2016-03-30 01:56:09 +03:00
if ( intf - > quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS )
2016-03-30 01:56:11 +03:00
attr = DME_T_TST_SRC_INCREMENT ;
2016-03-30 01:56:00 +03:00
else
2016-07-28 12:40:53 +03:00
attr = DME_TOSHIBA_GMP_INIT_STATUS ;
2016-03-30 01:56:00 +03:00
ret = gb_svc_dme_peer_get ( hd - > svc , intf - > interface_id , attr ,
2016-03-30 01:56:11 +03:00
DME_SELECTOR_INDEX_NULL , & value ) ;
2016-03-30 01:56:00 +03:00
if ( ret )
return ret ;
/*
2016-03-30 01:56:02 +03:00
* A nonzero init status indicates the module has finished
* initializing .
2016-03-30 01:56:00 +03:00
*/
if ( ! value ) {
2016-03-30 01:56:02 +03:00
dev_err ( & intf - > dev , " invalid init status \n " ) ;
2016-03-30 01:56:00 +03:00
return - ENODEV ;
}
/*
2016-03-30 01:56:03 +03:00
* Extract the init status .
2016-03-30 01:56:02 +03:00
*
2016-03-30 01:56:00 +03:00
* For ES2 : We need to check lowest 8 bits of ' value ' .
* For ES3 : We need to check highest 8 bits out of 32 of ' value ' .
2016-03-30 01:56:02 +03:00
*
* FIXME : Remove ES2 support
2016-03-30 01:56:00 +03:00
*/
2016-03-30 01:56:09 +03:00
if ( intf - > quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS )
2016-03-30 01:56:01 +03:00
init_status = value & 0xff ;
2016-03-30 01:56:00 +03:00
else
init_status = value > > 24 ;
2016-03-30 01:56:03 +03:00
/*
2016-05-27 18:26:23 +03:00
* Check if the interface is executing the quirky ES3 bootrom that ,
* for example , requires E2EFC , CSD and CSV to be disabled .
2016-03-30 01:56:03 +03:00
*/
2016-05-27 18:26:24 +03:00
bootrom_quirks = GB_INTERFACE_QUIRK_NO_CPORT_FEATURES |
2016-05-27 18:26:40 +03:00
GB_INTERFACE_QUIRK_FORCED_DISABLE |
2016-07-21 15:24:11 +03:00
GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH |
2016-07-26 23:41:03 +03:00
GB_INTERFACE_QUIRK_NO_BUNDLE_ACTIVATE ;
2016-07-26 23:41:04 +03:00
s2l_quirks = GB_INTERFACE_QUIRK_NO_PM ;
2016-03-30 01:56:03 +03:00
switch ( init_status ) {
2016-03-30 01:56:11 +03:00
case GB_INIT_BOOTROM_UNIPRO_BOOT_STARTED :
case GB_INIT_BOOTROM_FALLBACK_UNIPRO_BOOT_STARTED :
2016-05-27 18:26:23 +03:00
intf - > quirks | = bootrom_quirks ;
2016-03-30 01:56:03 +03:00
break ;
2016-07-26 23:41:04 +03:00
case GB_INIT_S2_LOADER_BOOT_STARTED :
/* S2 Loader doesn't support runtime PM */
intf - > quirks & = ~ bootrom_quirks ;
intf - > quirks | = s2l_quirks ;
break ;
2016-04-28 17:19:39 +03:00
default :
2016-05-27 18:26:23 +03:00
intf - > quirks & = ~ bootrom_quirks ;
2016-07-26 23:41:04 +03:00
intf - > quirks & = ~ s2l_quirks ;
2016-03-30 01:56:03 +03:00
}
2016-03-30 01:56:00 +03:00
2016-03-30 01:56:02 +03:00
/* Clear the init status. */
2016-03-30 01:56:00 +03:00
return gb_svc_dme_peer_set ( hd - > svc , intf - > interface_id , attr ,
2016-03-30 01:56:11 +03:00
DME_SELECTOR_INDEX_NULL , 0 ) ;
2016-03-30 01:56:00 +03:00
}
2014-12-20 01:56:31 +03:00
/* interface sysfs attributes */
# define gb_interface_attr(field, type) \
static ssize_t field # # _show ( struct device * dev , \
struct device_attribute * attr , \
char * buf ) \
2014-12-12 01:10:59 +03:00
{ \
2014-12-20 01:56:31 +03:00
struct gb_interface * intf = to_gb_interface ( dev ) ; \
2015-12-18 12:34:27 +03:00
return scnprintf ( buf , PAGE_SIZE , type " \n " , intf - > field ) ; \
2014-12-12 01:10:59 +03:00
} \
static DEVICE_ATTR_RO ( field )
2015-12-22 19:34:34 +03:00
gb_interface_attr ( ddbl1_manufacturer_id , " 0x%08x " ) ;
gb_interface_attr ( ddbl1_product_id , " 0x%08x " ) ;
2015-12-18 12:34:27 +03:00
gb_interface_attr ( interface_id , " %u " ) ;
2016-02-27 08:54:38 +03:00
gb_interface_attr ( vendor_id , " 0x%08x " ) ;
gb_interface_attr ( product_id , " 0x%08x " ) ;
2015-12-28 09:29:00 +03:00
gb_interface_attr ( serial_number , " 0x%016llx " ) ;
2014-12-12 01:10:59 +03:00
2016-04-08 06:15:30 +03:00
static ssize_t voltage_now_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct gb_interface * intf = to_gb_interface ( dev ) ;
int ret ;
u32 measurement ;
ret = gb_svc_pwrmon_intf_sample_get ( intf - > hd - > svc , intf - > interface_id ,
GB_SVC_PWRMON_TYPE_VOL ,
& measurement ) ;
if ( ret ) {
dev_err ( & intf - > dev , " failed to get voltage sample (%d) \n " , ret ) ;
return ret ;
}
return sprintf ( buf , " %u \n " , measurement ) ;
}
static DEVICE_ATTR_RO ( voltage_now ) ;
static ssize_t current_now_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct gb_interface * intf = to_gb_interface ( dev ) ;
int ret ;
u32 measurement ;
ret = gb_svc_pwrmon_intf_sample_get ( intf - > hd - > svc , intf - > interface_id ,
GB_SVC_PWRMON_TYPE_CURR ,
& measurement ) ;
if ( ret ) {
dev_err ( & intf - > dev , " failed to get current sample (%d) \n " , ret ) ;
return ret ;
}
return sprintf ( buf , " %u \n " , measurement ) ;
}
static DEVICE_ATTR_RO ( current_now ) ;
static ssize_t power_now_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct gb_interface * intf = to_gb_interface ( dev ) ;
int ret ;
u32 measurement ;
ret = gb_svc_pwrmon_intf_sample_get ( intf - > hd - > svc , intf - > interface_id ,
GB_SVC_PWRMON_TYPE_PWR ,
& measurement ) ;
if ( ret ) {
dev_err ( & intf - > dev , " failed to get power sample (%d) \n " , ret ) ;
return ret ;
}
return sprintf ( buf , " %u \n " , measurement ) ;
}
static DEVICE_ATTR_RO ( power_now ) ;
2016-07-20 17:40:25 +03:00
static ssize_t power_state_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct gb_interface * intf = to_gb_interface ( dev ) ;
if ( intf - > active )
return scnprintf ( buf , PAGE_SIZE , " on \n " ) ;
else
return scnprintf ( buf , PAGE_SIZE , " off \n " ) ;
}
static ssize_t power_state_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t len )
{
struct gb_interface * intf = to_gb_interface ( dev ) ;
bool activate ;
int ret = 0 ;
if ( kstrtobool ( buf , & activate ) )
return - EINVAL ;
mutex_lock ( & intf - > mutex ) ;
if ( activate = = intf - > active )
goto unlock ;
if ( activate ) {
ret = gb_interface_activate ( intf ) ;
if ( ret ) {
dev_err ( & intf - > dev ,
" failed to activate interface: %d \n " , ret ) ;
goto unlock ;
}
ret = gb_interface_enable ( intf ) ;
if ( ret ) {
dev_err ( & intf - > dev ,
" failed to enable interface: %d \n " , ret ) ;
gb_interface_deactivate ( intf ) ;
goto unlock ;
}
} else {
gb_interface_disable ( intf ) ;
gb_interface_deactivate ( intf ) ;
}
unlock :
mutex_unlock ( & intf - > mutex ) ;
if ( ret )
return ret ;
return len ;
}
static DEVICE_ATTR_RW ( power_state ) ;
2016-07-19 16:24:46 +03:00
static const char * gb_interface_type_string ( struct gb_interface * intf )
{
static const char * const types [ ] = {
2016-07-20 17:40:20 +03:00
[ GB_INTERFACE_TYPE_INVALID ] = " invalid " ,
[ GB_INTERFACE_TYPE_UNKNOWN ] = " unknown " ,
[ GB_INTERFACE_TYPE_DUMMY ] = " dummy " ,
[ GB_INTERFACE_TYPE_UNIPRO ] = " unipro " ,
[ GB_INTERFACE_TYPE_GREYBUS ] = " greybus " ,
2016-07-19 16:24:46 +03:00
} ;
return types [ intf - > type ] ;
}
static ssize_t interface_type_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct gb_interface * intf = to_gb_interface ( dev ) ;
return sprintf ( buf , " %s \n " , gb_interface_type_string ( intf ) ) ;
}
static DEVICE_ATTR_RO ( interface_type ) ;
2016-07-19 16:24:47 +03:00
static struct attribute * interface_unipro_attrs [ ] = {
2015-12-22 19:34:34 +03:00
& dev_attr_ddbl1_manufacturer_id . attr ,
& dev_attr_ddbl1_product_id . attr ,
2016-07-19 16:24:47 +03:00
NULL
} ;
static struct attribute * interface_greybus_attrs [ ] = {
2015-11-25 17:58:56 +03:00
& dev_attr_vendor_id . attr ,
& dev_attr_product_id . attr ,
2015-12-28 09:29:00 +03:00
& dev_attr_serial_number . attr ,
2016-07-19 16:24:47 +03:00
NULL
} ;
static struct attribute * interface_power_attrs [ ] = {
2016-04-08 06:15:30 +03:00
& dev_attr_voltage_now . attr ,
& dev_attr_current_now . attr ,
& dev_attr_power_now . attr ,
2016-07-20 17:40:25 +03:00
& dev_attr_power_state . attr ,
2016-07-19 16:24:47 +03:00
NULL
} ;
static struct attribute * interface_common_attrs [ ] = {
2016-07-21 13:48:57 +03:00
& dev_attr_interface_id . attr ,
2016-07-19 16:24:46 +03:00
& dev_attr_interface_type . attr ,
2016-07-19 16:24:47 +03:00
NULL
} ;
2016-07-19 16:24:48 +03:00
static umode_t interface_unipro_is_visible ( struct kobject * kobj ,
2017-07-23 20:51:46 +03:00
struct attribute * attr , int n )
2016-07-19 16:24:48 +03:00
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct gb_interface * intf = to_gb_interface ( dev ) ;
switch ( intf - > type ) {
2016-07-20 17:40:20 +03:00
case GB_INTERFACE_TYPE_UNIPRO :
case GB_INTERFACE_TYPE_GREYBUS :
2016-07-19 16:24:48 +03:00
return attr - > mode ;
default :
return 0 ;
}
}
static umode_t interface_greybus_is_visible ( struct kobject * kobj ,
2017-07-23 20:51:46 +03:00
struct attribute * attr , int n )
2016-07-19 16:24:48 +03:00
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct gb_interface * intf = to_gb_interface ( dev ) ;
switch ( intf - > type ) {
2016-07-20 17:40:20 +03:00
case GB_INTERFACE_TYPE_GREYBUS :
2016-07-19 16:24:48 +03:00
return attr - > mode ;
default :
return 0 ;
}
}
static umode_t interface_power_is_visible ( struct kobject * kobj ,
2017-07-23 20:51:46 +03:00
struct attribute * attr , int n )
2016-07-19 16:24:48 +03:00
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct gb_interface * intf = to_gb_interface ( dev ) ;
switch ( intf - > type ) {
2016-07-20 17:40:20 +03:00
case GB_INTERFACE_TYPE_UNIPRO :
case GB_INTERFACE_TYPE_GREYBUS :
2016-07-19 16:24:48 +03:00
return attr - > mode ;
default :
return 0 ;
}
}
2016-07-19 16:24:47 +03:00
static const struct attribute_group interface_unipro_group = {
2016-07-19 16:24:48 +03:00
. is_visible = interface_unipro_is_visible ,
2016-07-19 16:24:47 +03:00
. attrs = interface_unipro_attrs ,
} ;
static const struct attribute_group interface_greybus_group = {
2016-07-19 16:24:48 +03:00
. is_visible = interface_greybus_is_visible ,
2016-07-19 16:24:47 +03:00
. attrs = interface_greybus_attrs ,
} ;
static const struct attribute_group interface_power_group = {
2016-07-19 16:24:48 +03:00
. is_visible = interface_power_is_visible ,
2016-07-19 16:24:47 +03:00
. attrs = interface_power_attrs ,
} ;
static const struct attribute_group interface_common_group = {
. attrs = interface_common_attrs ,
} ;
static const struct attribute_group * interface_groups [ ] = {
& interface_unipro_group ,
& interface_greybus_group ,
& interface_power_group ,
& interface_common_group ,
NULL
2014-12-12 01:10:59 +03:00
} ;
2015-05-20 15:03:51 +03:00
static void gb_interface_release ( struct device * dev )
2014-10-21 08:01:04 +04:00
{
2014-12-20 01:56:31 +03:00
struct gb_interface * intf = to_gb_interface ( dev ) ;
2014-10-21 08:01:04 +04:00
2016-05-24 07:05:32 +03:00
trace_gb_interface_release ( intf ) ;
2014-12-20 01:56:31 +03:00
kfree ( intf ) ;
2014-10-21 08:01:04 +04:00
}
2016-09-09 10:47:01 +03:00
# ifdef CONFIG_PM
2016-07-14 23:13:00 +03:00
static int gb_interface_suspend ( struct device * dev )
{
struct gb_interface * intf = to_gb_interface ( dev ) ;
2017-01-05 20:39:12 +03:00
int ret ;
2016-07-14 23:13:00 +03:00
ret = gb_control_interface_suspend_prepare ( intf - > control ) ;
if ( ret )
return ret ;
ret = gb_control_suspend ( intf - > control ) ;
if ( ret )
goto err_hibernate_abort ;
ret = gb_interface_hibernate_link ( intf ) ;
if ( ret )
return ret ;
/* Delay to allow interface to enter standby before disabling refclk */
msleep ( GB_INTERFACE_SUSPEND_HIBERNATE_DELAY_MS ) ;
ret = gb_interface_refclk_set ( intf , false ) ;
if ( ret )
return ret ;
return 0 ;
err_hibernate_abort :
gb_control_interface_hibernate_abort ( intf - > control ) ;
return ret ;
}
static int gb_interface_resume ( struct device * dev )
{
struct gb_interface * intf = to_gb_interface ( dev ) ;
struct gb_svc * svc = intf - > hd - > svc ;
int ret ;
ret = gb_interface_refclk_set ( intf , true ) ;
if ( ret )
return ret ;
ret = gb_svc_intf_resume ( svc , intf - > interface_id ) ;
if ( ret )
return ret ;
ret = gb_control_resume ( intf - > control ) ;
if ( ret )
return ret ;
return 0 ;
}
static int gb_interface_runtime_idle ( struct device * dev )
{
pm_runtime_mark_last_busy ( dev ) ;
pm_request_autosuspend ( dev ) ;
return 0 ;
}
# endif
static const struct dev_pm_ops gb_interface_pm_ops = {
SET_RUNTIME_PM_OPS ( gb_interface_suspend , gb_interface_resume ,
gb_interface_runtime_idle )
} ;
2014-12-20 01:56:31 +03:00
struct device_type greybus_interface_type = {
. name = " greybus_interface " ,
2015-05-20 15:03:51 +03:00
. release = gb_interface_release ,
2016-07-14 23:13:00 +03:00
. pm = & gb_interface_pm_ops ,
2014-10-24 13:34:46 +04:00
} ;
2014-10-02 06:54:11 +04:00
/*
2016-07-28 12:40:53 +03:00
* A Greybus module represents a user - replaceable component on a GMP
2014-12-20 01:56:31 +03:00
* phone . An interface is the physical connection on that module . A
* module may have more than one interface .
2014-10-02 06:54:11 +04:00
*
2015-04-01 18:01:58 +03:00
* Create a gb_interface structure to represent a discovered interface .
* The position of interface within the Endo is encoded in " interface_id "
* argument .
*
2014-12-22 01:10:26 +03:00
* Returns a pointer to the new interfce or a null pointer if a
2014-10-02 06:54:11 +04:00
* failure occurs due to memory exhaustion .
*/
2016-04-23 19:47:24 +03:00
struct gb_interface * gb_interface_create ( struct gb_module * module ,
2015-06-22 14:12:27 +03:00
u8 interface_id )
2014-10-02 06:54:11 +04:00
{
2016-04-23 19:47:24 +03:00
struct gb_host_device * hd = module - > hd ;
2014-12-20 01:56:31 +03:00
struct gb_interface * intf ;
2014-10-02 06:54:11 +04:00
2014-12-20 01:56:31 +03:00
intf = kzalloc ( sizeof ( * intf ) , GFP_KERNEL ) ;
if ( ! intf )
2015-11-25 17:59:04 +03:00
return NULL ;
2014-10-02 06:54:11 +04:00
2014-12-20 01:56:31 +03:00
intf - > hd = hd ; /* XXX refcount? */
2016-04-23 19:47:24 +03:00
intf - > module = module ;
2015-04-01 18:01:58 +03:00
intf - > interface_id = interface_id ;
2014-12-20 01:56:31 +03:00
INIT_LIST_HEAD ( & intf - > bundles ) ;
2014-12-24 02:16:50 +03:00
INIT_LIST_HEAD ( & intf - > manifest_descs ) ;
2016-04-23 19:47:25 +03:00
mutex_init ( & intf - > mutex ) ;
2016-05-27 18:26:40 +03:00
INIT_WORK ( & intf - > mode_switch_work , gb_interface_mode_switch_work ) ;
init_completion ( & intf - > mode_switch_completion ) ;
2014-10-02 06:54:11 +04:00
2015-07-01 09:43:58 +03:00
/* Invalid device id to start with */
2016-03-30 01:56:06 +03:00
intf - > device_id = GB_INTERFACE_DEVICE_ID_BAD ;
2015-07-01 09:43:58 +03:00
2016-04-23 19:47:24 +03:00
intf - > dev . parent = & module - > dev ;
2014-12-20 01:56:31 +03:00
intf - > dev . bus = & greybus_bus_type ;
intf - > dev . type = & greybus_interface_type ;
intf - > dev . groups = interface_groups ;
2016-04-23 19:47:24 +03:00
intf - > dev . dma_mask = module - > dev . dma_mask ;
2014-12-20 01:56:31 +03:00
device_initialize ( & intf - > dev ) ;
2016-04-23 19:47:24 +03:00
dev_set_name ( & intf - > dev , " %s.%u " , dev_name ( & module - > dev ) ,
2017-07-23 20:51:46 +03:00
interface_id ) ;
2014-11-13 15:44:37 +03:00
2016-07-14 23:13:00 +03:00
pm_runtime_set_autosuspend_delay ( & intf - > dev ,
GB_INTERFACE_AUTOSUSPEND_MS ) ;
2016-05-24 07:05:32 +03:00
trace_gb_interface_create ( intf ) ;
2014-12-20 01:56:31 +03:00
return intf ;
2014-10-02 06:54:11 +04:00
}
2016-04-23 19:47:29 +03:00
static int gb_interface_vsys_set ( struct gb_interface * intf , bool enable )
{
struct gb_svc * svc = intf - > hd - > svc ;
int ret ;
dev_dbg ( & intf - > dev , " %s - %d \n " , __func__ , enable ) ;
ret = gb_svc_intf_vsys_set ( svc , intf - > interface_id , enable ) ;
if ( ret ) {
2016-05-25 23:18:14 +03:00
dev_err ( & intf - > dev , " failed to set v_sys: %d \n " , ret ) ;
2016-04-23 19:47:29 +03:00
return ret ;
}
return 0 ;
}
static int gb_interface_refclk_set ( struct gb_interface * intf , bool enable )
{
struct gb_svc * svc = intf - > hd - > svc ;
int ret ;
dev_dbg ( & intf - > dev , " %s - %d \n " , __func__ , enable ) ;
ret = gb_svc_intf_refclk_set ( svc , intf - > interface_id , enable ) ;
if ( ret ) {
2016-05-25 23:18:14 +03:00
dev_err ( & intf - > dev , " failed to set refclk: %d \n " , ret ) ;
2016-04-23 19:47:29 +03:00
return ret ;
}
return 0 ;
}
static int gb_interface_unipro_set ( struct gb_interface * intf , bool enable )
{
struct gb_svc * svc = intf - > hd - > svc ;
int ret ;
dev_dbg ( & intf - > dev , " %s - %d \n " , __func__ , enable ) ;
ret = gb_svc_intf_unipro_set ( svc , intf - > interface_id , enable ) ;
if ( ret ) {
2016-05-25 23:18:14 +03:00
dev_err ( & intf - > dev , " failed to set UniPro: %d \n " , ret ) ;
2016-04-23 19:47:29 +03:00
return ret ;
}
return 0 ;
}
2016-07-20 17:40:23 +03:00
static int gb_interface_activate_operation ( struct gb_interface * intf ,
enum gb_interface_type * intf_type )
2016-04-23 19:47:29 +03:00
{
struct gb_svc * svc = intf - > hd - > svc ;
u8 type ;
int ret ;
dev_dbg ( & intf - > dev , " %s \n " , __func__ ) ;
ret = gb_svc_intf_activate ( svc , intf - > interface_id , & type ) ;
if ( ret ) {
dev_err ( & intf - > dev , " failed to activate: %d \n " , ret ) ;
return ret ;
}
switch ( type ) {
case GB_SVC_INTF_TYPE_DUMMY :
2016-07-20 17:40:23 +03:00
* intf_type = GB_INTERFACE_TYPE_DUMMY ;
2016-04-23 19:47:29 +03:00
/* FIXME: handle as an error for now */
return - ENODEV ;
case GB_SVC_INTF_TYPE_UNIPRO :
2016-07-20 17:40:23 +03:00
* intf_type = GB_INTERFACE_TYPE_UNIPRO ;
2016-04-23 19:47:29 +03:00
dev_err ( & intf - > dev , " interface type UniPro not supported \n " ) ;
2016-07-20 17:40:22 +03:00
/* FIXME: handle as an error for now */
return - ENODEV ;
2016-04-23 19:47:29 +03:00
case GB_SVC_INTF_TYPE_GREYBUS :
2016-07-20 17:40:23 +03:00
* intf_type = GB_INTERFACE_TYPE_GREYBUS ;
2016-04-23 19:47:29 +03:00
break ;
default :
dev_err ( & intf - > dev , " unknown interface type: %u \n " , type ) ;
2016-07-20 17:40:23 +03:00
* intf_type = GB_INTERFACE_TYPE_UNKNOWN ;
2016-04-23 19:47:29 +03:00
return - ENODEV ;
}
return 0 ;
}
static int gb_interface_hibernate_link ( struct gb_interface * intf )
{
2016-07-08 06:07:00 +03:00
struct gb_svc * svc = intf - > hd - > svc ;
2016-04-23 19:47:29 +03:00
2016-07-08 06:07:00 +03:00
return gb_svc_intf_set_power_mode_hibernate ( svc , intf - > interface_id ) ;
2016-04-23 19:47:29 +03:00
}
2016-07-20 17:40:23 +03:00
static int _gb_interface_activate ( struct gb_interface * intf ,
enum gb_interface_type * type )
2016-03-30 01:56:04 +03:00
{
int ret ;
2016-07-20 17:40:23 +03:00
* type = GB_INTERFACE_TYPE_UNKNOWN ;
2016-07-20 17:40:24 +03:00
if ( intf - > ejected | | intf - > removed )
2016-04-23 19:47:25 +03:00
return - ENODEV ;
2016-04-23 19:47:29 +03:00
ret = gb_interface_vsys_set ( intf , true ) ;
2016-03-30 01:56:08 +03:00
if ( ret )
return ret ;
2016-04-23 19:47:29 +03:00
ret = gb_interface_refclk_set ( intf , true ) ;
if ( ret )
goto err_vsys_disable ;
ret = gb_interface_unipro_set ( intf , true ) ;
if ( ret )
goto err_refclk_disable ;
2016-07-20 17:40:23 +03:00
ret = gb_interface_activate_operation ( intf , type ) ;
2016-07-20 17:40:27 +03:00
if ( ret ) {
switch ( * type ) {
case GB_INTERFACE_TYPE_UNIPRO :
case GB_INTERFACE_TYPE_GREYBUS :
goto err_hibernate_link ;
default :
goto err_unipro_disable ;
}
}
2016-04-23 19:47:29 +03:00
ret = gb_interface_read_dme ( intf ) ;
if ( ret )
goto err_hibernate_link ;
2016-03-30 01:56:04 +03:00
ret = gb_interface_route_create ( intf ) ;
if ( ret )
2016-04-23 19:47:29 +03:00
goto err_hibernate_link ;
2016-03-30 01:56:04 +03:00
2016-04-23 19:47:26 +03:00
intf - > active = true ;
2016-05-24 07:05:32 +03:00
trace_gb_interface_activate ( intf ) ;
2016-03-30 01:56:04 +03:00
return 0 ;
2016-04-23 19:47:29 +03:00
err_hibernate_link :
gb_interface_hibernate_link ( intf ) ;
err_unipro_disable :
gb_interface_unipro_set ( intf , false ) ;
err_refclk_disable :
gb_interface_refclk_set ( intf , false ) ;
err_vsys_disable :
gb_interface_vsys_set ( intf , false ) ;
return ret ;
2016-03-30 01:56:04 +03:00
}
2016-07-20 17:40:22 +03:00
/*
2016-07-20 17:40:23 +03:00
* At present , we assume a UniPro - only module to be a Greybus module that
* failed to send its mailbox poke . There is some reason to believe that this
* is because of a bug in the ES3 bootrom .
2016-07-20 17:40:22 +03:00
*
2016-07-20 17:40:23 +03:00
* FIXME : Check if this is a Toshiba bridge before retrying ?
2016-07-20 17:40:22 +03:00
*/
2016-07-20 17:40:23 +03:00
static int _gb_interface_activate_es3_hack ( struct gb_interface * intf ,
enum gb_interface_type * type )
2016-07-20 17:40:22 +03:00
{
int retries = 3 ;
int ret ;
while ( retries - - ) {
2016-07-20 17:40:23 +03:00
ret = _gb_interface_activate ( intf , type ) ;
if ( ret = = - ENODEV & & * type = = GB_INTERFACE_TYPE_UNIPRO )
2016-07-20 17:40:22 +03:00
continue ;
break ;
}
return ret ;
}
2016-07-20 17:40:23 +03:00
/*
* Activate an interface .
*
* Locking : Caller holds the interface mutex .
*/
int gb_interface_activate ( struct gb_interface * intf )
{
enum gb_interface_type type ;
int ret ;
switch ( intf - > type ) {
case GB_INTERFACE_TYPE_INVALID :
case GB_INTERFACE_TYPE_GREYBUS :
ret = _gb_interface_activate_es3_hack ( intf , & type ) ;
break ;
default :
ret = _gb_interface_activate ( intf , & type ) ;
}
/* Make sure type is detected correctly during reactivation. */
if ( intf - > type ! = GB_INTERFACE_TYPE_INVALID ) {
if ( type ! = intf - > type ) {
dev_err ( & intf - > dev , " failed to detect interface type \n " ) ;
if ( ! ret )
gb_interface_deactivate ( intf ) ;
return - EIO ;
}
} else {
intf - > type = type ;
}
return ret ;
}
2016-04-23 19:47:25 +03:00
/*
* Deactivate an interface .
*
* Locking : Caller holds the interface mutex .
*/
2016-03-30 01:56:04 +03:00
void gb_interface_deactivate ( struct gb_interface * intf )
{
2016-04-23 19:47:26 +03:00
if ( ! intf - > active )
return ;
2016-05-24 07:05:32 +03:00
trace_gb_interface_deactivate ( intf ) ;
2016-05-27 18:26:40 +03:00
/* Abort any ongoing mode switch. */
if ( intf - > mode_switch )
complete ( & intf - > mode_switch_completion ) ;
2016-03-30 01:56:04 +03:00
gb_interface_route_destroy ( intf ) ;
2016-04-23 19:47:29 +03:00
gb_interface_hibernate_link ( intf ) ;
gb_interface_unipro_set ( intf , false ) ;
gb_interface_refclk_set ( intf , false ) ;
gb_interface_vsys_set ( intf , false ) ;
2016-04-23 19:47:26 +03:00
intf - > active = false ;
2016-03-30 01:56:04 +03:00
}
2016-03-09 14:20:36 +03:00
/*
2016-04-13 20:19:08 +03:00
* Enable an interface by enabling its control connection , fetching the
* manifest and other information over it , and finally registering its child
* devices .
2016-04-23 19:47:25 +03:00
*
* Locking : Caller holds the interface mutex .
2014-11-14 14:55:07 +03:00
*/
2016-03-09 14:20:42 +03:00
int gb_interface_enable ( struct gb_interface * intf )
2014-11-14 14:55:07 +03:00
{
2016-04-13 20:19:06 +03:00
struct gb_control * control ;
2016-03-09 14:20:37 +03:00
struct gb_bundle * bundle , * tmp ;
2015-06-22 14:12:27 +03:00
int ret , size ;
void * manifest ;
2016-03-30 01:56:02 +03:00
ret = gb_interface_read_and_clear_init_status ( intf ) ;
2016-03-30 01:56:00 +03:00
if ( ret ) {
2016-03-30 01:56:02 +03:00
dev_err ( & intf - > dev , " failed to clear init status: %d \n " , ret ) ;
2016-03-30 01:56:00 +03:00
return ret ;
}
2015-12-15 17:28:56 +03:00
/* Establish control connection */
2016-04-13 20:19:06 +03:00
control = gb_control_create ( intf ) ;
if ( IS_ERR ( control ) ) {
2016-05-09 15:40:09 +03:00
dev_err ( & intf - > dev , " failed to create control device: %ld \n " ,
2017-07-23 20:51:46 +03:00
PTR_ERR ( control ) ) ;
2016-04-13 20:19:06 +03:00
return PTR_ERR ( control ) ;
}
intf - > control = control ;
2015-12-15 17:28:56 +03:00
ret = gb_control_enable ( intf - > control ) ;
if ( ret )
2016-04-13 20:19:06 +03:00
goto err_put_control ;
2015-12-07 17:05:34 +03:00
2015-06-22 14:12:27 +03:00
/* Get manifest size using control protocol on CPort */
size = gb_control_get_manifest_size_operation ( intf ) ;
if ( size < = 0 ) {
2015-12-07 17:05:46 +03:00
dev_err ( & intf - > dev , " failed to get manifest size: %d \n " , size ) ;
2016-03-09 14:20:39 +03:00
2015-06-22 14:12:27 +03:00
if ( size )
2016-03-09 14:20:39 +03:00
ret = size ;
2015-06-22 14:12:27 +03:00
else
2016-03-09 14:20:39 +03:00
ret = - EINVAL ;
goto err_disable_control ;
2015-06-22 14:12:27 +03:00
}
manifest = kmalloc ( size , GFP_KERNEL ) ;
2016-03-09 14:20:39 +03:00
if ( ! manifest ) {
ret = - ENOMEM ;
goto err_disable_control ;
}
2015-06-22 14:12:27 +03:00
/* Get manifest using control protocol on CPort */
ret = gb_control_get_manifest_operation ( intf , manifest , size ) ;
if ( ret ) {
2015-12-07 17:05:46 +03:00
dev_err ( & intf - > dev , " failed to get manifest: %d \n " , ret ) ;
2016-03-09 14:20:37 +03:00
goto err_free_manifest ;
2014-11-14 14:55:07 +03:00
}
/*
2015-06-22 14:12:27 +03:00
* Parse the manifest and build up our data structures representing
* what ' s in it .
2014-11-14 14:55:07 +03:00
*/
2015-06-22 14:12:27 +03:00
if ( ! gb_manifest_parse ( intf , manifest , size ) ) {
2015-12-07 17:05:46 +03:00
dev_err ( & intf - > dev , " failed to parse manifest \n " ) ;
2015-06-22 14:12:27 +03:00
ret = - EINVAL ;
2016-03-09 14:20:37 +03:00
goto err_destroy_bundles ;
2014-11-14 14:55:07 +03:00
}
2016-01-19 14:51:21 +03:00
ret = gb_control_get_bundle_versions ( intf - > control ) ;
if ( ret )
2016-03-09 14:20:37 +03:00
goto err_destroy_bundles ;
2016-08-06 01:08:40 +03:00
/* Register the control device and any bundles */
ret = gb_control_add ( intf - > control ) ;
if ( ret )
2017-01-05 20:39:12 +03:00
goto err_destroy_bundles ;
2016-08-06 01:08:40 +03:00
2016-07-14 23:13:00 +03:00
pm_runtime_use_autosuspend ( & intf - > dev ) ;
pm_runtime_get_noresume ( & intf - > dev ) ;
pm_runtime_set_active ( & intf - > dev ) ;
pm_runtime_enable ( & intf - > dev ) ;
2016-04-13 20:19:08 +03:00
list_for_each_entry_safe_reverse ( bundle , tmp , & intf - > bundles , links ) {
ret = gb_bundle_add ( bundle ) ;
if ( ret ) {
gb_bundle_destroy ( bundle ) ;
continue ;
}
}
2016-03-09 14:20:37 +03:00
kfree ( manifest ) ;
2016-01-19 14:51:21 +03:00
2016-04-13 20:19:06 +03:00
intf - > enabled = true ;
2016-07-14 23:13:00 +03:00
pm_runtime_put ( & intf - > dev ) ;
2016-05-24 07:05:32 +03:00
trace_gb_interface_enable ( intf ) ;
2016-03-09 14:20:37 +03:00
return 0 ;
err_destroy_bundles :
list_for_each_entry_safe ( bundle , tmp , & intf - > bundles , links )
gb_bundle_destroy ( bundle ) ;
err_free_manifest :
2016-03-09 14:20:36 +03:00
kfree ( manifest ) ;
2016-03-09 14:20:39 +03:00
err_disable_control :
gb_control_disable ( intf - > control ) ;
2016-04-13 20:19:06 +03:00
err_put_control :
gb_control_put ( intf - > control ) ;
intf - > control = NULL ;
2016-03-09 14:20:36 +03:00
return ret ;
}
2016-04-23 19:47:25 +03:00
/*
* Disable an interface and destroy its bundles .
*
* Locking : Caller holds the interface mutex .
*/
2016-03-09 14:20:43 +03:00
void gb_interface_disable ( struct gb_interface * intf )
{
struct gb_bundle * bundle ;
struct gb_bundle * next ;
2016-04-13 20:19:06 +03:00
if ( ! intf - > enabled )
return ;
2016-05-24 07:05:32 +03:00
trace_gb_interface_disable ( intf ) ;
2016-07-14 23:13:00 +03:00
pm_runtime_get_sync ( & intf - > dev ) ;
2016-05-27 18:26:24 +03:00
/* Set disconnected flag to avoid I/O during connection tear down. */
if ( intf - > quirks & GB_INTERFACE_QUIRK_FORCED_DISABLE )
intf - > disconnected = true ;
2016-03-09 14:20:43 +03:00
list_for_each_entry_safe ( bundle , next , & intf - > bundles , links )
gb_bundle_destroy ( bundle ) ;
2016-07-08 06:07:00 +03:00
if ( ! intf - > mode_switch & & ! intf - > disconnected )
gb_control_interface_deactivate_prepare ( intf - > control ) ;
2016-04-13 20:19:03 +03:00
gb_control_del ( intf - > control ) ;
2016-03-09 14:20:43 +03:00
gb_control_disable ( intf - > control ) ;
2016-04-13 20:19:06 +03:00
gb_control_put ( intf - > control ) ;
intf - > control = NULL ;
intf - > enabled = false ;
2016-07-14 23:13:00 +03:00
pm_runtime_disable ( & intf - > dev ) ;
pm_runtime_set_suspended ( & intf - > dev ) ;
pm_runtime_dont_use_autosuspend ( & intf - > dev ) ;
pm_runtime_put_noidle ( & intf - > dev ) ;
2016-03-09 14:20:43 +03:00
}
2016-04-13 20:19:08 +03:00
/* Register an interface. */
2016-03-09 14:20:36 +03:00
int gb_interface_add ( struct gb_interface * intf )
{
int ret ;
2015-12-07 17:05:45 +03:00
ret = device_add ( & intf - > dev ) ;
if ( ret ) {
dev_err ( & intf - > dev , " failed to register interface: %d \n " , ret ) ;
2016-03-09 14:20:36 +03:00
return ret ;
2015-12-07 17:05:45 +03:00
}
2016-05-24 07:05:32 +03:00
trace_gb_interface_add ( intf ) ;
2016-07-19 16:24:49 +03:00
dev_info ( & intf - > dev , " Interface added (%s) \n " ,
2017-07-23 20:51:46 +03:00
gb_interface_type_string ( intf ) ) ;
2016-07-19 16:24:49 +03:00
switch ( intf - > type ) {
2016-07-20 17:40:20 +03:00
case GB_INTERFACE_TYPE_GREYBUS :
2016-07-28 12:40:53 +03:00
dev_info ( & intf - > dev , " GMP VID=0x%08x, PID=0x%08x \n " ,
2017-07-23 20:51:46 +03:00
intf - > vendor_id , intf - > product_id ) ;
2020-07-27 21:32:58 +03:00
fallthrough ;
2016-07-20 17:40:20 +03:00
case GB_INTERFACE_TYPE_UNIPRO :
2016-07-19 16:24:49 +03:00
dev_info ( & intf - > dev , " DDBL1 Manufacturer=0x%08x, Product=0x%08x \n " ,
2017-07-23 20:51:46 +03:00
intf - > ddbl1_manufacturer_id ,
intf - > ddbl1_product_id ) ;
2016-07-19 16:24:49 +03:00
break ;
2016-07-20 17:40:20 +03:00
default :
break ;
2016-07-19 16:24:49 +03:00
}
2016-02-19 13:27:46 +03:00
2016-03-09 14:20:36 +03:00
return 0 ;
2014-11-14 14:55:07 +03:00
}
2016-03-09 14:20:43 +03:00
2016-04-23 19:47:24 +03:00
/* Deregister an interface. */
void gb_interface_del ( struct gb_interface * intf )
2016-03-09 14:20:43 +03:00
{
if ( device_is_registered ( & intf - > dev ) ) {
2016-05-24 07:05:32 +03:00
trace_gb_interface_del ( intf ) ;
2016-03-09 14:20:43 +03:00
device_del ( & intf - > dev ) ;
dev_info ( & intf - > dev , " Interface removed \n " ) ;
}
2016-04-23 19:47:24 +03:00
}
2016-03-09 14:20:43 +03:00
2016-04-23 19:47:24 +03:00
void gb_interface_put ( struct gb_interface * intf )
{
2016-03-09 14:20:43 +03:00
put_device ( & intf - > dev ) ;
}