1 // SPDX-License-Identifier: GPL-2.0
3 * Wireless Host Controller (WHC) driver.
5 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
7 #include <linux/kernel.h>
8 #include <linux/init.h>
9 #include <linux/module.h>
10 #include <linux/uwb/umc.h>
12 #include "../../wusbcore/wusbhc.h"
17 * One time initialization.
21 static int whc_reset(struct usb_hcd
*usb_hcd
)
27 * Start the wireless host controller.
29 * Start device notification.
31 * Put hc into run state, set DNTS parameters.
33 static int whc_start(struct usb_hcd
*usb_hcd
)
35 struct wusbhc
*wusbhc
= usb_hcd_to_wusbhc(usb_hcd
);
36 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
40 mutex_lock(&wusbhc
->mutex
);
42 le_writel(WUSBINTR_GEN_CMD_DONE
44 | WUSBINTR_ASYNC_SCHED_SYNCED
48 whc
->base
+ WUSBINTR
);
51 bcid
= wusb_cluster_id_get();
52 ret
= whc_set_cluster_id(whc
, bcid
);
55 wusbhc
->cluster_id
= bcid
;
58 whc_write_wusbcmd(whc
, WUSBCMD_RUN
, WUSBCMD_RUN
);
60 usb_hcd
->uses_new_polling
= 1;
61 set_bit(HCD_FLAG_POLL_RH
, &usb_hcd
->flags
);
62 usb_hcd
->state
= HC_STATE_RUNNING
;
65 mutex_unlock(&wusbhc
->mutex
);
71 * Stop the wireless host controller.
73 * Stop device notification.
75 * Wait for pending transfer to stop? Put hc into stop state?
77 static void whc_stop(struct usb_hcd
*usb_hcd
)
79 struct wusbhc
*wusbhc
= usb_hcd_to_wusbhc(usb_hcd
);
80 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
82 mutex_lock(&wusbhc
->mutex
);
85 le_writel(0, whc
->base
+ WUSBINTR
);
86 whc_write_wusbcmd(whc
, WUSBCMD_RUN
, 0);
87 whci_wait_for(&whc
->umc
->dev
, whc
->base
+ WUSBSTS
,
88 WUSBSTS_HCHALTED
, WUSBSTS_HCHALTED
,
91 wusb_cluster_id_put(wusbhc
->cluster_id
);
93 mutex_unlock(&wusbhc
->mutex
);
96 static int whc_get_frame_number(struct usb_hcd
*usb_hcd
)
98 /* Frame numbers are not applicable to WUSB. */
104 * Queue an URB to the ASL or PZL
106 static int whc_urb_enqueue(struct usb_hcd
*usb_hcd
, struct urb
*urb
,
109 struct wusbhc
*wusbhc
= usb_hcd_to_wusbhc(usb_hcd
);
110 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
113 switch (usb_pipetype(urb
->pipe
)) {
115 ret
= pzl_urb_enqueue(whc
, urb
, mem_flags
);
117 case PIPE_ISOCHRONOUS
:
118 dev_err(&whc
->umc
->dev
, "isochronous transfers unsupported\n");
124 ret
= asl_urb_enqueue(whc
, urb
, mem_flags
);
132 * Remove a queued URB from the ASL or PZL.
134 static int whc_urb_dequeue(struct usb_hcd
*usb_hcd
, struct urb
*urb
, int status
)
136 struct wusbhc
*wusbhc
= usb_hcd_to_wusbhc(usb_hcd
);
137 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
140 switch (usb_pipetype(urb
->pipe
)) {
142 ret
= pzl_urb_dequeue(whc
, urb
, status
);
144 case PIPE_ISOCHRONOUS
:
150 ret
= asl_urb_dequeue(whc
, urb
, status
);
158 * Wait for all URBs to the endpoint to be completed, then delete the
161 static void whc_endpoint_disable(struct usb_hcd
*usb_hcd
,
162 struct usb_host_endpoint
*ep
)
164 struct wusbhc
*wusbhc
= usb_hcd_to_wusbhc(usb_hcd
);
165 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
166 struct whc_qset
*qset
;
171 if (usb_endpoint_xfer_bulk(&ep
->desc
)
172 || usb_endpoint_xfer_control(&ep
->desc
))
173 asl_qset_delete(whc
, qset
);
175 pzl_qset_delete(whc
, qset
);
179 static void whc_endpoint_reset(struct usb_hcd
*usb_hcd
,
180 struct usb_host_endpoint
*ep
)
182 struct wusbhc
*wusbhc
= usb_hcd_to_wusbhc(usb_hcd
);
183 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
184 struct whc_qset
*qset
;
187 spin_lock_irqsave(&whc
->lock
, flags
);
194 if (usb_endpoint_xfer_bulk(&ep
->desc
)
195 || usb_endpoint_xfer_control(&ep
->desc
))
196 queue_work(whc
->workqueue
, &whc
->async_work
);
198 queue_work(whc
->workqueue
, &whc
->periodic_work
);
201 spin_unlock_irqrestore(&whc
->lock
, flags
);
205 static const struct hc_driver whc_hc_driver
= {
206 .description
= "whci-hcd",
207 .product_desc
= "Wireless host controller",
208 .hcd_priv_size
= sizeof(struct whc
) - sizeof(struct usb_hcd
),
209 .irq
= whc_int_handler
,
215 .get_frame_number
= whc_get_frame_number
,
216 .urb_enqueue
= whc_urb_enqueue
,
217 .urb_dequeue
= whc_urb_dequeue
,
218 .endpoint_disable
= whc_endpoint_disable
,
219 .endpoint_reset
= whc_endpoint_reset
,
221 .hub_status_data
= wusbhc_rh_status_data
,
222 .hub_control
= wusbhc_rh_control
,
223 .start_port_reset
= wusbhc_rh_start_port_reset
,
226 static int whc_probe(struct umc_dev
*umc
)
229 struct usb_hcd
*usb_hcd
;
230 struct wusbhc
*wusbhc
;
232 struct device
*dev
= &umc
->dev
;
234 usb_hcd
= usb_create_hcd(&whc_hc_driver
, dev
, "whci");
235 if (usb_hcd
== NULL
) {
236 dev_err(dev
, "unable to create hcd\n");
240 usb_hcd
->wireless
= 1;
241 usb_hcd
->self
.sg_tablesize
= 2048; /* somewhat arbitrary */
243 wusbhc
= usb_hcd_to_wusbhc(usb_hcd
);
244 whc
= wusbhc_to_whc(wusbhc
);
252 wusbhc
->uwb_rc
= uwb_rc_get_by_grandpa(umc
->dev
.parent
);
253 if (!wusbhc
->uwb_rc
) {
255 dev_err(dev
, "cannot get radio controller\n");
259 if (whc
->n_devices
> USB_MAXCHILDREN
) {
260 dev_warn(dev
, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n",
262 wusbhc
->ports_max
= USB_MAXCHILDREN
;
264 wusbhc
->ports_max
= whc
->n_devices
;
265 wusbhc
->mmcies_max
= whc
->n_mmc_ies
;
266 wusbhc
->start
= whc_wusbhc_start
;
267 wusbhc
->stop
= whc_wusbhc_stop
;
268 wusbhc
->mmcie_add
= whc_mmcie_add
;
269 wusbhc
->mmcie_rm
= whc_mmcie_rm
;
270 wusbhc
->dev_info_set
= whc_dev_info_set
;
271 wusbhc
->bwa_set
= whc_bwa_set
;
272 wusbhc
->set_num_dnts
= whc_set_num_dnts
;
273 wusbhc
->set_ptk
= whc_set_ptk
;
274 wusbhc
->set_gtk
= whc_set_gtk
;
276 ret
= wusbhc_create(wusbhc
);
278 goto error_wusbhc_create
;
280 ret
= usb_add_hcd(usb_hcd
, whc
->umc
->irq
, IRQF_SHARED
);
282 dev_err(dev
, "cannot add HCD: %d\n", ret
);
283 goto error_usb_add_hcd
;
285 device_wakeup_enable(usb_hcd
->self
.controller
);
287 ret
= wusbhc_b_create(wusbhc
);
289 dev_err(dev
, "WUSBHC phase B setup failed: %d\n", ret
);
290 goto error_wusbhc_b_create
;
297 error_wusbhc_b_create
:
298 usb_remove_hcd(usb_hcd
);
300 wusbhc_destroy(wusbhc
);
302 uwb_rc_put(wusbhc
->uwb_rc
);
306 usb_put_hcd(usb_hcd
);
311 static void whc_remove(struct umc_dev
*umc
)
313 struct usb_hcd
*usb_hcd
= dev_get_drvdata(&umc
->dev
);
314 struct wusbhc
*wusbhc
= usb_hcd_to_wusbhc(usb_hcd
);
315 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
318 whc_dbg_clean_up(whc
);
319 wusbhc_b_destroy(wusbhc
);
320 usb_remove_hcd(usb_hcd
);
321 wusbhc_destroy(wusbhc
);
322 uwb_rc_put(wusbhc
->uwb_rc
);
324 usb_put_hcd(usb_hcd
);
328 static struct umc_driver whci_hc_driver
= {
330 .cap_id
= UMC_CAP_ID_WHCI_WUSB_HC
,
332 .remove
= whc_remove
,
335 static int __init
whci_hc_driver_init(void)
337 return umc_driver_register(&whci_hc_driver
);
339 module_init(whci_hc_driver_init
);
341 static void __exit
whci_hc_driver_exit(void)
343 umc_driver_unregister(&whci_hc_driver
);
345 module_exit(whci_hc_driver_exit
);
347 /* PCI device ID's that we handle (so it gets loaded) */
348 static struct pci_device_id __used whci_hcd_id_table
[] = {
349 { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI
, ~0) },
350 { /* empty last entry */ }
352 MODULE_DEVICE_TABLE(pci
, whci_hcd_id_table
);
354 MODULE_DESCRIPTION("WHCI Wireless USB host controller driver");
355 MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
356 MODULE_LICENSE("GPL");