2013-08-14 12:44:06 +03:00
/*
* otg . c - ChipIdea USB IP core OTG driver
*
* Copyright ( C ) 2013 Freescale Semiconductor , Inc .
*
* Author : Peter Chen
*
* 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 file mainly handles otgsc register , it may include OTG operation
* in the future .
*/
# include <linux/usb/otg.h>
# include <linux/usb/gadget.h>
# include <linux/usb/chipidea.h>
# include "ci.h"
# include "bits.h"
# include "otg.h"
/**
2013-08-14 12:44:10 +03:00
* ci_otg_role - pick role based on ID pin state
* @ ci : the controller
*/
enum ci_role ci_otg_role ( struct ci_hdrc * ci )
{
u32 sts = hw_read ( ci , OP_OTGSC , ~ 0 ) ;
enum ci_role role = sts & OTGSC_ID
? CI_ROLE_GADGET
: CI_ROLE_HOST ;
return role ;
}
/**
* ci_role_work - perform role changing based on ID pin
* @ work : work struct
*/
static void ci_role_work ( struct work_struct * work )
{
struct ci_hdrc * ci = container_of ( work , struct ci_hdrc , work ) ;
enum ci_role role = ci_otg_role ( ci ) ;
if ( role ! = ci - > role ) {
dev_dbg ( ci - > dev , " switching from %s to %s \n " ,
ci_role ( ci ) - > name , ci - > roles [ role ] - > name ) ;
ci_role_stop ( ci ) ;
ci_role_start ( ci , role ) ;
}
enable_irq ( ci - > irq ) ;
}
/**
* ci_hdrc_otg_init - initialize otg struct
2013-08-14 12:44:06 +03:00
* ci : the controller
*/
int ci_hdrc_otg_init ( struct ci_hdrc * ci )
{
2013-08-14 12:44:10 +03:00
INIT_WORK ( & ci - > work , ci_role_work ) ;
ci - > wq = create_singlethread_workqueue ( " ci_otg " ) ;
if ( ! ci - > wq ) {
dev_err ( ci - > dev , " can't create workqueue \n " ) ;
return - ENODEV ;
}
2013-08-14 12:44:06 +03:00
return 0 ;
}
2013-08-14 12:44:10 +03:00
/**
* ci_hdrc_otg_destroy - destroy otg struct
* ci : the controller
*/
void ci_hdrc_otg_destroy ( struct ci_hdrc * ci )
{
if ( ci - > wq ) {
flush_workqueue ( ci - > wq ) ;
destroy_workqueue ( ci - > wq ) ;
}
ci_disable_otg_interrupt ( ci , OTGSC_INT_EN_BITS ) ;
ci_clear_otg_interrupt ( ci , OTGSC_INT_STATUS_BITS ) ;
}