1 // SPDX-License-Identifier: GPL-2.0
3 * Generic UHCI HCD (Host Controller Driver) for Platform Devices
5 * Copyright (c) 2011 Tony Prisk <linux@prisktech.co.nz>
7 * This file is based on uhci-grlib.c
8 * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
12 #include <linux/device.h>
13 #include <linux/platform_device.h>
15 static int uhci_platform_init(struct usb_hcd
*hcd
)
17 struct uhci_hcd
*uhci
= hcd_to_uhci(hcd
);
19 /* Probe number of ports if not already provided by DT */
20 if (!uhci
->rh_numports
)
21 uhci
->rh_numports
= uhci_count_ports(hcd
);
23 /* Set up pointers to to generic functions */
24 uhci
->reset_hc
= uhci_generic_reset_hc
;
25 uhci
->check_and_reset_hc
= uhci_generic_check_and_reset_hc
;
27 /* No special actions need to be taken for the functions below */
28 uhci
->configure_hc
= NULL
;
29 uhci
->resume_detect_interrupts_are_broken
= NULL
;
30 uhci
->global_suspend_mode_is_broken
= NULL
;
32 /* Reset if the controller isn't already safely quiescent. */
33 check_and_reset_hc(uhci
);
37 static const struct hc_driver uhci_platform_hc_driver
= {
38 .description
= hcd_name
,
39 .product_desc
= "Generic UHCI Host Controller",
40 .hcd_priv_size
= sizeof(struct uhci_hcd
),
42 /* Generic hardware linkage */
44 .flags
= HCD_MEMORY
| HCD_USB11
,
46 /* Basic lifecycle operations */
47 .reset
= uhci_platform_init
,
52 .bus_suspend
= uhci_rh_suspend
,
53 .bus_resume
= uhci_rh_resume
,
57 .urb_enqueue
= uhci_urb_enqueue
,
58 .urb_dequeue
= uhci_urb_dequeue
,
60 .endpoint_disable
= uhci_hcd_endpoint_disable
,
61 .get_frame_number
= uhci_hcd_get_frame_number
,
63 .hub_status_data
= uhci_hub_status_data
,
64 .hub_control
= uhci_hub_control
,
67 static int uhci_hcd_platform_probe(struct platform_device
*pdev
)
69 struct device_node
*np
= pdev
->dev
.of_node
;
71 struct uhci_hcd
*uhci
;
79 * Right now device-tree probed devices don't get dma_mask set.
80 * Since shared usb code relies on it, set it here for now.
81 * Once we have dma capability bindings this can go away.
83 ret
= dma_coerce_mask_and_coherent(&pdev
->dev
, DMA_BIT_MASK(32));
87 hcd
= usb_create_hcd(&uhci_platform_hc_driver
, &pdev
->dev
,
92 uhci
= hcd_to_uhci(hcd
);
94 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
95 hcd
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
96 if (IS_ERR(hcd
->regs
)) {
97 ret
= PTR_ERR(hcd
->regs
);
100 hcd
->rsrc_start
= res
->start
;
101 hcd
->rsrc_len
= resource_size(res
);
103 uhci
->regs
= hcd
->regs
;
105 /* Grab some things from the device-tree */
109 if (of_property_read_u32(np
, "#ports", &num_ports
) == 0) {
110 uhci
->rh_numports
= num_ports
;
112 "Detected %d ports from device-tree\n",
115 if (of_device_is_compatible(np
, "aspeed,ast2400-uhci") ||
116 of_device_is_compatible(np
, "aspeed,ast2500-uhci")) {
119 "Enabled Aspeed implementation workarounds\n");
123 /* Get and enable clock if any specified */
124 uhci
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
125 if (IS_ERR(uhci
->clk
)) {
126 ret
= PTR_ERR(uhci
->clk
);
129 ret
= clk_prepare_enable(uhci
->clk
);
131 dev_err(&pdev
->dev
, "Error couldn't enable clock (%d)\n", ret
);
135 ret
= usb_add_hcd(hcd
, pdev
->resource
[1].start
, IRQF_SHARED
);
139 device_wakeup_enable(hcd
->self
.controller
);
143 clk_disable_unprepare(uhci
->clk
);
150 static int uhci_hcd_platform_remove(struct platform_device
*pdev
)
152 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
153 struct uhci_hcd
*uhci
= hcd_to_uhci(hcd
);
155 clk_disable_unprepare(uhci
->clk
);
162 /* Make sure the controller is quiescent and that we're not using it
163 * any more. This is mainly for the benefit of programs which, like kexec,
164 * expect the hardware to be idle: not doing DMA or generating IRQs.
166 * This routine may be called in a damaged or failing kernel. Hence we
167 * do not acquire the spinlock before shutting down the controller.
169 static void uhci_hcd_platform_shutdown(struct platform_device
*op
)
171 struct usb_hcd
*hcd
= platform_get_drvdata(op
);
173 uhci_hc_died(hcd_to_uhci(hcd
));
176 static const struct of_device_id platform_uhci_ids
[] = {
177 { .compatible
= "generic-uhci", },
178 { .compatible
= "platform-uhci", },
181 MODULE_DEVICE_TABLE(of
, platform_uhci_ids
);
183 static struct platform_driver uhci_platform_driver
= {
184 .probe
= uhci_hcd_platform_probe
,
185 .remove
= uhci_hcd_platform_remove
,
186 .shutdown
= uhci_hcd_platform_shutdown
,
188 .name
= "platform-uhci",
189 .of_match_table
= platform_uhci_ids
,