max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,
		    char *buf, u16 length)
{
	struct spi_device *spi = to_spi_device(hcd->self.controller);
	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
	struct max3421_hcd_platform_data *pdata;
	unsigned long flags;
	int retval = 0;

	pdata = spi->dev.platform_data;

	spin_lock_irqsave(&max3421_hcd->lock, flags);

	switch (type_req) {
	case ClearHubFeature:
		break;
	case ClearPortFeature:
		switch (value) {
		case USB_PORT_FEAT_SUSPEND:
			break;
		case USB_PORT_FEAT_POWER:
			dev_dbg(hcd->self.controller, "power-off\n");
			max3421_gpout_set_value(hcd, pdata->vbus_gpout,
						!pdata->vbus_active_level);
			fallthrough;
		default:
			max3421_hcd->port_status &= ~(1 << value);
		}
		break;
	case GetHubDescriptor:
		hub_descriptor((struct usb_hub_descriptor *) buf);
		break;

	case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
	case GetPortErrorCount:
	case SetHubDepth:
		/* USB3 only */
		goto error;

	case GetHubStatus:
		*(__le32 *) buf = cpu_to_le32(0);
		break;

	case GetPortStatus:
		if (index != 1) {
			retval = -EPIPE;
			goto error;
		}
		((__le16 *) buf)[0] = cpu_to_le16(max3421_hcd->port_status);
		((__le16 *) buf)[1] =
			cpu_to_le16(max3421_hcd->port_status >> 16);
		break;

	case SetHubFeature:
		retval = -EPIPE;
		break;

	case SetPortFeature:
		switch (value) {
		case USB_PORT_FEAT_LINK_STATE:
		case USB_PORT_FEAT_U1_TIMEOUT:
		case USB_PORT_FEAT_U2_TIMEOUT:
		case USB_PORT_FEAT_BH_PORT_RESET:
			goto error;
		case USB_PORT_FEAT_SUSPEND:
			if (max3421_hcd->active)
				max3421_hcd->port_status |=
					USB_PORT_STAT_SUSPEND;
			break;
		case USB_PORT_FEAT_POWER:
			dev_dbg(hcd->self.controller, "power-on\n");
			max3421_hcd->port_status |= USB_PORT_STAT_POWER;
			max3421_gpout_set_value(hcd, pdata->vbus_gpout,
						pdata->vbus_active_level);
			break;
		case USB_PORT_FEAT_RESET:
			max3421_reset_port(hcd);
			fallthrough;
		default:
			if ((max3421_hcd->port_status & USB_PORT_STAT_POWER)
			    != 0)
				max3421_hcd->port_status |= (1 << value);
		}
		break;

	default:
		dev_dbg(hcd->self.controller,
			"hub control req%04x v%04x i%04x l%d\n",
			type_req, value, index, length);
error:		/* "protocol stall" on error */
		retval = -EPIPE;
	}

	spin_unlock_irqrestore(&max3421_hcd->lock, flags);
	return retval;
}
max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,
		    char *buf, u16 length)
{
	struct spi_device *spi = to_spi_device(hcd->self.controller);
	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
	struct max3421_hcd_platform_data *pdata;
	unsigned long flags;
	int retval = 0;

	pdata = spi->dev.platform_data;

	spin_lock_irqsave(&max3421_hcd->lock, flags);

	switch (type_req) {
	case ClearHubFeature:
		break;
	case ClearPortFeature:
		switch (value) {
		case USB_PORT_FEAT_SUSPEND:
			break;
		case USB_PORT_FEAT_POWER:
			dev_dbg(hcd->self.controller, "power-off\n");
			max3421_gpout_set_value(hcd, pdata->vbus_gpout,
						!pdata->vbus_active_level);
			fallthrough;
		default:
			max3421_hcd->port_status &= ~(1 << value);
		}
		break;
	case GetHubDescriptor:
		hub_descriptor((struct usb_hub_descriptor *) buf);
		break;

	case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
	case GetPortErrorCount:
	case SetHubDepth:
		 
		goto error;

	case GetHubStatus:
		*(__le32 *) buf = cpu_to_le32(0);
		break;

	case GetPortStatus:
		if (index != 1) {
			retval = -EPIPE;
			goto error;
		}
		((__le16 *) buf)[0] = cpu_to_le16(max3421_hcd->port_status);
		((__le16 *) buf)[1] =
			cpu_to_le16(max3421_hcd->port_status >> 16);
		break;

	case SetHubFeature:
		retval = -EPIPE;
		break;

	case SetPortFeature:
		switch (value) {
		case USB_PORT_FEAT_LINK_STATE:
		case USB_PORT_FEAT_U1_TIMEOUT:
		case USB_PORT_FEAT_U2_TIMEOUT:
		case USB_PORT_FEAT_BH_PORT_RESET:
			goto error;
		case USB_PORT_FEAT_SUSPEND:
			if (max3421_hcd->active)
				max3421_hcd->port_status |=
					USB_PORT_STAT_SUSPEND;
			break;
		case USB_PORT_FEAT_POWER:
			dev_dbg(hcd->self.controller, "power-on\n");
			max3421_hcd->port_status |= USB_PORT_STAT_POWER;
			max3421_gpout_set_value(hcd, pdata->vbus_gpout,
						pdata->vbus_active_level);
			break;
		case USB_PORT_FEAT_RESET:
			max3421_reset_port(hcd);
			fallthrough;
		default:
			if ((max3421_hcd->port_status & USB_PORT_STAT_POWER)
			    != 0)
				max3421_hcd->port_status |= (1 << value);
		}
		break;

	default:
		dev_dbg(hcd->self.controller,
			"hub control req%04x v%04x i%04x l%d\n",
			type_req, value, index, length);
error:		 
		retval = -EPIPE;
	}

	spin_unlock_irqrestore(&max3421_hcd->lock, flags);
	return retval;
}