xref: /linux/drivers/staging/greybus/usb.c (revision 44f57d78)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * USB host driver for the Greybus "generic" USB module.
4  *
5  * Copyright 2014 Google Inc.
6  * Copyright 2014 Linaro Ltd.
7  */
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/slab.h>
11 #include <linux/usb.h>
12 #include <linux/usb/hcd.h>
13 
14 #include "greybus.h"
15 #include "gbphy.h"
16 
17 /* Greybus USB request types */
18 #define GB_USB_TYPE_HCD_START		0x02
19 #define GB_USB_TYPE_HCD_STOP		0x03
20 #define GB_USB_TYPE_HUB_CONTROL		0x04
21 
22 struct gb_usb_hub_control_request {
23 	__le16 typeReq;
24 	__le16 wValue;
25 	__le16 wIndex;
26 	__le16 wLength;
27 };
28 
29 struct gb_usb_hub_control_response {
30 	u8 buf[0];
31 };
32 
33 struct gb_usb_device {
34 	struct gb_connection *connection;
35 	struct gbphy_device *gbphy_dev;
36 };
37 
38 static inline struct gb_usb_device *to_gb_usb_device(struct usb_hcd *hcd)
39 {
40 	return (struct gb_usb_device *)hcd->hcd_priv;
41 }
42 
43 static inline struct usb_hcd *gb_usb_device_to_hcd(struct gb_usb_device *dev)
44 {
45 	return container_of((void *)dev, struct usb_hcd, hcd_priv);
46 }
47 
48 static void hcd_stop(struct usb_hcd *hcd)
49 {
50 	struct gb_usb_device *dev = to_gb_usb_device(hcd);
51 	int ret;
52 
53 	ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_STOP,
54 				NULL, 0, NULL, 0);
55 	if (ret)
56 		dev_err(&dev->gbphy_dev->dev, "HCD stop failed '%d'\n", ret);
57 }
58 
59 static int hcd_start(struct usb_hcd *hcd)
60 {
61 	struct usb_bus *bus = hcd_to_bus(hcd);
62 	struct gb_usb_device *dev = to_gb_usb_device(hcd);
63 	int ret;
64 
65 	ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_START,
66 				NULL, 0, NULL, 0);
67 	if (ret) {
68 		dev_err(&dev->gbphy_dev->dev, "HCD start failed '%d'\n", ret);
69 		return ret;
70 	}
71 
72 	hcd->state = HC_STATE_RUNNING;
73 	if (bus->root_hub)
74 		usb_hcd_resume_root_hub(hcd);
75 	return 0;
76 }
77 
78 static int urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
79 {
80 	return -ENXIO;
81 }
82 
83 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
84 {
85 	return -ENXIO;
86 }
87 
88 static int get_frame_number(struct usb_hcd *hcd)
89 {
90 	return 0;
91 }
92 
93 static int hub_status_data(struct usb_hcd *hcd, char *buf)
94 {
95 	return 0;
96 }
97 
98 static int hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
99 		       char *buf, u16 wLength)
100 {
101 	struct gb_usb_device *dev = to_gb_usb_device(hcd);
102 	struct gb_operation *operation;
103 	struct gb_usb_hub_control_request *request;
104 	struct gb_usb_hub_control_response *response;
105 	size_t response_size;
106 	int ret;
107 
108 	/* FIXME: handle unspecified lengths */
109 	response_size = sizeof(*response) + wLength;
110 
111 	operation = gb_operation_create(dev->connection,
112 					GB_USB_TYPE_HUB_CONTROL,
113 					sizeof(*request),
114 					response_size,
115 					GFP_KERNEL);
116 	if (!operation)
117 		return -ENOMEM;
118 
119 	request = operation->request->payload;
120 	request->typeReq = cpu_to_le16(typeReq);
121 	request->wValue = cpu_to_le16(wValue);
122 	request->wIndex = cpu_to_le16(wIndex);
123 	request->wLength = cpu_to_le16(wLength);
124 
125 	ret = gb_operation_request_send_sync(operation);
126 	if (ret)
127 		goto out;
128 
129 	if (wLength) {
130 		/* Greybus core has verified response size */
131 		response = operation->response->payload;
132 		memcpy(buf, response->buf, wLength);
133 	}
134 out:
135 	gb_operation_put(operation);
136 
137 	return ret;
138 }
139 
140 static const struct hc_driver usb_gb_hc_driver = {
141 	.description = "greybus-hcd",
142 	.product_desc = "Greybus USB Host Controller",
143 	.hcd_priv_size = sizeof(struct gb_usb_device),
144 
145 	.flags = HCD_USB2,
146 
147 	.start = hcd_start,
148 	.stop = hcd_stop,
149 
150 	.urb_enqueue = urb_enqueue,
151 	.urb_dequeue = urb_dequeue,
152 
153 	.get_frame_number = get_frame_number,
154 	.hub_status_data = hub_status_data,
155 	.hub_control = hub_control,
156 };
157 
158 static int gb_usb_probe(struct gbphy_device *gbphy_dev,
159 			const struct gbphy_device_id *id)
160 {
161 	struct gb_connection *connection;
162 	struct device *dev = &gbphy_dev->dev;
163 	struct gb_usb_device *gb_usb_dev;
164 	struct usb_hcd *hcd;
165 	int retval;
166 
167 	hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
168 	if (!hcd)
169 		return -ENOMEM;
170 
171 	connection = gb_connection_create(gbphy_dev->bundle,
172 					  le16_to_cpu(gbphy_dev->cport_desc->id),
173 					  NULL);
174 	if (IS_ERR(connection)) {
175 		retval = PTR_ERR(connection);
176 		goto exit_usb_put;
177 	}
178 
179 	gb_usb_dev = to_gb_usb_device(hcd);
180 	gb_usb_dev->connection = connection;
181 	gb_connection_set_data(connection, gb_usb_dev);
182 	gb_usb_dev->gbphy_dev = gbphy_dev;
183 	gb_gbphy_set_data(gbphy_dev, gb_usb_dev);
184 
185 	hcd->has_tt = 1;
186 
187 	retval = gb_connection_enable(connection);
188 	if (retval)
189 		goto exit_connection_destroy;
190 
191 	/*
192 	 * FIXME: The USB bridged-PHY protocol driver depends on changes to
193 	 *        USB core which are not yet upstream.
194 	 *
195 	 *        Disable for now.
196 	 */
197 	if (1) {
198 		dev_warn(dev, "USB protocol disabled\n");
199 		retval = -EPROTONOSUPPORT;
200 		goto exit_connection_disable;
201 	}
202 
203 	retval = usb_add_hcd(hcd, 0, 0);
204 	if (retval)
205 		goto exit_connection_disable;
206 
207 	return 0;
208 
209 exit_connection_disable:
210 	gb_connection_disable(connection);
211 exit_connection_destroy:
212 	gb_connection_destroy(connection);
213 exit_usb_put:
214 	usb_put_hcd(hcd);
215 
216 	return retval;
217 }
218 
219 static void gb_usb_remove(struct gbphy_device *gbphy_dev)
220 {
221 	struct gb_usb_device *gb_usb_dev = gb_gbphy_get_data(gbphy_dev);
222 	struct gb_connection *connection = gb_usb_dev->connection;
223 	struct usb_hcd *hcd = gb_usb_device_to_hcd(gb_usb_dev);
224 
225 	usb_remove_hcd(hcd);
226 	gb_connection_disable(connection);
227 	gb_connection_destroy(connection);
228 	usb_put_hcd(hcd);
229 }
230 
231 static const struct gbphy_device_id gb_usb_id_table[] = {
232 	{ GBPHY_PROTOCOL(GREYBUS_PROTOCOL_USB) },
233 	{ },
234 };
235 MODULE_DEVICE_TABLE(gbphy, gb_usb_id_table);
236 
237 static struct gbphy_driver usb_driver = {
238 	.name		= "usb",
239 	.probe		= gb_usb_probe,
240 	.remove		= gb_usb_remove,
241 	.id_table	= gb_usb_id_table,
242 };
243 
244 module_gbphy_driver(usb_driver);
245 MODULE_LICENSE("GPL v2");
246