2 * USB host driver for the Greybus "generic" USB module.
4 * Copyright 2014 Google Inc.
5 * Copyright 2014 Linaro Ltd.
7 * Released under the GPLv2 only.
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/usb.h>
14 #include <linux/usb/hcd.h>
19 /* Greybus USB request types */
20 #define GB_USB_TYPE_HCD_START 0x02
21 #define GB_USB_TYPE_HCD_STOP 0x03
22 #define GB_USB_TYPE_HUB_CONTROL 0x04
24 struct gb_usb_hub_control_request {
31 struct gb_usb_hub_control_response {
35 struct gb_usb_device {
36 struct gb_connection *connection;
37 struct gbphy_device *gbphy_dev;
40 static inline struct gb_usb_device *to_gb_usb_device(struct usb_hcd *hcd)
42 return (struct gb_usb_device *)hcd->hcd_priv;
45 static inline struct usb_hcd *gb_usb_device_to_hcd(struct gb_usb_device *dev)
47 return container_of((void *)dev, struct usb_hcd, hcd_priv);
50 static void hcd_stop(struct usb_hcd *hcd)
52 struct gb_usb_device *dev = to_gb_usb_device(hcd);
55 ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_STOP,
58 dev_err(&dev->gbphy_dev->dev, "HCD stop failed '%d'\n", ret);
61 static int hcd_start(struct usb_hcd *hcd)
63 struct usb_bus *bus = hcd_to_bus(hcd);
64 struct gb_usb_device *dev = to_gb_usb_device(hcd);
67 ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_START,
70 dev_err(&dev->gbphy_dev->dev, "HCD start failed '%d'\n", ret);
74 hcd->state = HC_STATE_RUNNING;
76 usb_hcd_resume_root_hub(hcd);
80 static int urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
85 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
90 static int get_frame_number(struct usb_hcd *hcd)
95 static int hub_status_data(struct usb_hcd *hcd, char *buf)
100 static int hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
101 char *buf, u16 wLength)
103 struct gb_usb_device *dev = to_gb_usb_device(hcd);
104 struct gb_operation *operation;
105 struct gb_usb_hub_control_request *request;
106 struct gb_usb_hub_control_response *response;
107 size_t response_size;
110 /* FIXME: handle unspecified lengths */
111 response_size = sizeof(*response) + wLength;
113 operation = gb_operation_create(dev->connection,
114 GB_USB_TYPE_HUB_CONTROL,
121 request = operation->request->payload;
122 request->typeReq = cpu_to_le16(typeReq);
123 request->wValue = cpu_to_le16(wValue);
124 request->wIndex = cpu_to_le16(wIndex);
125 request->wLength = cpu_to_le16(wLength);
127 ret = gb_operation_request_send_sync(operation);
132 /* Greybus core has verified response size */
133 response = operation->response->payload;
134 memcpy(buf, response->buf, wLength);
137 gb_operation_put(operation);
142 static const struct hc_driver usb_gb_hc_driver = {
143 .description = "greybus-hcd",
144 .product_desc = "Greybus USB Host Controller",
145 .hcd_priv_size = sizeof(struct gb_usb_device),
152 .urb_enqueue = urb_enqueue,
153 .urb_dequeue = urb_dequeue,
155 .get_frame_number = get_frame_number,
156 .hub_status_data = hub_status_data,
157 .hub_control = hub_control,
160 static int gb_usb_probe(struct gbphy_device *gbphy_dev,
161 const struct gbphy_device_id *id)
163 struct gb_connection *connection;
164 struct device *dev = &gbphy_dev->dev;
165 struct gb_usb_device *gb_usb_dev;
169 hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
173 connection = gb_connection_create(gbphy_dev->bundle,
174 le16_to_cpu(gbphy_dev->cport_desc->id),
176 if (IS_ERR(connection)) {
177 retval = PTR_ERR(connection);
181 gb_usb_dev = to_gb_usb_device(hcd);
182 gb_usb_dev->connection = connection;
183 gb_connection_set_data(connection, gb_usb_dev);
184 gb_usb_dev->gbphy_dev = gbphy_dev;
185 gb_gbphy_set_data(gbphy_dev, gb_usb_dev);
189 retval = gb_connection_enable(connection);
191 goto exit_connection_destroy;
194 * FIXME: The USB bridged-PHY protocol driver depends on changes to
195 * USB core which are not yet upstream.
200 dev_warn(dev, "USB protocol disabled\n");
201 retval = -EPROTONOSUPPORT;
202 goto exit_connection_disable;
205 retval = usb_add_hcd(hcd, 0, 0);
207 goto exit_connection_disable;
211 exit_connection_disable:
212 gb_connection_disable(connection);
213 exit_connection_destroy:
214 gb_connection_destroy(connection);
221 static void gb_usb_remove(struct gbphy_device *gbphy_dev)
223 struct gb_usb_device *gb_usb_dev = gb_gbphy_get_data(gbphy_dev);
224 struct gb_connection *connection = gb_usb_dev->connection;
225 struct usb_hcd *hcd = gb_usb_device_to_hcd(gb_usb_dev);
228 gb_connection_disable(connection);
229 gb_connection_destroy(connection);
233 static const struct gbphy_device_id gb_usb_id_table[] = {
234 { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_USB) },
237 MODULE_DEVICE_TABLE(gbphy, gb_usb_id_table);
239 static struct gbphy_driver usb_driver = {
241 .probe = gb_usb_probe,
242 .remove = gb_usb_remove,
243 .id_table = gb_usb_id_table,
246 module_gbphy_driver(usb_driver);
247 MODULE_LICENSE("GPL v2");