diff options
Diffstat (limited to 'drivers/usb/otg/fsl_otg.c')
-rw-r--r-- | drivers/usb/otg/fsl_otg.c | 219 |
1 files changed, 78 insertions, 141 deletions
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c index 81a2985632b6..6941e0565c03 100644 --- a/drivers/usb/otg/fsl_otg.c +++ b/drivers/usb/otg/fsl_otg.c @@ -34,7 +34,6 @@ #include <linux/init.h> #include <linux/reboot.h> #include <linux/timer.h> -#include <linux/jiffies.h> #include <linux/list.h> #include <linux/usb.h> #include <linux/device.h> @@ -62,8 +61,6 @@ #define DRIVER_DESC "Freescale USB OTG Driver" #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC -#define TIMER_FREQ 1000 /* 100 ms*/ -#define IDLE_TIME 5000 /* 1000 ms */ MODULE_DESCRIPTION("Freescale USB OTG Transceiver Driver"); @@ -93,13 +90,6 @@ static struct fsl_otg_config fsl_otg_initdata = { .otg_port = 1, }; -/* the timer is used to monitor the otg loading, if idle for some times - * we will close the otg clk - */ -static unsigned long last_busy; -static bool clk_stopped; -static struct timer_list monitor_timer; - int write_ulpi(u8 addr, u8 data) { u32 temp; @@ -149,6 +139,15 @@ void fsl_otg_dischrg_vbus(int on) /* A-device driver vbus, controlled through PP bit in PORTSC */ void fsl_otg_drv_vbus(struct fsl_usb2_platform_data *pdata, int on) { +/* if (on) + usb_dr_regs->portsc = + cpu_to_le32((le32_to_cpu(usb_dr_regs->portsc) & + ~PORTSC_W1C_BITS) | PORTSC_PORT_POWER); + else + usb_dr_regs->portsc = + cpu_to_le32(le32_to_cpu(usb_dr_regs->portsc) & + ~PORTSC_W1C_BITS & ~PORTSC_PORT_POWER); +*/ if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_power) pdata->xcvr_ops->set_vbus_power(pdata->xcvr_ops, pdata, on); } @@ -399,61 +398,6 @@ int fsl_otg_tick_timer(void) return expired; } -static void fsl_otg_clk_gate(bool on) -{ - struct device *dev = fsl_otg_dev->otg.dev; - struct fsl_usb2_platform_data *pdata; - - if (dev) { - pdata = dev->platform_data; - if (pdata && pdata->usb_clock_for_pm) - pdata->usb_clock_for_pm(on); - } -} - -static void fsl_otg_clk_ctl(void) -{ - if (clk_stopped){ - fsl_otg_clk_gate(true); - clk_stopped = false; - } - last_busy = jiffies; -} - -static void fsl_otg_loading_monitor(unsigned long data) -{ - unsigned long now = jiffies; - if (!clk_stopped){ - if (time_after(now, last_busy + msecs_to_jiffies(IDLE_TIME))){ - printk("otg is idle for some times,so we close the clock %x\n", le32_to_cpu(usb_dr_regs->otgsc)); - clk_stopped = true; - fsl_otg_clk_gate(false); - printk("close otg clk ok\n"); - } - } - mod_timer(&monitor_timer, jiffies + msecs_to_jiffies(TIMER_FREQ)); -} - -/** - * Enable vbus interrupt - * The otg cares USB_ID interrupt - * The device cares B Sesstion Valid - */ -static void b_session_irq_enable(bool enable) -{ - int osc = le32_to_cpu(usb_dr_regs->otgsc); - /* The other interrupts' status should not be cleared */ - osc &= ~(OTGSC_INTSTS_USB_ID | OTGSC_INTSTS_A_VBUS_VALID - | OTGSC_INTSTS_A_SESSION_VALID | OTGSC_INTSTS_B_SESSION_VALID); - osc |= OTGSC_INTSTS_B_SESSION_VALID; - - if (enable) - osc |= OTGSC_INTR_B_SESSION_VALID_EN; - else - osc &= ~OTGSC_INTR_B_SESSION_VALID_EN; - usb_dr_regs->otgsc = cpu_to_le32(osc); -} - /* Reset controller, not reset the bus */ void otg_reset_controller(void) { @@ -540,6 +484,7 @@ int fsl_otg_start_gadget(struct otg_fsm *fsm, int on) struct device *dev; struct platform_driver *gadget_pdrv; struct platform_device *gadget_pdev; + if (!xceiv->gadget || !xceiv->gadget->dev.parent) return -ENODEV; @@ -575,6 +520,7 @@ static int fsl_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host) if (host) { VDBG("host off......\n"); + otg_p->host->otg_port = fsl_otg_initdata.otg_port; otg_p->host->is_b_host = otg_dev->fsm.id; /* must leave time for khubd to finish its thing @@ -691,29 +637,11 @@ static void fsl_otg_event(struct work_struct *work) { struct fsl_otg *og = container_of(work, struct fsl_otg, otg_event.work); struct otg_fsm *fsm = &og->fsm; - struct otg_transceiver *otg = &og->otg; - - otg->default_a = (fsm->id == 0); - /* clear conn information */ - if (fsm->id) - fsm->b_conn = 0; - else - fsm->a_conn = 0; - - if (otg->host) - otg->host->is_b_host = fsm->id; - if (otg->gadget) - otg->gadget->is_a_peripheral = !fsm->id; if (fsm->id) { /* switch to gadget */ - b_session_irq_enable(true); fsl_otg_start_host(fsm, 0); otg_drv_vbus(fsm, 0); fsl_otg_start_gadget(fsm, 1); - }else { /* switch to host */ - fsl_otg_start_gadget(fsm, 0); - otg_drv_vbus(fsm, 1); - fsl_otg_start_host(fsm, 1); } } @@ -753,13 +681,13 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id) struct otg_fsm *fsm; struct fsl_usb2_platform_data *pdata = (struct fsl_usb2_platform_data *)dev_id; - struct fsl_otg *f_otg; + struct fsl_otg *p_otg; struct otg_transceiver *otg_trans = otg_get_transceiver(); int value; - f_otg = container_of(otg_trans, struct fsl_otg, otg); - fsm = &f_otg->fsm; - fsl_otg_clk_ctl(); + p_otg = container_of(otg_trans, struct fsl_otg, otg); + fsm = &p_otg->fsm; + if (pdata->id_gpio == 0) return IRQ_NONE; @@ -771,25 +699,35 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id) set_irq_type(gpio_to_irq(pdata->id_gpio), IRQ_TYPE_LEVEL_HIGH); - if (value == f_otg->fsm.id) + if (value == p_otg->fsm.id) return IRQ_HANDLED; - f_otg->fsm.id = value; + p_otg->fsm.id = value; - cancel_delayed_work(&f_otg->otg_event); - schedule_delayed_work(&f_otg->otg_event, msecs_to_jiffies(10)); - /* if host mode, we should clear B_SESSION_VLD event and disable - * B_SESSION_VLD irq - */ - if (!f_otg->fsm.id) { - b_session_irq_enable(false); - }else { - //b_session_irq_enable(true); - } + otg_trans->default_a = (fsm->id == 0); + /* clear conn information */ + if (fsm->id) + fsm->b_conn = 0; + else + fsm->a_conn = 0; + if (otg_trans->host) + otg_trans->host->is_b_host = fsm->id; + if (otg_trans->gadget) + otg_trans->gadget->is_a_peripheral = !fsm->id; + + VDBG("ID int (ID is %d)\n", fsm->id); + if (fsm->id) { /* switch to gadget */ + schedule_delayed_work(&p_otg->otg_event, 100); + + } else { /* switch to host */ + cancel_delayed_work(&p_otg->otg_event); + fsl_otg_start_gadget(fsm, 0); + otg_drv_vbus(fsm, 1); + fsl_otg_start_host(fsm, 1); + } return IRQ_HANDLED; } - /* Interrupt handler. OTG/host/peripheral share the same int line. * OTG driver clears OTGSC interrupts and leaves USB interrupts * intact. It needs to have knowledge of some USB interrupts @@ -797,65 +735,71 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id) */ irqreturn_t fsl_otg_isr(int irq, void *dev_id) { - struct fsl_otg *fotg = (struct fsl_otg *)dev_id; - struct otg_transceiver *otg = &fotg->otg; + struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm; + struct otg_transceiver *otg = &((struct fsl_otg *)dev_id)->otg; u32 otg_int_src, otg_sc; - irqreturn_t ret = IRQ_NONE; - fsl_otg_clk_ctl(); otg_sc = le32_to_cpu(usb_dr_regs->otgsc); otg_int_src = otg_sc & OTGSC_INTSTS_MASK & (otg_sc >> 8); - /* Only clear otg interrupts, expect B_SESSION_VALID, - * Leave it to be handled by arcotg_udc */ - usb_dr_regs->otgsc = ((usb_dr_regs->otgsc | cpu_to_le32(otg_sc & OTGSC_INTSTS_MASK))& - (~OTGSC_INTSTS_B_SESSION_VALID)); + /* Only clear otg interrupts */ + usb_dr_regs->otgsc |= cpu_to_le32(otg_sc & OTGSC_INTSTS_MASK); /*FIXME: ID change not generate when init to 0 */ - fotg->fsm.id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; - otg->default_a = (fotg->fsm.id == 0); + fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; + otg->default_a = (fsm->id == 0); /* process OTG interrupts */ if (otg_int_src) { if (otg_int_src & OTGSC_INTSTS_USB_ID) { - fotg->fsm.id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; - - printk("ID int (ID is %d)\n", fotg->fsm.id); - - cancel_delayed_work(&fotg->otg_event); - schedule_delayed_work(&fotg->otg_event, msecs_to_jiffies(10)); - /* if host mode, we should clear B_SESSION_VLD event and disable - * B_SESSION_VLD irq - */ - if (!fotg->fsm.id) { - b_session_irq_enable(false); - }else { - //b_session_irq_enable(true); + fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; + otg->default_a = (fsm->id == 0); + /* clear conn information */ + if (fsm->id) + fsm->b_conn = 0; + else + fsm->a_conn = 0; + + if (otg->host) + otg->host->is_b_host = fsm->id; + if (otg->gadget) + otg->gadget->is_a_peripheral = !fsm->id; + VDBG("ID int (ID is %d)\n", fsm->id); + + if (fsm->id) { /* switch to gadget */ + schedule_delayed_work(&((struct fsl_otg *) + dev_id)->otg_event, + 100); + } else { /* switch to host */ + cancel_delayed_work(& + ((struct fsl_otg *)dev_id)-> + otg_event); + fsl_otg_start_gadget(fsm, 0); + otg_drv_vbus(fsm, 1); + fsl_otg_start_host(fsm, 1); } - ret = IRQ_HANDLED; + + return IRQ_HANDLED; } } - return ret; + return IRQ_NONE; } static void fsl_otg_fsm_drv_vbus(int on) { struct otg_fsm *fsm = &(fsl_otg_dev->fsm); struct otg_transceiver *xceiv = fsm->transceiver; + struct device *dev = NULL; - struct device *dev; - /* - * The host is assigned at otg_set_host - */ - if (!xceiv->host) + if (!xceiv->host) { return; - /* - * The dev is assigned at usb_create_hcd which is called earlier - * than otg_set_host at host driver's probe - */ + } + dev = xceiv->host->controller; + fsl_otg_drv_vbus(dev->platform_data, on); + } static struct otg_fsm_ops fsl_otg_ops = { @@ -913,7 +857,6 @@ static int fsl_otg_conf(struct platform_device *pdev) fsl_otg_tc->otg.set_power = fsl_otg_set_power; fsl_otg_tc->otg.start_hnp = fsl_otg_start_hnp; fsl_otg_tc->otg.start_srp = fsl_otg_start_srp; - fsl_otg_tc->otg.dev = &pdev->dev; fsl_otg_dev = fsl_otg_tc; @@ -980,8 +923,6 @@ int usb_otg_start(struct platform_device *pdev) if (pdata->platform_init && pdata->platform_init(pdev) != 0) return -EINVAL; - clk_stopped = false; /* platform_init will open the otg clk */ - /* stop the controller */ temp = readl(&p_otg->dr_mem_map->usbcmd); temp &= ~USB_CMD_RUN_STOP; @@ -1308,10 +1249,6 @@ static int __init fsl_otg_probe(struct platform_device *pdev) return -EIO; } - last_busy = jiffies; - setup_timer(&monitor_timer, fsl_otg_loading_monitor, (unsigned long)pdev); - mod_timer(&monitor_timer, jiffies + msecs_to_jiffies(TIMER_FREQ)); - create_proc_file(); return status; } |