1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Intel XHCI (Cherry Trail, Broxton and others) USB OTG role switch driver 4 * 5 * Copyright (c) 2016-2017 Hans de Goede <hdegoede@redhat.com> 6 * 7 * Loosely based on android x86 kernel code which is: 8 * 9 * Copyright (C) 2014 Intel Corp. 10 * 11 * Author: Wu, Hao 12 */ 13 14 #include <linux/acpi.h> 15 #include <linux/delay.h> 16 #include <linux/err.h> 17 #include <linux/io.h> 18 #include <linux/kernel.h> 19 #include <linux/module.h> 20 #include <linux/platform_device.h> 21 #include <linux/pm_runtime.h> 22 #include <linux/usb/role.h> 23 24 /* register definition */ 25 #define DUAL_ROLE_CFG0 0x68 26 #define SW_VBUS_VALID BIT(24) 27 #define SW_IDPIN_EN BIT(21) 28 #define SW_IDPIN BIT(20) 29 30 #define DUAL_ROLE_CFG1 0x6c 31 #define HOST_MODE BIT(29) 32 33 #define DUAL_ROLE_CFG1_POLL_TIMEOUT 1000 34 35 #define DRV_NAME "intel_xhci_usb_sw" 36 37 struct intel_xhci_usb_data { 38 struct usb_role_switch *role_sw; 39 void __iomem *base; 40 }; 41 42 static int intel_xhci_usb_set_role(struct device *dev, enum usb_role role) 43 { 44 struct intel_xhci_usb_data *data = dev_get_drvdata(dev); 45 unsigned long timeout; 46 acpi_status status; 47 u32 glk, val; 48 49 /* 50 * On many CHT devices ACPI event (_AEI) handlers read / modify / 51 * write the cfg0 register, just like we do. Take the ACPI lock 52 * to avoid us racing with the AML code. 53 */ 54 status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, &glk); 55 if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) { 56 dev_err(dev, "Error could not acquire lock\n"); 57 return -EIO; 58 } 59 60 pm_runtime_get_sync(dev); 61 62 /* Set idpin value as requested */ 63 val = readl(data->base + DUAL_ROLE_CFG0); 64 switch (role) { 65 case USB_ROLE_NONE: 66 val |= SW_IDPIN; 67 val &= ~SW_VBUS_VALID; 68 break; 69 case USB_ROLE_HOST: 70 val &= ~SW_IDPIN; 71 val &= ~SW_VBUS_VALID; 72 break; 73 case USB_ROLE_DEVICE: 74 val |= SW_IDPIN; 75 val |= SW_VBUS_VALID; 76 break; 77 } 78 val |= SW_IDPIN_EN; 79 80 writel(val, data->base + DUAL_ROLE_CFG0); 81 82 acpi_release_global_lock(glk); 83 84 /* In most case it takes about 600ms to finish mode switching */ 85 timeout = jiffies + msecs_to_jiffies(DUAL_ROLE_CFG1_POLL_TIMEOUT); 86 87 /* Polling on CFG1 register to confirm mode switch.*/ 88 do { 89 val = readl(data->base + DUAL_ROLE_CFG1); 90 if (!!(val & HOST_MODE) == (role == USB_ROLE_HOST)) { 91 pm_runtime_put(dev); 92 return 0; 93 } 94 95 /* Interval for polling is set to about 5 - 10 ms */ 96 usleep_range(5000, 10000); 97 } while (time_before(jiffies, timeout)); 98 99 pm_runtime_put(dev); 100 101 dev_warn(dev, "Timeout waiting for role-switch\n"); 102 return -ETIMEDOUT; 103 } 104 105 static enum usb_role intel_xhci_usb_get_role(struct device *dev) 106 { 107 struct intel_xhci_usb_data *data = dev_get_drvdata(dev); 108 enum usb_role role; 109 u32 val; 110 111 pm_runtime_get_sync(dev); 112 val = readl(data->base + DUAL_ROLE_CFG0); 113 pm_runtime_put(dev); 114 115 if (!(val & SW_IDPIN)) 116 role = USB_ROLE_HOST; 117 else if (val & SW_VBUS_VALID) 118 role = USB_ROLE_DEVICE; 119 else 120 role = USB_ROLE_NONE; 121 122 return role; 123 } 124 125 static const struct usb_role_switch_desc sw_desc = { 126 .set = intel_xhci_usb_set_role, 127 .get = intel_xhci_usb_get_role, 128 .allow_userspace_control = true, 129 }; 130 131 static int intel_xhci_usb_probe(struct platform_device *pdev) 132 { 133 struct device *dev = &pdev->dev; 134 struct intel_xhci_usb_data *data; 135 struct resource *res; 136 137 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 138 if (!data) 139 return -ENOMEM; 140 141 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 142 if (!res) 143 return -EINVAL; 144 data->base = devm_ioremap_nocache(dev, res->start, resource_size(res)); 145 if (!data->base) 146 return -ENOMEM; 147 148 platform_set_drvdata(pdev, data); 149 150 data->role_sw = usb_role_switch_register(dev, &sw_desc); 151 if (IS_ERR(data->role_sw)) 152 return PTR_ERR(data->role_sw); 153 154 pm_runtime_set_active(dev); 155 pm_runtime_enable(dev); 156 157 return 0; 158 } 159 160 static int intel_xhci_usb_remove(struct platform_device *pdev) 161 { 162 struct intel_xhci_usb_data *data = platform_get_drvdata(pdev); 163 164 pm_runtime_disable(&pdev->dev); 165 166 usb_role_switch_unregister(data->role_sw); 167 return 0; 168 } 169 170 static const struct platform_device_id intel_xhci_usb_table[] = { 171 { .name = DRV_NAME }, 172 {} 173 }; 174 MODULE_DEVICE_TABLE(platform, intel_xhci_usb_table); 175 176 static struct platform_driver intel_xhci_usb_driver = { 177 .driver = { 178 .name = DRV_NAME, 179 }, 180 .id_table = intel_xhci_usb_table, 181 .probe = intel_xhci_usb_probe, 182 .remove = intel_xhci_usb_remove, 183 }; 184 185 module_platform_driver(intel_xhci_usb_driver); 186 187 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 188 MODULE_DESCRIPTION("Intel XHCI USB role switch driver"); 189 MODULE_LICENSE("GPL"); 190