Commit | Line | Data |
---|---|---|
100d4597 TP |
1 | /* |
2 | * Generic UHCI HCD (Host Controller Driver) for Platform Devices | |
3 | * | |
4 | * Copyright (c) 2011 Tony Prisk <linux@prisktech.co.nz> | |
5 | * | |
6 | * This file is based on uhci-grlib.c | |
7 | * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu | |
8 | */ | |
9 | ||
10 | #include <linux/of.h> | |
96ae5713 | 11 | #include <linux/device.h> |
100d4597 TP |
12 | #include <linux/platform_device.h> |
13 | ||
14 | static int uhci_platform_init(struct usb_hcd *hcd) | |
15 | { | |
16 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | |
17 | ||
18 | uhci->rh_numports = uhci_count_ports(hcd); | |
19 | ||
20 | /* Set up pointers to to generic functions */ | |
21 | uhci->reset_hc = uhci_generic_reset_hc; | |
22 | uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc; | |
23 | ||
24 | /* No special actions need to be taken for the functions below */ | |
25 | uhci->configure_hc = NULL; | |
26 | uhci->resume_detect_interrupts_are_broken = NULL; | |
27 | uhci->global_suspend_mode_is_broken = NULL; | |
28 | ||
29 | /* Reset if the controller isn't already safely quiescent. */ | |
30 | check_and_reset_hc(uhci); | |
31 | return 0; | |
32 | } | |
33 | ||
34 | static const struct hc_driver uhci_platform_hc_driver = { | |
35 | .description = hcd_name, | |
36 | .product_desc = "Generic UHCI Host Controller", | |
37 | .hcd_priv_size = sizeof(struct uhci_hcd), | |
38 | ||
39 | /* Generic hardware linkage */ | |
40 | .irq = uhci_irq, | |
41 | .flags = HCD_MEMORY | HCD_USB11, | |
42 | ||
43 | /* Basic lifecycle operations */ | |
44 | .reset = uhci_platform_init, | |
45 | .start = uhci_start, | |
46 | #ifdef CONFIG_PM | |
47 | .pci_suspend = NULL, | |
48 | .pci_resume = NULL, | |
49 | .bus_suspend = uhci_rh_suspend, | |
50 | .bus_resume = uhci_rh_resume, | |
51 | #endif | |
52 | .stop = uhci_stop, | |
53 | ||
54 | .urb_enqueue = uhci_urb_enqueue, | |
55 | .urb_dequeue = uhci_urb_dequeue, | |
56 | ||
57 | .endpoint_disable = uhci_hcd_endpoint_disable, | |
58 | .get_frame_number = uhci_hcd_get_frame_number, | |
59 | ||
60 | .hub_status_data = uhci_hub_status_data, | |
61 | .hub_control = uhci_hub_control, | |
62 | }; | |
63 | ||
41ac7b3a | 64 | static int uhci_hcd_platform_probe(struct platform_device *pdev) |
100d4597 TP |
65 | { |
66 | struct usb_hcd *hcd; | |
67 | struct uhci_hcd *uhci; | |
68 | struct resource *res; | |
69 | int ret; | |
70 | ||
71 | if (usb_disabled()) | |
72 | return -ENODEV; | |
73 | ||
09eeffb7 TP |
74 | /* |
75 | * Right now device-tree probed devices don't get dma_mask set. | |
76 | * Since shared usb code relies on it, set it here for now. | |
77 | * Once we have dma capability bindings this can go away. | |
78 | */ | |
e1fd7341 | 79 | ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); |
22d9d8e8 RK |
80 | if (ret) |
81 | return ret; | |
09eeffb7 | 82 | |
100d4597 TP |
83 | hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev, |
84 | pdev->name); | |
85 | if (!hcd) | |
86 | return -ENOMEM; | |
87 | ||
88 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
96ae5713 HS |
89 | hcd->regs = devm_ioremap_resource(&pdev->dev, res); |
90 | if (IS_ERR(hcd->regs)) { | |
91 | ret = PTR_ERR(hcd->regs); | |
100d4597 TP |
92 | goto err_rmr; |
93 | } | |
6827f7e3 VB |
94 | hcd->rsrc_start = res->start; |
95 | hcd->rsrc_len = resource_size(res); | |
96 | ||
100d4597 TP |
97 | uhci = hcd_to_uhci(hcd); |
98 | ||
99 | uhci->regs = hcd->regs; | |
100 | ||
2b4ef839 | 101 | ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); |
100d4597 | 102 | if (ret) |
96ae5713 | 103 | goto err_rmr; |
100d4597 | 104 | |
3c9740a1 | 105 | device_wakeup_enable(hcd->self.controller); |
100d4597 TP |
106 | return 0; |
107 | ||
100d4597 TP |
108 | err_rmr: |
109 | usb_put_hcd(hcd); | |
110 | ||
111 | return ret; | |
112 | } | |
113 | ||
114 | static int uhci_hcd_platform_remove(struct platform_device *pdev) | |
115 | { | |
116 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | |
117 | ||
118 | usb_remove_hcd(hcd); | |
100d4597 | 119 | usb_put_hcd(hcd); |
100d4597 TP |
120 | |
121 | return 0; | |
122 | } | |
123 | ||
124 | /* Make sure the controller is quiescent and that we're not using it | |
125 | * any more. This is mainly for the benefit of programs which, like kexec, | |
126 | * expect the hardware to be idle: not doing DMA or generating IRQs. | |
127 | * | |
128 | * This routine may be called in a damaged or failing kernel. Hence we | |
129 | * do not acquire the spinlock before shutting down the controller. | |
130 | */ | |
131 | static void uhci_hcd_platform_shutdown(struct platform_device *op) | |
132 | { | |
477527ba | 133 | struct usb_hcd *hcd = platform_get_drvdata(op); |
100d4597 TP |
134 | |
135 | uhci_hc_died(hcd_to_uhci(hcd)); | |
136 | } | |
137 | ||
138 | static const struct of_device_id platform_uhci_ids[] = { | |
e16fa44b | 139 | { .compatible = "generic-uhci", }, |
100d4597 TP |
140 | { .compatible = "platform-uhci", }, |
141 | {} | |
142 | }; | |
e2f39511 | 143 | MODULE_DEVICE_TABLE(of, platform_uhci_ids); |
100d4597 TP |
144 | |
145 | static struct platform_driver uhci_platform_driver = { | |
146 | .probe = uhci_hcd_platform_probe, | |
147 | .remove = uhci_hcd_platform_remove, | |
148 | .shutdown = uhci_hcd_platform_shutdown, | |
149 | .driver = { | |
150 | .name = "platform-uhci", | |
5d689168 | 151 | .of_match_table = platform_uhci_ids, |
100d4597 TP |
152 | }, |
153 | }; |