Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Intel XHCI (Cherry Trail, Broxton and others) USB OTG role switch driver
0004  *
0005  * Copyright (c) 2016-2017 Hans de Goede <hdegoede@redhat.com>
0006  *
0007  * Loosely based on android x86 kernel code which is:
0008  *
0009  * Copyright (C) 2014 Intel Corp.
0010  *
0011  * Author: Wu, Hao
0012  */
0013 
0014 #include <linux/acpi.h>
0015 #include <linux/delay.h>
0016 #include <linux/err.h>
0017 #include <linux/io.h>
0018 #include <linux/kernel.h>
0019 #include <linux/module.h>
0020 #include <linux/platform_device.h>
0021 #include <linux/pm_runtime.h>
0022 #include <linux/property.h>
0023 #include <linux/usb/role.h>
0024 
0025 /* register definition */
0026 #define DUAL_ROLE_CFG0          0x68
0027 #define SW_VBUS_VALID           BIT(24)
0028 #define SW_IDPIN_EN         BIT(21)
0029 #define SW_IDPIN            BIT(20)
0030 #define SW_SWITCH_EN            BIT(16)
0031 
0032 #define DRD_CONFIG_DYNAMIC      0
0033 #define DRD_CONFIG_STATIC_HOST      1
0034 #define DRD_CONFIG_STATIC_DEVICE    2
0035 #define DRD_CONFIG_MASK         3
0036 
0037 #define DUAL_ROLE_CFG1          0x6c
0038 #define HOST_MODE           BIT(29)
0039 
0040 #define DUAL_ROLE_CFG1_POLL_TIMEOUT 1000
0041 
0042 #define DRV_NAME            "intel_xhci_usb_sw"
0043 
0044 struct intel_xhci_usb_data {
0045     struct device *dev;
0046     struct usb_role_switch *role_sw;
0047     void __iomem *base;
0048     bool enable_sw_switch;
0049 };
0050 
0051 static const struct software_node intel_xhci_usb_node = {
0052     "intel-xhci-usb-sw",
0053 };
0054 
0055 static int intel_xhci_usb_set_role(struct usb_role_switch *sw,
0056                    enum usb_role role)
0057 {
0058     struct intel_xhci_usb_data *data = usb_role_switch_get_drvdata(sw);
0059     unsigned long timeout;
0060     acpi_status status;
0061     u32 glk, val;
0062     u32 drd_config = DRD_CONFIG_DYNAMIC;
0063 
0064     /*
0065      * On many CHT devices ACPI event (_AEI) handlers read / modify /
0066      * write the cfg0 register, just like we do. Take the ACPI lock
0067      * to avoid us racing with the AML code.
0068      */
0069     status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, &glk);
0070     if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
0071         dev_err(data->dev, "Error could not acquire lock\n");
0072         return -EIO;
0073     }
0074 
0075     pm_runtime_get_sync(data->dev);
0076 
0077     /*
0078      * Set idpin value as requested.
0079      * Since some devices rely on firmware setting DRD_CONFIG and
0080      * SW_SWITCH_EN bits to be zero for role switch,
0081      * do not set these bits for those devices.
0082      */
0083     val = readl(data->base + DUAL_ROLE_CFG0);
0084     switch (role) {
0085     case USB_ROLE_NONE:
0086         val |= SW_IDPIN;
0087         val &= ~SW_VBUS_VALID;
0088         drd_config = DRD_CONFIG_DYNAMIC;
0089         break;
0090     case USB_ROLE_HOST:
0091         val &= ~SW_IDPIN;
0092         val &= ~SW_VBUS_VALID;
0093         drd_config = DRD_CONFIG_STATIC_HOST;
0094         break;
0095     case USB_ROLE_DEVICE:
0096         val |= SW_IDPIN;
0097         val |= SW_VBUS_VALID;
0098         drd_config = DRD_CONFIG_STATIC_DEVICE;
0099         break;
0100     }
0101     val |= SW_IDPIN_EN;
0102     if (data->enable_sw_switch) {
0103         val &= ~DRD_CONFIG_MASK;
0104         val |= SW_SWITCH_EN | drd_config;
0105     }
0106     writel(val, data->base + DUAL_ROLE_CFG0);
0107 
0108     acpi_release_global_lock(glk);
0109 
0110     /* In most case it takes about 600ms to finish mode switching */
0111     timeout = jiffies + msecs_to_jiffies(DUAL_ROLE_CFG1_POLL_TIMEOUT);
0112 
0113     /* Polling on CFG1 register to confirm mode switch.*/
0114     do {
0115         val = readl(data->base + DUAL_ROLE_CFG1);
0116         if (!!(val & HOST_MODE) == (role == USB_ROLE_HOST)) {
0117             pm_runtime_put(data->dev);
0118             return 0;
0119         }
0120 
0121         /* Interval for polling is set to about 5 - 10 ms */
0122         usleep_range(5000, 10000);
0123     } while (time_before(jiffies, timeout));
0124 
0125     pm_runtime_put(data->dev);
0126 
0127     dev_warn(data->dev, "Timeout waiting for role-switch\n");
0128     return -ETIMEDOUT;
0129 }
0130 
0131 static enum usb_role intel_xhci_usb_get_role(struct usb_role_switch *sw)
0132 {
0133     struct intel_xhci_usb_data *data = usb_role_switch_get_drvdata(sw);
0134     enum usb_role role;
0135     u32 val;
0136 
0137     pm_runtime_get_sync(data->dev);
0138     val = readl(data->base + DUAL_ROLE_CFG0);
0139     pm_runtime_put(data->dev);
0140 
0141     if (!(val & SW_IDPIN))
0142         role = USB_ROLE_HOST;
0143     else if (val & SW_VBUS_VALID)
0144         role = USB_ROLE_DEVICE;
0145     else
0146         role = USB_ROLE_NONE;
0147 
0148     return role;
0149 }
0150 
0151 static int intel_xhci_usb_probe(struct platform_device *pdev)
0152 {
0153     struct usb_role_switch_desc sw_desc = { };
0154     struct device *dev = &pdev->dev;
0155     struct intel_xhci_usb_data *data;
0156     struct resource *res;
0157     int ret;
0158 
0159     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0160     if (!data)
0161         return -ENOMEM;
0162 
0163     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0164     if (!res)
0165         return -EINVAL;
0166     data->base = devm_ioremap(dev, res->start, resource_size(res));
0167     if (!data->base)
0168         return -ENOMEM;
0169 
0170     platform_set_drvdata(pdev, data);
0171 
0172     ret = software_node_register(&intel_xhci_usb_node);
0173     if (ret)
0174         return ret;
0175 
0176     sw_desc.set = intel_xhci_usb_set_role,
0177     sw_desc.get = intel_xhci_usb_get_role,
0178     sw_desc.allow_userspace_control = true,
0179     sw_desc.fwnode = software_node_fwnode(&intel_xhci_usb_node);
0180     sw_desc.driver_data = data;
0181 
0182     data->dev = dev;
0183     data->enable_sw_switch = !device_property_read_bool(dev,
0184                         "sw_switch_disable");
0185 
0186     data->role_sw = usb_role_switch_register(dev, &sw_desc);
0187     if (IS_ERR(data->role_sw)) {
0188         fwnode_handle_put(sw_desc.fwnode);
0189         return PTR_ERR(data->role_sw);
0190     }
0191 
0192     pm_runtime_set_active(dev);
0193     pm_runtime_enable(dev);
0194 
0195     return 0;
0196 }
0197 
0198 static int intel_xhci_usb_remove(struct platform_device *pdev)
0199 {
0200     struct intel_xhci_usb_data *data = platform_get_drvdata(pdev);
0201 
0202     pm_runtime_disable(&pdev->dev);
0203 
0204     usb_role_switch_unregister(data->role_sw);
0205     fwnode_handle_put(software_node_fwnode(&intel_xhci_usb_node));
0206 
0207     return 0;
0208 }
0209 
0210 static const struct platform_device_id intel_xhci_usb_table[] = {
0211     { .name = DRV_NAME },
0212     {}
0213 };
0214 MODULE_DEVICE_TABLE(platform, intel_xhci_usb_table);
0215 
0216 static struct platform_driver intel_xhci_usb_driver = {
0217     .driver = {
0218         .name = DRV_NAME,
0219     },
0220     .id_table = intel_xhci_usb_table,
0221     .probe = intel_xhci_usb_probe,
0222     .remove = intel_xhci_usb_remove,
0223 };
0224 
0225 module_platform_driver(intel_xhci_usb_driver);
0226 
0227 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
0228 MODULE_DESCRIPTION("Intel XHCI USB role switch driver");
0229 MODULE_LICENSE("GPL");