gpio: rcar: Fix runtime PM imbalance on error
[linux/fpc-iii.git] / drivers / staging / greybus / usb.c
blob8e9d9d59a357385aa67e8fcd1ccc5d595eb69167
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * USB host driver for the Greybus "generic" USB module.
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 #include <linux/greybus.h>
15 #include "gbphy.h"
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
22 struct gb_usb_hub_control_request {
23 __le16 typeReq;
24 __le16 wValue;
25 __le16 wIndex;
26 __le16 wLength;
29 struct gb_usb_hub_control_response {
30 u8 buf[0];
33 struct gb_usb_device {
34 struct gb_connection *connection;
35 struct gbphy_device *gbphy_dev;
38 static inline struct gb_usb_device *to_gb_usb_device(struct usb_hcd *hcd)
40 return (struct gb_usb_device *)hcd->hcd_priv;
43 static inline struct usb_hcd *gb_usb_device_to_hcd(struct gb_usb_device *dev)
45 return container_of((void *)dev, struct usb_hcd, hcd_priv);
48 static void hcd_stop(struct usb_hcd *hcd)
50 struct gb_usb_device *dev = to_gb_usb_device(hcd);
51 int ret;
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);
59 static int hcd_start(struct usb_hcd *hcd)
61 struct usb_bus *bus = hcd_to_bus(hcd);
62 struct gb_usb_device *dev = to_gb_usb_device(hcd);
63 int ret;
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;
72 hcd->state = HC_STATE_RUNNING;
73 if (bus->root_hub)
74 usb_hcd_resume_root_hub(hcd);
75 return 0;
78 static int urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
80 return -ENXIO;
83 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
85 return -ENXIO;
88 static int get_frame_number(struct usb_hcd *hcd)
90 return 0;
93 static int hub_status_data(struct usb_hcd *hcd, char *buf)
95 return 0;
98 static int hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
99 char *buf, u16 wLength)
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;
108 /* FIXME: handle unspecified lengths */
109 response_size = sizeof(*response) + wLength;
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;
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);
125 ret = gb_operation_request_send_sync(operation);
126 if (ret)
127 goto out;
129 if (wLength) {
130 /* Greybus core has verified response size */
131 response = operation->response->payload;
132 memcpy(buf, response->buf, wLength);
134 out:
135 gb_operation_put(operation);
137 return ret;
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),
145 .flags = HCD_USB2,
147 .start = hcd_start,
148 .stop = hcd_stop,
150 .urb_enqueue = urb_enqueue,
151 .urb_dequeue = urb_dequeue,
153 .get_frame_number = get_frame_number,
154 .hub_status_data = hub_status_data,
155 .hub_control = hub_control,
158 static int gb_usb_probe(struct gbphy_device *gbphy_dev,
159 const struct gbphy_device_id *id)
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;
167 hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
168 if (!hcd)
169 return -ENOMEM;
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;
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);
185 hcd->has_tt = 1;
187 retval = gb_connection_enable(connection);
188 if (retval)
189 goto exit_connection_destroy;
192 * FIXME: The USB bridged-PHY protocol driver depends on changes to
193 * USB core which are not yet upstream.
195 * Disable for now.
197 if (1) {
198 dev_warn(dev, "USB protocol disabled\n");
199 retval = -EPROTONOSUPPORT;
200 goto exit_connection_disable;
203 retval = usb_add_hcd(hcd, 0, 0);
204 if (retval)
205 goto exit_connection_disable;
207 return 0;
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);
216 return retval;
219 static void gb_usb_remove(struct gbphy_device *gbphy_dev)
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);
225 usb_remove_hcd(hcd);
226 gb_connection_disable(connection);
227 gb_connection_destroy(connection);
228 usb_put_hcd(hcd);
231 static const struct gbphy_device_id gb_usb_id_table[] = {
232 { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_USB) },
233 { },
235 MODULE_DEVICE_TABLE(gbphy, gb_usb_id_table);
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,
244 module_gbphy_driver(usb_driver);
245 MODULE_LICENSE("GPL v2");