| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <linux/of.h> |
| #include <linux/device.h> |
| #include <linux/platform_device.h> |
| |
| static int uhci_platform_init(struct usb_hcd *hcd) |
| { |
| <------>struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
| |
| <------> |
| <------>if (!uhci->rh_numports) |
| <------><------>uhci->rh_numports = uhci_count_ports(hcd); |
| |
| <------> |
| <------>uhci->reset_hc = uhci_generic_reset_hc; |
| <------>uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc; |
| |
| <------> |
| <------>uhci->configure_hc = NULL; |
| <------>uhci->resume_detect_interrupts_are_broken = NULL; |
| <------>uhci->global_suspend_mode_is_broken = NULL; |
| |
| <------> |
| <------>check_and_reset_hc(uhci); |
| <------>return 0; |
| } |
| |
| static const struct hc_driver uhci_platform_hc_driver = { |
| <------>.description = hcd_name, |
| <------>.product_desc = "Generic UHCI Host Controller", |
| <------>.hcd_priv_size = sizeof(struct uhci_hcd), |
| |
| <------> |
| <------>.irq = uhci_irq, |
| <------>.flags = HCD_MEMORY | HCD_DMA | HCD_USB11, |
| |
| <------> |
| <------>.reset = uhci_platform_init, |
| <------>.start = uhci_start, |
| #ifdef CONFIG_PM |
| <------>.pci_suspend = NULL, |
| <------>.pci_resume = NULL, |
| <------>.bus_suspend = uhci_rh_suspend, |
| <------>.bus_resume = uhci_rh_resume, |
| #endif |
| <------>.stop = uhci_stop, |
| |
| <------>.urb_enqueue = uhci_urb_enqueue, |
| <------>.urb_dequeue = uhci_urb_dequeue, |
| |
| <------>.endpoint_disable = uhci_hcd_endpoint_disable, |
| <------>.get_frame_number = uhci_hcd_get_frame_number, |
| |
| <------>.hub_status_data = uhci_hub_status_data, |
| <------>.hub_control = uhci_hub_control, |
| }; |
| |
| static int uhci_hcd_platform_probe(struct platform_device *pdev) |
| { |
| <------>struct device_node *np = pdev->dev.of_node; |
| <------>struct usb_hcd *hcd; |
| <------>struct uhci_hcd *uhci; |
| <------>struct resource *res; |
| <------>int ret; |
| |
| <------>if (usb_disabled()) |
| <------><------>return -ENODEV; |
| |
| <------> |
| <------> * Right now device-tree probed devices don't get dma_mask set. |
| <------> * Since shared usb code relies on it, set it here for now. |
| <------> * Once we have dma capability bindings this can go away. |
| <------> */ |
| <------>ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); |
| <------>if (ret) |
| <------><------>return ret; |
| |
| <------>hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev, |
| <------><------><------>pdev->name); |
| <------>if (!hcd) |
| <------><------>return -ENOMEM; |
| |
| <------>uhci = hcd_to_uhci(hcd); |
| |
| <------>res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| <------>hcd->regs = devm_ioremap_resource(&pdev->dev, res); |
| <------>if (IS_ERR(hcd->regs)) { |
| <------><------>ret = PTR_ERR(hcd->regs); |
| <------><------>goto err_rmr; |
| <------>} |
| <------>hcd->rsrc_start = res->start; |
| <------>hcd->rsrc_len = resource_size(res); |
| |
| <------>uhci->regs = hcd->regs; |
| |
| <------> |
| <------>if (np) { |
| <------><------>u32 num_ports; |
| |
| <------><------>if (of_property_read_u32(np, "#ports", &num_ports) == 0) { |
| <------><------><------>uhci->rh_numports = num_ports; |
| <------><------><------>dev_info(&pdev->dev, |
| <------><------><------><------>"Detected %d ports from device-tree\n", |
| <------><------><------><------>num_ports); |
| <------><------>} |
| <------><------>if (of_device_is_compatible(np, "aspeed,ast2400-uhci") || |
| <------><------> of_device_is_compatible(np, "aspeed,ast2500-uhci") || |
| <------><------> of_device_is_compatible(np, "aspeed,ast2600-uhci")) { |
| <------><------><------>uhci->is_aspeed = 1; |
| <------><------><------>dev_info(&pdev->dev, |
| <------><------><------><------> "Enabled Aspeed implementation workarounds\n"); |
| <------><------>} |
| <------>} |
| |
| <------> |
| <------>uhci->clk = devm_clk_get(&pdev->dev, NULL); |
| <------>if (IS_ERR(uhci->clk)) { |
| <------><------>ret = PTR_ERR(uhci->clk); |
| <------><------>goto err_rmr; |
| <------>} |
| <------>ret = clk_prepare_enable(uhci->clk); |
| <------>if (ret) { |
| <------><------>dev_err(&pdev->dev, "Error couldn't enable clock (%d)\n", ret); |
| <------><------>goto err_rmr; |
| <------>} |
| |
| <------>ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); |
| <------>if (ret) |
| <------><------>goto err_clk; |
| |
| <------>device_wakeup_enable(hcd->self.controller); |
| <------>return 0; |
| |
| err_clk: |
| <------>clk_disable_unprepare(uhci->clk); |
| err_rmr: |
| <------>usb_put_hcd(hcd); |
| |
| <------>return ret; |
| } |
| |
| static int uhci_hcd_platform_remove(struct platform_device *pdev) |
| { |
| <------>struct usb_hcd *hcd = platform_get_drvdata(pdev); |
| <------>struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
| |
| <------>clk_disable_unprepare(uhci->clk); |
| <------>usb_remove_hcd(hcd); |
| <------>usb_put_hcd(hcd); |
| |
| <------>return 0; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| static void uhci_hcd_platform_shutdown(struct platform_device *op) |
| { |
| <------>struct usb_hcd *hcd = platform_get_drvdata(op); |
| |
| <------>uhci_hc_died(hcd_to_uhci(hcd)); |
| } |
| |
| static const struct of_device_id platform_uhci_ids[] = { |
| <------>{ .compatible = "generic-uhci", }, |
| <------>{ .compatible = "platform-uhci", }, |
| <------>{} |
| }; |
| MODULE_DEVICE_TABLE(of, platform_uhci_ids); |
| |
| static struct platform_driver uhci_platform_driver = { |
| <------>.probe = uhci_hcd_platform_probe, |
| <------>.remove = uhci_hcd_platform_remove, |
| <------>.shutdown = uhci_hcd_platform_shutdown, |
| <------>.driver = { |
| <------><------>.name = "platform-uhci", |
| <------><------>.of_match_table = platform_uhci_ids, |
| <------>}, |
| }; |
| |