summaryrefslogtreecommitdiff
path: root/drivers/usb/otg/fsl_otg.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/otg/fsl_otg.c')
-rw-r--r--drivers/usb/otg/fsl_otg.c219
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;
}