xref: /linux/drivers/usb/host/uhci-platform.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
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>
11 #include <linux/device.h>
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 
64 static int uhci_hcd_platform_probe(struct platform_device *pdev)
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 
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 	 */
79 	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
80 	if (ret)
81 		return ret;
82 
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);
89 	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
90 	if (IS_ERR(hcd->regs)) {
91 		ret = PTR_ERR(hcd->regs);
92 		goto err_rmr;
93 	}
94 	hcd->rsrc_start = res->start;
95 	hcd->rsrc_len = resource_size(res);
96 
97 	uhci = hcd_to_uhci(hcd);
98 
99 	uhci->regs = hcd->regs;
100 
101 	ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED);
102 	if (ret)
103 		goto err_rmr;
104 
105 	device_wakeup_enable(hcd->self.controller);
106 	return 0;
107 
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);
119 	usb_put_hcd(hcd);
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 {
133 	struct usb_hcd *hcd = platform_get_drvdata(op);
134 
135 	uhci_hc_died(hcd_to_uhci(hcd));
136 }
137 
138 static const struct of_device_id platform_uhci_ids[] = {
139 	{ .compatible = "generic-uhci", },
140 	{ .compatible = "platform-uhci", },
141 	{}
142 };
143 
144 static struct platform_driver uhci_platform_driver = {
145 	.probe		= uhci_hcd_platform_probe,
146 	.remove		= uhci_hcd_platform_remove,
147 	.shutdown	= uhci_hcd_platform_shutdown,
148 	.driver = {
149 		.name = "platform-uhci",
150 		.of_match_table = platform_uhci_ids,
151 	},
152 };
153