+static int cport_features_enable(struct gb_host_device *hd, u16 cport_id)
+{
+ int retval;
+ struct es2_ap_dev *es2 = hd_to_es2(hd);
+ struct usb_device *udev = es2->usb_dev;
+
+ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ GB_APB_REQUEST_CPORT_FEAT_EN,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_INTERFACE, cport_id, 0, NULL,
+ 0, ES2_USB_CTRL_TIMEOUT);
+ if (retval < 0)
+ dev_err(&udev->dev, "Cannot enable CPort features for cport %u: %d\n",
+ cport_id, retval);
+ return retval;
+}
+
+static int cport_features_disable(struct gb_host_device *hd, u16 cport_id)
+{
+ int retval;
+ struct es2_ap_dev *es2 = hd_to_es2(hd);
+ struct usb_device *udev = es2->usb_dev;
+
+ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ GB_APB_REQUEST_CPORT_FEAT_DIS,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_INTERFACE, cport_id, 0, NULL,
+ 0, ES2_USB_CTRL_TIMEOUT);
+ if (retval < 0)
+ dev_err(&udev->dev,
+ "Cannot disable CPort features for cport %u: %d\n",
+ cport_id, retval);
+ return retval;
+}
+
+static int timesync_enable(struct gb_host_device *hd, u8 count,
+ u64 frame_time, u32 strobe_delay, u32 refclk)
+{
+ int retval;
+ struct es2_ap_dev *es2 = hd_to_es2(hd);
+ struct usb_device *udev = es2->usb_dev;
+ struct gb_control_timesync_enable_request *request;
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
+
+ request->count = count;
+ request->frame_time = cpu_to_le64(frame_time);
+ request->strobe_delay = cpu_to_le32(strobe_delay);
+ request->refclk = cpu_to_le32(refclk);
+ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ GB_APB_REQUEST_TIMESYNC_ENABLE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_INTERFACE, 0, 0, request,
+ sizeof(*request), ES2_USB_CTRL_TIMEOUT);
+ if (retval < 0)
+ dev_err(&udev->dev, "Cannot enable timesync %d\n", retval);
+
+ kfree(request);
+ return retval;
+}
+
+static int timesync_disable(struct gb_host_device *hd)
+{
+ int retval;
+ struct es2_ap_dev *es2 = hd_to_es2(hd);
+ struct usb_device *udev = es2->usb_dev;
+
+ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ GB_APB_REQUEST_TIMESYNC_DISABLE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_INTERFACE, 0, 0, NULL,
+ 0, ES2_USB_CTRL_TIMEOUT);
+ if (retval < 0)
+ dev_err(&udev->dev, "Cannot disable timesync %d\n", retval);
+
+ return retval;
+}
+
+static int timesync_authoritative(struct gb_host_device *hd, u64 *frame_time)
+{
+ int retval, i;
+ struct es2_ap_dev *es2 = hd_to_es2(hd);
+ struct usb_device *udev = es2->usb_dev;
+ struct timesync_authoritative_request *request;
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
+
+ for (i = 0; i < GB_TIMESYNC_MAX_STROBES; i++)
+ request->frame_time[i] = cpu_to_le64(frame_time[i]);
+
+ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ GB_APB_REQUEST_TIMESYNC_AUTHORITATIVE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_INTERFACE, 0, 0, request,
+ sizeof(*request), ES2_USB_CTRL_TIMEOUT);
+ if (retval < 0)
+ dev_err(&udev->dev, "Cannot timesync authoritative out %d\n", retval);
+
+ kfree(request);
+ return retval;
+}
+
+static int timesync_get_last_event(struct gb_host_device *hd, u64 *frame_time)
+{
+ int retval;
+ struct es2_ap_dev *es2 = hd_to_es2(hd);
+ struct usb_device *udev = es2->usb_dev;
+ __le64 *response_frame_time;
+
+ response_frame_time = kzalloc(sizeof(*response_frame_time), GFP_KERNEL);
+ if (!response_frame_time)
+ return -ENOMEM;
+
+ retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ GB_APB_REQUEST_TIMESYNC_GET_LAST_EVENT,
+ USB_DIR_IN | USB_TYPE_VENDOR |
+ USB_RECIP_INTERFACE, 0, 0, response_frame_time,
+ sizeof(*response_frame_time),
+ ES2_USB_CTRL_TIMEOUT);
+
+ if (retval != sizeof(*response_frame_time)) {
+ dev_err(&udev->dev, "Cannot get last TimeSync event: %d\n",
+ retval);
+
+ if (retval >= 0)
+ retval = -EIO;
+
+ goto out;
+ }
+ *frame_time = le64_to_cpu(*response_frame_time);
+ retval = 0;
+out:
+ kfree(response_frame_time);
+ return retval;
+}
+