usb: gadget: Introduce udc_set_ssp_rate() for SSP
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>
Thu, 14 Jan 2021 02:53:07 +0000 (18:53 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 18 Jan 2021 17:40:08 +0000 (18:40 +0100)
A SuperSpeed Plus device may operate at different speed and lane count
(i.e. gen2x2, gen1x2, or gen2x1). Introduce gadget ops
udc_set_ssp_rate() to set the desire corresponding usb_ssp_rate for
SuperSpeed Plus capable devices.

If the USB device supports different speeds at SuperSpeed Plus, set the
device to operate with the maximum number of lanes and speed.

Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Link: https://lore.kernel.org/r/9b85357cdadc02e3f0d653fd05f89eb46af836e1.1610592135.git.Thinh.Nguyen@synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/udc/core.c
include/linux/usb/gadget.h

index 98cf921..4173acd 100644 (file)
@@ -1133,12 +1133,18 @@ static inline void usb_gadget_udc_stop(struct usb_udc *udc)
 static inline void usb_gadget_udc_set_speed(struct usb_udc *udc,
                                            enum usb_device_speed speed)
 {
-       if (udc->gadget->ops->udc_set_speed) {
-               enum usb_device_speed s;
+       struct usb_gadget *gadget = udc->gadget;
+       enum usb_device_speed s;
 
-               s = min(speed, udc->gadget->max_speed);
-               udc->gadget->ops->udc_set_speed(udc->gadget, s);
-       }
+       if (speed == USB_SPEED_UNKNOWN)
+               s = gadget->max_speed;
+       else
+               s = min(speed, gadget->max_speed);
+
+       if (s == USB_SPEED_SUPER_PLUS && gadget->ops->udc_set_ssp_rate)
+               gadget->ops->udc_set_ssp_rate(gadget, gadget->max_ssp_rate);
+       else if (gadget->ops->udc_set_speed)
+               gadget->ops->udc_set_speed(gadget, s);
 }
 
 /**
index 02483c8..ee04ef2 100644 (file)
@@ -323,6 +323,8 @@ struct usb_gadget_ops {
                        struct usb_gadget_driver *);
        int     (*udc_stop)(struct usb_gadget *);
        void    (*udc_set_speed)(struct usb_gadget *, enum usb_device_speed);
+       void    (*udc_set_ssp_rate)(struct usb_gadget *gadget,
+                       enum usb_ssp_rate rate);
        struct usb_ep *(*match_ep)(struct usb_gadget *,
                        struct usb_endpoint_descriptor *,
                        struct usb_ss_ep_comp_descriptor *);