@ -163,6 +163,8 @@ struct twl4030_usb {
bool vbus_supplied ;
u8 asleep ;
bool irq_enabled ;
struct delayed_work id_workaround_work ;
} ;
/* internal define on top of container_of */
@ -287,10 +289,6 @@ static enum omap_musb_vbus_id_status
* are registered , and that both are active . . .
*/
spin_lock_irq ( & twl - > lock ) ;
twl - > linkstat = linkstat ;
spin_unlock_irq ( & twl - > lock ) ;
return linkstat ;
}
@ -412,6 +410,16 @@ static void twl4030_phy_resume(struct twl4030_usb *twl)
__twl4030_phy_resume ( twl ) ;
twl - > asleep = 0 ;
dev_dbg ( twl - > dev , " %s \n " , __func__ ) ;
/*
* XXX When VBUS gets driven after musb goes to A mode ,
* ID_PRES related interrupts no longer arrive , why ?
* Register itself is updated fine though , so we must poll .
*/
if ( twl - > linkstat = = OMAP_MUSB_ID_GROUND ) {
cancel_delayed_work ( & twl - > id_workaround_work ) ;
schedule_delayed_work ( & twl - > id_workaround_work , HZ ) ;
}
}
static int twl4030_usb_ldo_init ( struct twl4030_usb * twl )
@ -483,10 +491,18 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
{
struct twl4030_usb * twl = _twl ;
enum omap_musb_vbus_id_status status ;
enum omap_musb_vbus_id_status status_prev = twl - > linkstat ;
bool status_changed = false ;
status = twl4030_usb_linkstat ( twl ) ;
if ( status > 0 & & status ! = status_prev ) {
spin_lock_irq ( & twl - > lock ) ;
if ( status > = 0 & & status ! = twl - > linkstat ) {
twl - > linkstat = status ;
status_changed = true ;
}
spin_unlock_irq ( & twl - > lock ) ;
if ( status_changed ) {
/* FIXME add a set_power() method so that B-devices can
* configure the charger appropriately . It ' s not always
* correct to consume VBUS power , and how much current to
@ -498,13 +514,42 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
* USB_LINK_VBUS state . musb_hdrc won ' t care until it
* starts to handle softconnect right .
*/
omap_musb_mailbox ( twl - > linkstat ) ;
omap_musb_mailbox ( status ) ;
}
sysfs_notify ( & twl - > dev - > kobj , NULL , " vbus " ) ;
return IRQ_HANDLED ;
}
static void twl4030_id_workaround_work ( struct work_struct * work )
{
struct twl4030_usb * twl = container_of ( work , struct twl4030_usb ,
id_workaround_work . work ) ;
enum omap_musb_vbus_id_status status ;
bool status_changed = false ;
status = twl4030_usb_linkstat ( twl ) ;
spin_lock_irq ( & twl - > lock ) ;
if ( status > = 0 & & status ! = twl - > linkstat ) {
twl - > linkstat = status ;
status_changed = true ;
}
spin_unlock_irq ( & twl - > lock ) ;
if ( status_changed ) {
dev_dbg ( twl - > dev , " handle missing status change to %d \n " ,
status ) ;
omap_musb_mailbox ( status ) ;
}
/* don't schedule during sleep - irq works right then */
if ( status = = OMAP_MUSB_ID_GROUND & & ! twl - > asleep ) {
cancel_delayed_work ( & twl - > id_workaround_work ) ;
schedule_delayed_work ( & twl - > id_workaround_work , HZ ) ;
}
}
static int twl4030_usb_phy_init ( struct usb_phy * phy )
{
struct twl4030_usb * twl = phy_to_twl ( phy ) ;
@ -518,6 +563,8 @@ static int twl4030_usb_phy_init(struct usb_phy *phy)
twl - > asleep = 1 ;
status = twl4030_usb_linkstat ( twl ) ;
twl - > linkstat = status ;
if ( status = = OMAP_MUSB_ID_GROUND | | status = = OMAP_MUSB_VBUS_VALID )
omap_musb_mailbox ( twl - > linkstat ) ;
@ -608,6 +655,8 @@ static int twl4030_usb_probe(struct platform_device *pdev)
/* init spinlock for workqueue */
spin_lock_init ( & twl - > lock ) ;
INIT_DELAYED_WORK ( & twl - > id_workaround_work , twl4030_id_workaround_work ) ;
err = twl4030_usb_ldo_init ( twl ) ;
if ( err ) {
dev_err ( & pdev - > dev , " ldo init failed \n " ) ;
@ -646,6 +695,7 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
struct twl4030_usb * twl = platform_get_drvdata ( pdev ) ;
int val ;
cancel_delayed_work ( & twl - > id_workaround_work ) ;
device_remove_file ( twl - > dev , & dev_attr_vbus ) ;
/* set transceiver mode to power on defaults */