📄 dm_usb_isp1362.c
字号:
.release = single_release,};/* expect just one isp1362 per system */static const char proc_filename[] = "driver/isp1362";static void create_debug_file(struct isp1362 *isp1362){ struct proc_dir_entry *pde; pde = create_proc_entry(proc_filename, 0, NULL); if (pde == NULL) return; pde->proc_fops = &proc_ops; pde->data = isp1362; isp1362->pde = pde;}static void remove_debug_file(struct isp1362 *isp1362){ if (isp1362->pde) remove_proc_entry(proc_filename, NULL);}#endif/*-----------------------------------------------------------------*//* Software reset - can be called from any contect.*/static int isp1362_sw_reset(struct isp1362 *isp1362){ int retries = 15; unsigned long flags; int ret = 0; spin_lock_irqsave(&isp1362->lock, flags); isp1362_write_reg16(isp1362, HCSWRES, HCSWRES_MAGIC); isp1362_write_reg32(isp1362, HCCMDSTAT, HCCMDSTAT_HCR); while (--retries) { /* It usually resets within 1 ms */ mdelay(1); if (!(isp1362_read_reg32(isp1362, HCCMDSTAT) & HCCMDSTAT_HCR)) break; } if (!retries) { ERR("Software reset timeout\n"); ret = -ETIME; } spin_unlock_irqrestore(&isp1362->lock, flags); return ret;}static int isp1362_reset(struct usb_hcd *hcd){ struct isp1362 *isp1362 = hcd_to_isp1362(hcd); unsigned long t; u16 clkrdy = 0; int ret = 0, timeout = 15 /* ms */ ; ret = isp1362_sw_reset(isp1362); if (ret) return ret; t = jiffies + msecs_to_jiffies(timeout); while (time_before_eq(jiffies, t)) { msleep(4); spin_lock_irq(&isp1362->lock); clkrdy = isp1362_read_reg16(isp1362, HCuPINT) & HCuPINT_CLKRDY; spin_unlock_irq(&isp1362->lock); if (clkrdy) break; } if (!clkrdy) { ERR("Clock not ready after 20ms\n"); /* After sw_reset the clock won't report to be ready, if H_WAKEUP pin is high. */ ERR("Please make sure that the H_WAKEUP pin is pulled low!\n"); ret = -ENODEV; } return ret;}static void isp1362_stop(struct usb_hcd *hcd){ struct isp1362 *isp1362 = hcd_to_isp1362(hcd); unsigned long flags; u32 val; spin_lock_irqsave(&isp1362->lock, flags); isp1362_write_reg16(isp1362, HCuPINTENB, 0); /* Switch off ports' power, some devices don't come up after next 'insmod' without this */ val = isp1362_read_reg32(isp1362, HCRHDESCA); val &= ~(RH_A_NPS | RH_A_PSM); isp1362_write_reg32(isp1362, HCRHDESCA, val); isp1362_write_reg32(isp1362, HCRHSTATUS, RH_HS_LPS); spin_unlock_irqrestore(&isp1362->lock, flags); isp1362_sw_reset(isp1362);}/* Configure the chip. The chip must be successfully reset by now.*/static int isp1362_start(struct usb_hcd *hcd){ struct isp1362 *isp1362 = hcd_to_isp1362(hcd); struct isp1362_platform_data *board = isp1362->board; u32 val; unsigned long flags; spin_lock_irqsave(&isp1362->lock, flags); /* clear interrupt status and disable all interrupt sources */ isp1362_write_reg16(isp1362, HCuPINT, 0xff); isp1362_write_reg16(isp1362, HCuPINTENB, 0); val = isp1362_read_reg16(isp1362, HCCHIPID); if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) { ERR("Invalid chip ID %04x\n", val); spin_unlock_irqrestore(&isp1362->lock, flags); return -ENODEV; } /* To be removed in future */ hcd->uses_new_polling = 1; isp1362_write_reg16(isp1362, HCITLBUFLEN, ISP116x_ITL_BUFSIZE); isp1362_write_reg16(isp1362, HCATLBUFLEN, ISP116x_ATL_BUFSIZE); /* ----- HW conf */ val = HCHWCFG_INT_ENABLE | HCHWCFG_DBWIDTH(1); if (board->sel15Kres) val |= HCHWCFG_15KRSEL; /* Remote wakeup won't work without working clock */ if (board->remote_wakeup_enable) val |= HCHWCFG_CLKNOTSTOP; if (board->oc_enable) val |= HCHWCFG_ANALOG_OC; if (board->int_act_high) val |= HCHWCFG_INT_POL; if (board->int_edge_triggered) val |= HCHWCFG_INT_TRIGGER; isp1362_write_reg16(isp1362, HCHWCFG, val); /* ----- Root hub conf */ val = (25 << 24) & RH_A_POTPGT; /* AN10003_1.pdf recommends RH_A_NPS (no power switching) to be always set. Yet, instead, we request individual port power switching. */ val |= RH_A_PSM; /* Report overcurrent per port */ val |= RH_A_OCPM; isp1362_write_reg32(isp1362, HCRHDESCA, val); isp1362->rhdesca = isp1362_read_reg32(isp1362, HCRHDESCA); val = RH_B_PPCM; isp1362_write_reg32(isp1362, HCRHDESCB, val); isp1362->rhdescb = isp1362_read_reg32(isp1362, HCRHDESCB); val = 0; if (board->remote_wakeup_enable) { hcd->can_wakeup = 1; val |= RH_HS_DRWE; } isp1362_write_reg32(isp1362, HCRHSTATUS, val); isp1362->rhstatus = isp1362_read_reg32(isp1362, HCRHSTATUS); isp1362_write_reg32(isp1362, HCFMINTVL, 0x27782edf); hcd->state = HC_STATE_RUNNING; /* Set up interrupts */ isp1362->intenb = HCINT_MIE | HCINT_RHSC | HCINT_UE; if (board->remote_wakeup_enable) isp1362->intenb |= HCINT_RD; isp1362->irqenb = HCuPINT_ATL | HCuPINT_OPR; /* | HCuPINT_SUSP; */ isp1362_write_reg32(isp1362, HCINTENB, isp1362->intenb); isp1362_write_reg16(isp1362, HCuPINTENB, isp1362->irqenb); /* Go operational */ val = HCCONTROL_USB_OPER; if (board->remote_wakeup_enable) val |= HCCONTROL_RWE; isp1362_write_reg32(isp1362, HCCONTROL, val); /* Disable ports to avoid race in device enumeration */ isp1362_write_reg32(isp1362, HCRHPORT1, RH_PS_CCS); isp1362_write_reg32(isp1362, HCRHPORT2, RH_PS_CCS); isp1362_show_regs(isp1362); spin_unlock_irqrestore(&isp1362->lock, flags); return 0;}/*-----------------------------------------------------------------*/static struct hc_driver isp1362_hc_driver = { .description = hcd_name, .product_desc = "ISP116x Host Controller", .hcd_priv_size = sizeof(struct isp1362), .irq = isp1362_irq, .flags = HCD_USB11, .reset = isp1362_reset, .start = isp1362_start, .stop = isp1362_stop, .urb_enqueue = isp1362_urb_enqueue, .urb_dequeue = isp1362_urb_dequeue, .endpoint_disable = isp1362_endpoint_disable, .get_frame_number = isp1362_get_frame, .hub_status_data = isp1362_hub_status_data, .hub_control = isp1362_hub_control, .hub_suspend = isp1362_hub_suspend, .hub_resume = isp1362_hub_resume,};/*----------------------------------------------------------------*/static int __init_or_module isp1362_remove(struct device *dev){ struct usb_hcd *hcd = dev_get_drvdata(dev); struct isp1362 *isp1362; struct platform_device *pdev; struct resource *res; if (!hcd) return 0; isp1362 = hcd_to_isp1362(hcd); pdev = container_of(dev, struct platform_device, dev); remove_debug_file(isp1362); usb_remove_hcd(hcd); iounmap(isp1362->data_reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); release_mem_region(res->start, 2); iounmap(isp1362->addr_reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, 2); usb_put_hcd(hcd); return 0;}#define resource_len(r) (((r)->end - (r)->start) + 1)/*********************************************************************************** 名称 :isp1362_probe* 功能 :检测设备* 入口参数 :无* 出口参数 :无***********************************************************************************/static int __init isp1362_probe(struct device *dev){ struct usb_hcd *hcd; struct isp1362 *isp1362; struct platform_device *pdev; struct resource *addr, *data; void __iomem *addr_reg; void __iomem *data_reg; int irq; int ret = 0; pdev = container_of(dev, struct platform_device, dev); if (pdev->num_resources < 3) { ret = -ENODEV; goto err1; } data = platform_get_resource(pdev, IORESOURCE_MEM, 0); addr = platform_get_resource(pdev, IORESOURCE_MEM, 1); irq = platform_get_irq(pdev, 0); if (!addr || !data || irq < 0) { ret = -ENODEV; goto err1; } if (dev->dma_mask) { DBG("DMA not supported\n"); ret = -EINVAL; goto err1; } if (!request_mem_region(addr->start, 2, hcd_name)) { ret = -EBUSY; goto err1; } addr_reg = ioremap(addr->start, resource_len(addr)); if (addr_reg == NULL) { ret = -ENOMEM; goto err2; } if (!request_mem_region(data->start, 2, hcd_name)) { ret = -EBUSY; goto err3; } data_reg = ioremap(data->start, resource_len(data)); if (data_reg == NULL) { ret = -ENOMEM; goto err4; } /* allocate and initialize hcd */ hcd = usb_create_hcd(&isp1362_hc_driver, dev, dev->bus_id); if (!hcd) { ret = -ENOMEM; goto err5; } /* this rsrc_start is bogus */ hcd->rsrc_start = addr->start; isp1362 = hcd_to_isp1362(hcd); isp1362->data_reg = data_reg; isp1362->addr_reg = addr_reg; spin_lock_init(&isp1362->lock); INIT_LIST_HEAD(&isp1362->async);/// INIT_WORK(&isp1362->rh_resume, isp1362_rh_resume, hcd); isp1362->board = dev->platform_data; if (!isp1362->board) { ERR("Platform data structure not initialized\n"); ret = -ENODEV; goto err6; } if (isp1362_check_platform_delay(isp1362)) { ERR("USE_PLATFORM_DELAY defined, but delay function not " "implemented.\n"); ERR("See comments in drivers/usb/host/isp1362-hcd.c\n"); ret = -ENODEV; goto err6; } ret = usb_add_hcd(hcd, irq, SA_INTERRUPT); if (ret != 0) goto err6; create_debug_file(isp1362); return 0; err6: usb_put_hcd(hcd); err5: iounmap(data_reg); err4: release_mem_region(data->start, 2); err3: iounmap(addr_reg); err2: release_mem_region(addr->start, 2); err1: ERR("init error, %d\n", ret); return ret;}#ifdef CONFIG_PM/*********************************************************************************** 名称 :isp1362_suspend* 功能 :挂起设备* 入口参数 :无* 出口参数 :无***********************************************************************************/static int isp1362_suspend(struct device *dev, pm_message_t state, u32 phase){ int ret = 0; struct usb_hcd *hcd = dev_get_drvdata(dev); VDBG("%s: state %x, phase %x\n", __func__, state, phase); if (phase != SUSPEND_DISABLE && phase != SUSPEND_POWER_DOWN) return 0; ret = usb_suspend_device(hcd->self.root_hub, state); if (!ret) { dev->power.power_state = state; INFO("%s suspended\n", hcd_name); } else ERR("%s suspend failed\n", hcd_name); return ret;}/*********************************************************************************** 名称 :isp1362_resume* 功能 :重新连接设备* 入口参数 :无* 出口参数 :无***********************************************************************************/static int isp1362_resume(struct device *dev, u32 phase){ int ret = 0; struct usb_hcd *hcd = dev_get_drvdata(dev); VDBG("%s: state %x, phase %x\n", __func__, dev->power.power_state, phase); if (phase != RESUME_POWER_ON) return 0; ret = usb_resume_device(hcd->self.root_hub); if (!ret) { dev->power.power_state = PMSG_ON; VDBG("%s resumed\n", (char *)hcd_name); } return ret;}#else#define isp1362_suspend NULL#define isp1362_resume NULL#endifstatic struct device_driver isp1362_driver = { .name = (char *)hcd_name, .bus = &platform_bus_type, .probe = isp1362_probe, .remove = isp1362_remove, .suspend = isp1362_suspend, .resume = isp1362_resume,};/*-----------------------------------------------------------------*//*********************************************************************************** 名称 :isp1362_init* 功能 :ISP1362初始化* 入口参数 :无* 出口参数 :无***********************************************************************************/static int __init isp1362_init(void){ if (usb_disabled()) return -ENODEV; INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION); return driver_register(&isp1362_driver);}module_init(isp1362_init);/*********************************************************************************** 名称 :isp1362_cleanup* 功能 :清除ISP1362* 入口参数 :无* 出口参数 :无***********************************************************************************/static void __exit isp1362_cleanup(void){ driver_unregister(&isp1362_driver);}module_exit(isp1362_cleanup);#endif//motor
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -