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 
intel_xhci_usb_set_role(struct device * dev,enum usb_role role)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 
intel_xhci_usb_get_role(struct device * dev)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 
intel_xhci_usb_probe(struct platform_device * pdev)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 
intel_xhci_usb_remove(struct platform_device * pdev)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