#endif
static int rkehci_status = 1;
+static struct ehci_hcd *g_ehci;
+#define EHCI_PRINT(x...) printk( KERN_INFO "EHCI: " x )
+
+static struct rkehci_pdata_id rkehci_pdata[] = {
+ {
+ .name = "rk3188-reserved",
+ .pdata = NULL,
+ },
+ {
+ .name = "rk3288-ehci",
+ .pdata = &rkehci_pdata_rk3288,
+ },
+ { },
+};
+
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
{
+ unsigned port;
+
+ if (!HCS_PPC (ehci->hcs_params))
+ return;
+ ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down");
+ for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
+ (void) ehci_hub_control(ehci_to_hcd(ehci),
+ is_on ? SetPortFeature : ClearPortFeature,
+ USB_PORT_FEAT_POWER,
+ port--, NULL, 0);
+ /* Flush those writes */
+ ehci_readl(ehci, &ehci->regs->command);
+ msleep(20);
}
-static struct hc_driver rk_hc_driver = {
+static struct hc_driver rk_ehci_hc_driver = {
.description = hcd_name,
.product_desc = "Rockchip On-Chip EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
struct device_attribute *attr,
const char *buf, size_t count )
{
+ uint32_t val = simple_strtoul(buf, NULL, 16);
+ struct usb_hcd *hcd = dev_get_drvdata(_dev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct rkehci_platform_data *pldata = _dev->platform_data;
+
+ printk("%s: %d setting to: %d\n", __func__, rkehci_status, val);
+ if(val == rkehci_status)
+ goto out;
+
+ rkehci_status = val;
+ switch(val){
+ case 0: //power down
+ ehci_port_power(ehci, 0);
+ msleep(5);
+ usb_remove_hcd(hcd);
+ break;
+ case 1:// power on
+ pldata->soft_reset();
+ usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);
+ ehci_port_power(ehci, 1);
+ writel_relaxed(0x1d4d ,hcd->regs +0x90);
+ writel_relaxed(0x4 ,hcd->regs +0xa0);
+ dsb();
+ break;
+ default:
+ break;
+ }
+out:
return count;
}
static DEVICE_ATTR(ehci_power, S_IRUGO|S_IWUSR, ehci_power_show, ehci_power_store);
static ssize_t debug_show( struct device *_dev,
struct device_attribute *attr, char *buf)
{
+ volatile uint32_t *addr;
+
+ EHCI_PRINT("******** EHCI Capability Registers **********\n");
+ addr = &g_ehci->caps->hc_capbase;
+ EHCI_PRINT("HCIVERSION / CAPLENGTH @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+ addr = &g_ehci->caps->hcs_params;
+ EHCI_PRINT("HCSPARAMS @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+ addr = &g_ehci->caps->hcc_params;
+ EHCI_PRINT("HCCPARAMS @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+ EHCI_PRINT("********* EHCI Operational Registers *********\n");
+ addr = &g_ehci->regs->command;
+ EHCI_PRINT("USBCMD @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+ addr = &g_ehci->regs->status;
+ EHCI_PRINT("USBSTS @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+ addr = &g_ehci->regs->intr_enable;
+ EHCI_PRINT("USBINTR @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+ addr = &g_ehci->regs->frame_index;
+ EHCI_PRINT("FRINDEX @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+ addr = &g_ehci->regs->segment;
+ EHCI_PRINT("CTRLDSSEGMENT @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+ addr = &g_ehci->regs->frame_list;
+ EHCI_PRINT("PERIODICLISTBASE @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+ addr = &g_ehci->regs->async_next;
+ EHCI_PRINT("ASYNCLISTADDR @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+ addr = &g_ehci->regs->configured_flag;
+ EHCI_PRINT("CONFIGFLAG @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+ addr = g_ehci->regs->port_status;
+ EHCI_PRINT("PORTSC @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
return sprintf(buf, "EHCI Registers Dump\n");
}
static DEVICE_ATTR(debug_ehci, S_IRUGO, debug_show, NULL);
+
+static struct of_device_id rk_ehci_of_match[] = {
+ {
+ .compatible = "rockchip,rk3288_rk_ehci_host",
+ .data = &rkehci_pdata[RK3288_USB_CTLR],
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, rk_ehci_of_match);
+
static int ehci_rk_probe(struct platform_device *pdev)
{
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct rkehci_platform_data *pldata;
+ int ret;
+ int retval = 0;
+ static u64 usb_dmamask = 0xffffffffUL;
+ struct device_node *node = pdev->dev.of_node;
+ struct rkehci_pdata_id *p;
+ const struct of_device_id *match =
+ of_match_device(of_match_ptr( rk_ehci_of_match ), &pdev->dev);
+
dev_dbg(&pdev->dev, "ehci_rk proble\n");
+
+ if (match){
+ p = (struct rkehci_pdata_id *)match->data;
+ }else{
+ dev_err(dev, "ehci_rk match failed\n");
+ return -EINVAL;
+ }
+
+ dev->platform_data = p->pdata;
+ pldata = dev->platform_data;
+ pldata->dev = dev;
+
+ if (!node) {
+ dev_err(dev, "device node not found\n");
+ return -EINVAL;
+ }
+
+ dev->dma_mask = &usb_dmamask;
+
+ retval = device_create_file(dev, &dev_attr_ehci_power);
+ retval = device_create_file(dev, &dev_attr_debug_ehci);
+ hcd = usb_create_hcd(&rk_ehci_hc_driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd) {
+ dev_err(&pdev->dev, "Unable to create HCD\n");
+ return -ENOMEM;
+ }
+
+ if(pldata->hw_init)
+ pldata->hw_init();
+
+ if(pldata->clock_init){
+ pldata->clock_init(pldata);
+ pldata->clock_enable(pldata, 1);
+ }
+
+ if(pldata->soft_reset)
+ pldata->soft_reset();
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get memory resource\n");
+ ret = -ENODEV;
+ goto put_hcd;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+ hcd->regs = devm_ioremap_resource(dev, res);
+
+ if (!hcd->regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto put_hcd;
+ }
+
+ hcd->irq = platform_get_irq(pdev, 0);
+ if (hcd->irq < 0) {
+ dev_err(&pdev->dev, "Unable to get IRQ resource\n");
+ ret = hcd->irq;
+ goto put_hcd;
+ }
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + 0x10;
+ printk("%s %p %p\n", __func__, ehci->caps, ehci->regs);
+
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+ ret = usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add USB HCD\n");
+ goto put_hcd;
+ }
+
+ g_ehci = ehci;
+ ehci_port_power(ehci, 1);
+ writel_relaxed(0x1d4d ,hcd->regs +0x90);
+ writel_relaxed(0x4 ,hcd->regs +0xa0);
+ dsb();
+
+ printk("%s ok\n", __func__);
+
return 0;
+
+put_hcd:
+ if(pldata->clock_enable)
+ pldata->clock_enable(pldata, 0);
+ usb_put_hcd(hcd);
+
+ return ret;
}
static int ehci_rk_remove(struct platform_device *pdev)
{
.resume = ehci_rk_pm_resume,
};
-static struct of_device_id rk_ehci_of_match[] = {
- { .compatible = "rockchip,rk_ehci_host", },
- { },
-};
-
-MODULE_DEVICE_TABLE(of, rk_ehci_of_match);
-
static struct platform_driver ehci_rk_driver = {
.probe = ehci_rk_probe,
.remove = ehci_rk_remove,