blob: ccadda084b766e864104c33efd88cf1b62ae831e [file] [log] [blame]
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -08001/*
2 * USB host driver for the Greybus "generic" USB module.
3 *
4 * Copyright 2014 Google Inc.
Alex Eldera46e9672014-12-12 12:08:42 -06005 * Copyright 2014 Linaro Ltd.
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -08006 *
7 * Released under the GPLv2 only.
8 *
9 */
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>
15
16#include "greybus.h"
Sandeep Patile54b1062016-05-19 08:52:39 -070017#include "gbphy.h"
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080018
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080019/* Greybus USB request types */
Johan Hovold583804f2015-07-30 20:30:37 +020020#define GB_USB_TYPE_HCD_START 0x02
21#define GB_USB_TYPE_HCD_STOP 0x03
22#define GB_USB_TYPE_HUB_CONTROL 0x04
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080023
24struct gb_usb_hub_control_request {
25 __le16 typeReq;
26 __le16 wValue;
27 __le16 wIndex;
28 __le16 wLength;
29};
30
31struct gb_usb_hub_control_response {
32 u8 buf[0];
33};
34
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080035struct gb_usb_device {
36 struct gb_connection *connection;
Sandeep Patile54b1062016-05-19 08:52:39 -070037 struct gbphy_device *gbphy_dev;
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080038};
39
Johan Hovoldcc9bd532015-07-30 20:30:38 +020040static inline struct gb_usb_device *to_gb_usb_device(struct usb_hcd *hcd)
41{
42 return (struct gb_usb_device *)hcd->hcd_priv;
43}
44
45static inline struct usb_hcd *gb_usb_device_to_hcd(struct gb_usb_device *dev)
46{
47 return container_of((void *)dev, struct usb_hcd, hcd_priv);
48}
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080049
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080050static void hcd_stop(struct usb_hcd *hcd)
51{
52 struct gb_usb_device *dev = to_gb_usb_device(hcd);
53 int ret;
54
55 ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_STOP,
56 NULL, 0, NULL, 0);
57 if (ret)
Sandeep Patile54b1062016-05-19 08:52:39 -070058 dev_err(&dev->gbphy_dev->dev, "HCD stop failed '%d'\n", ret);
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080059}
60
61static int hcd_start(struct usb_hcd *hcd)
62{
63 struct usb_bus *bus = hcd_to_bus(hcd);
64 struct gb_usb_device *dev = to_gb_usb_device(hcd);
65 int ret;
66
67 ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_START,
68 NULL, 0, NULL, 0);
69 if (ret) {
Sandeep Patile54b1062016-05-19 08:52:39 -070070 dev_err(&dev->gbphy_dev->dev, "HCD start failed '%d'\n", ret);
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080071 return ret;
72 }
73
74 hcd->state = HC_STATE_RUNNING;
75 if (bus->root_hub)
76 usb_hcd_resume_root_hub(hcd);
77 return 0;
78}
79
80static int urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
81{
Johan Hovold3a6b5ae2015-07-30 20:30:36 +020082 return -ENXIO;
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080083}
84
85static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
86{
Johan Hovold3a6b5ae2015-07-30 20:30:36 +020087 return -ENXIO;
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080088}
89
90static int get_frame_number(struct usb_hcd *hcd)
91{
Johan Hovold3a6b5ae2015-07-30 20:30:36 +020092 return 0;
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080093}
94
95static int hub_status_data(struct usb_hcd *hcd, char *buf)
96{
Johan Hovold3a6b5ae2015-07-30 20:30:36 +020097 return 0;
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -080098}
99
100static int hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
101 char *buf, u16 wLength)
102{
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800103 struct gb_usb_device *dev = to_gb_usb_device(hcd);
Johan Hovolda422ecd2015-07-30 20:30:40 +0200104 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;
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800108 int ret;
109
Johan Hovolda422ecd2015-07-30 20:30:40 +0200110 /* FIXME: handle unspecified lengths */
111 response_size = sizeof(*response) + wLength;
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800112
Johan Hovolda422ecd2015-07-30 20:30:40 +0200113 operation = gb_operation_create(dev->connection,
114 GB_USB_TYPE_HUB_CONTROL,
115 sizeof(*request),
116 response_size,
117 GFP_KERNEL);
118 if (!operation)
119 return -ENOMEM;
120
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);
126
127 ret = gb_operation_request_send_sync(operation);
128 if (ret)
129 goto out;
130
131 if (wLength) {
132 /* Greybus core has verified response size */
133 response = operation->response->payload;
134 memcpy(buf, response->buf, wLength);
135 }
136out:
137 gb_operation_put(operation);
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800138
139 return ret;
140}
141
142static struct hc_driver usb_gb_hc_driver = {
Johan Hovoldb1e4a1f2015-07-30 20:30:39 +0200143 .description = "greybus-hcd",
144 .product_desc = "Greybus USB Host Controller",
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800145 .hcd_priv_size = sizeof(struct gb_usb_device),
146
Johan Hovoldb1e4a1f2015-07-30 20:30:39 +0200147 .flags = HCD_USB2,
148
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800149 .start = hcd_start,
150 .stop = hcd_stop,
Johan Hovold3a6b5ae2015-07-30 20:30:36 +0200151
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800152 .urb_enqueue = urb_enqueue,
153 .urb_dequeue = urb_dequeue,
Johan Hovold3a6b5ae2015-07-30 20:30:36 +0200154
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800155 .get_frame_number = get_frame_number,
156 .hub_status_data = hub_status_data,
157 .hub_control = hub_control,
158};
159
Sandeep Patile54b1062016-05-19 08:52:39 -0700160static int gb_usb_probe(struct gbphy_device *gbphy_dev,
161 const struct gbphy_device_id *id)
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800162{
Greg Kroah-Hartman4dda7e92016-05-05 14:32:36 +0530163 struct gb_connection *connection;
Sandeep Patile54b1062016-05-19 08:52:39 -0700164 struct device *dev = &gbphy_dev->dev;
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800165 struct gb_usb_device *gb_usb_dev;
Johan Hovoldcc9bd532015-07-30 20:30:38 +0200166 struct usb_hcd *hcd;
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800167 int retval;
168
Johan Hovoldcc9bd532015-07-30 20:30:38 +0200169 hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
170 if (!hcd)
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800171 return -ENOMEM;
172
Sandeep Patile54b1062016-05-19 08:52:39 -0700173 connection = gb_connection_create(gbphy_dev->bundle,
174 le16_to_cpu(gbphy_dev->cport_desc->id),
Greg Kroah-Hartman4dda7e92016-05-05 14:32:36 +0530175 NULL);
176 if (IS_ERR(connection)) {
177 retval = PTR_ERR(connection);
178 goto exit_usb_put;
179 }
180
Johan Hovoldcc9bd532015-07-30 20:30:38 +0200181 gb_usb_dev = to_gb_usb_device(hcd);
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800182 gb_usb_dev->connection = connection;
Greg Kroah-Hartman0ec30632016-03-22 14:30:35 -0400183 gb_connection_set_data(connection, gb_usb_dev);
Sandeep Patile54b1062016-05-19 08:52:39 -0700184 gb_usb_dev->gbphy_dev = gbphy_dev;
185 gb_gbphy_set_data(gbphy_dev, gb_usb_dev);
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800186
Johan Hovoldcc9bd532015-07-30 20:30:38 +0200187 hcd->has_tt = 1;
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800188
Greg Kroah-Hartman4dda7e92016-05-05 14:32:36 +0530189 retval = gb_connection_enable(connection);
190 if (retval)
191 goto exit_connection_destroy;
192
Johan Hovolda9649352015-07-30 20:30:41 +0200193 /*
194 * FIXME: The USB bridged-PHY protocol driver depends on changes to
195 * USB core which are not yet upstream.
196 *
197 * Disable for now.
198 */
199 if (1) {
Greg Kroah-Hartmandfdc6e12015-10-14 11:20:00 -0700200 dev_warn(dev, "USB protocol disabled\n");
Johan Hovolda9649352015-07-30 20:30:41 +0200201 retval = -EPROTONOSUPPORT;
Greg Kroah-Hartman4dda7e92016-05-05 14:32:36 +0530202 goto exit_connection_disable;
Johan Hovolda9649352015-07-30 20:30:41 +0200203 }
204
Johan Hovoldcc9bd532015-07-30 20:30:38 +0200205 retval = usb_add_hcd(hcd, 0, 0);
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800206 if (retval)
Greg Kroah-Hartman4dda7e92016-05-05 14:32:36 +0530207 goto exit_connection_disable;
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800208
209 return 0;
Johan Hovoldcc9bd532015-07-30 20:30:38 +0200210
Greg Kroah-Hartman4dda7e92016-05-05 14:32:36 +0530211exit_connection_disable:
212 gb_connection_disable(connection);
213exit_connection_destroy:
214 gb_connection_destroy(connection);
215exit_usb_put:
Johan Hovoldcc9bd532015-07-30 20:30:38 +0200216 usb_put_hcd(hcd);
217
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800218 return retval;
219}
220
Sandeep Patile54b1062016-05-19 08:52:39 -0700221static void gb_usb_remove(struct gbphy_device *gbphy_dev)
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800222{
Sandeep Patile54b1062016-05-19 08:52:39 -0700223 struct gb_usb_device *gb_usb_dev = gb_gbphy_get_data(gbphy_dev);
Greg Kroah-Hartman4dda7e92016-05-05 14:32:36 +0530224 struct gb_connection *connection = gb_usb_dev->connection;
Johan Hovoldcc9bd532015-07-30 20:30:38 +0200225 struct usb_hcd *hcd = gb_usb_device_to_hcd(gb_usb_dev);
226
227 usb_remove_hcd(hcd);
Greg Kroah-Hartman4dda7e92016-05-05 14:32:36 +0530228 gb_connection_disable(connection);
229 gb_connection_destroy(connection);
Johan Hovoldcc9bd532015-07-30 20:30:38 +0200230 usb_put_hcd(hcd);
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800231}
232
Sandeep Patile54b1062016-05-19 08:52:39 -0700233static const struct gbphy_device_id gb_usb_id_table[] = {
234 { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_USB) },
Greg Kroah-Hartman4dda7e92016-05-05 14:32:36 +0530235 { },
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800236};
Sandeep Patile54b1062016-05-19 08:52:39 -0700237MODULE_DEVICE_TABLE(gbphy, gb_usb_id_table);
Greg Kroah-Hartman615772a2014-11-25 16:59:21 -0800238
Sandeep Patile54b1062016-05-19 08:52:39 -0700239static struct gbphy_driver usb_driver = {
Greg Kroah-Hartman4dda7e92016-05-05 14:32:36 +0530240 .name = "usb",
241 .probe = gb_usb_probe,
242 .remove = gb_usb_remove,
243 .id_table = gb_usb_id_table,
244};
Viresh Kumarea7c4772016-05-09 18:15:12 +0530245
Sandeep Patile54b1062016-05-19 08:52:39 -0700246module_gbphy_driver(usb_driver);
Viresh Kumarea7c4772016-05-09 18:15:12 +0530247MODULE_LICENSE("GPL v2");