Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * USB4 port device
  4 *
  5 * Copyright (C) 2021, Intel Corporation
  6 * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
  7 */
  8
  9#include <linux/pm_runtime.h>
 10#include <linux/component.h>
 11#include <linux/property.h>
 12
 13#include "tb.h"
 14
 15static int connector_bind(struct device *dev, struct device *connector, void *data)
 16{
 17	int ret;
 18
 19	ret = sysfs_create_link(&dev->kobj, &connector->kobj, "connector");
 20	if (ret)
 21		return ret;
 22
 23	ret = sysfs_create_link(&connector->kobj, &dev->kobj, dev_name(dev));
 24	if (ret)
 25		sysfs_remove_link(&dev->kobj, "connector");
 26
 27	return ret;
 28}
 29
 30static void connector_unbind(struct device *dev, struct device *connector, void *data)
 31{
 32	sysfs_remove_link(&connector->kobj, dev_name(dev));
 33	sysfs_remove_link(&dev->kobj, "connector");
 34}
 35
 36static const struct component_ops connector_ops = {
 37	.bind = connector_bind,
 38	.unbind = connector_unbind,
 39};
 40
 41static ssize_t link_show(struct device *dev, struct device_attribute *attr,
 42			 char *buf)
 43{
 44	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
 45	struct tb_port *port = usb4->port;
 46	struct tb *tb = port->sw->tb;
 47	const char *link;
 48
 49	if (mutex_lock_interruptible(&tb->lock))
 50		return -ERESTARTSYS;
 51
 52	if (tb_is_upstream_port(port))
 53		link = port->sw->link_usb4 ? "usb4" : "tbt";
 54	else if (tb_port_has_remote(port))
 55		link = port->remote->sw->link_usb4 ? "usb4" : "tbt";
 56	else if (port->xdomain)
 57		link = port->xdomain->link_usb4 ? "usb4" : "tbt";
 58	else
 59		link = "none";
 60
 61	mutex_unlock(&tb->lock);
 62
 63	return sysfs_emit(buf, "%s\n", link);
 64}
 65static DEVICE_ATTR_RO(link);
 66
 67static struct attribute *common_attrs[] = {
 68	&dev_attr_link.attr,
 69	NULL
 70};
 71
 72static const struct attribute_group common_group = {
 73	.attrs = common_attrs,
 74};
 75
 76static int usb4_port_offline(struct usb4_port *usb4)
 77{
 78	struct tb_port *port = usb4->port;
 79	int ret;
 80
 81	ret = tb_acpi_power_on_retimers(port);
 82	if (ret)
 83		return ret;
 84
 85	ret = usb4_port_router_offline(port);
 86	if (ret) {
 87		tb_acpi_power_off_retimers(port);
 88		return ret;
 89	}
 90
 91	ret = tb_retimer_scan(port, false);
 92	if (ret) {
 93		usb4_port_router_online(port);
 94		tb_acpi_power_off_retimers(port);
 95	}
 96
 97	return ret;
 98}
 99
100static void usb4_port_online(struct usb4_port *usb4)
101{
102	struct tb_port *port = usb4->port;
103
104	usb4_port_router_online(port);
105	tb_acpi_power_off_retimers(port);
106}
107
108static ssize_t offline_show(struct device *dev,
109	struct device_attribute *attr, char *buf)
110{
111	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
112
113	return sysfs_emit(buf, "%d\n", usb4->offline);
114}
115
116static ssize_t offline_store(struct device *dev,
117	struct device_attribute *attr, const char *buf, size_t count)
118{
119	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
120	struct tb_port *port = usb4->port;
121	struct tb *tb = port->sw->tb;
122	bool val;
123	int ret;
124
125	ret = kstrtobool(buf, &val);
126	if (ret)
127		return ret;
128
129	pm_runtime_get_sync(&usb4->dev);
130
131	if (mutex_lock_interruptible(&tb->lock)) {
132		ret = -ERESTARTSYS;
133		goto out_rpm;
134	}
135
136	if (val == usb4->offline)
137		goto out_unlock;
138
139	/* Offline mode works only for ports that are not connected */
140	if (tb_port_has_remote(port)) {
141		ret = -EBUSY;
142		goto out_unlock;
143	}
144
145	if (val) {
146		ret = usb4_port_offline(usb4);
147		if (ret)
148			goto out_unlock;
149	} else {
150		usb4_port_online(usb4);
151		tb_retimer_remove_all(port);
152	}
153
154	usb4->offline = val;
155	tb_port_dbg(port, "%s offline mode\n", val ? "enter" : "exit");
156
157out_unlock:
158	mutex_unlock(&tb->lock);
159out_rpm:
160	pm_runtime_mark_last_busy(&usb4->dev);
161	pm_runtime_put_autosuspend(&usb4->dev);
162
163	return ret ? ret : count;
164}
165static DEVICE_ATTR_RW(offline);
166
167static ssize_t rescan_store(struct device *dev,
168	struct device_attribute *attr, const char *buf, size_t count)
169{
170	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
171	struct tb_port *port = usb4->port;
172	struct tb *tb = port->sw->tb;
173	bool val;
174	int ret;
175
176	ret = kstrtobool(buf, &val);
177	if (ret)
178		return ret;
179
180	if (!val)
181		return count;
182
183	pm_runtime_get_sync(&usb4->dev);
184
185	if (mutex_lock_interruptible(&tb->lock)) {
186		ret = -ERESTARTSYS;
187		goto out_rpm;
188	}
189
190	/* Must be in offline mode already */
191	if (!usb4->offline) {
192		ret = -EINVAL;
193		goto out_unlock;
194	}
195
196	tb_retimer_remove_all(port);
197	ret = tb_retimer_scan(port, true);
198
199out_unlock:
200	mutex_unlock(&tb->lock);
201out_rpm:
202	pm_runtime_mark_last_busy(&usb4->dev);
203	pm_runtime_put_autosuspend(&usb4->dev);
204
205	return ret ? ret : count;
206}
207static DEVICE_ATTR_WO(rescan);
208
209static struct attribute *service_attrs[] = {
210	&dev_attr_offline.attr,
211	&dev_attr_rescan.attr,
212	NULL
213};
214
215static umode_t service_attr_is_visible(struct kobject *kobj,
216				       struct attribute *attr, int n)
217{
218	struct device *dev = kobj_to_dev(kobj);
219	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
220
221	/*
222	 * Always need some platform help to cycle the modes so that
223	 * retimers can be accessed through the sideband.
224	 */
225	return usb4->can_offline ? attr->mode : 0;
226}
227
228static const struct attribute_group service_group = {
229	.attrs = service_attrs,
230	.is_visible = service_attr_is_visible,
231};
232
233static const struct attribute_group *usb4_port_device_groups[] = {
234	&common_group,
235	&service_group,
236	NULL
237};
238
239static void usb4_port_device_release(struct device *dev)
240{
241	struct usb4_port *usb4 = container_of(dev, struct usb4_port, dev);
242
243	kfree(usb4);
244}
245
246struct device_type usb4_port_device_type = {
247	.name = "usb4_port",
248	.groups = usb4_port_device_groups,
249	.release = usb4_port_device_release,
250};
251
252/**
253 * usb4_port_device_add() - Add USB4 port device
254 * @port: Lane 0 adapter port to add the USB4 port
255 *
256 * Creates and registers a USB4 port device for @port. Returns the new
257 * USB4 port device pointer or ERR_PTR() in case of error.
258 */
259struct usb4_port *usb4_port_device_add(struct tb_port *port)
260{
261	struct usb4_port *usb4;
262	int ret;
263
264	usb4 = kzalloc(sizeof(*usb4), GFP_KERNEL);
265	if (!usb4)
266		return ERR_PTR(-ENOMEM);
267
268	usb4->port = port;
269	usb4->dev.type = &usb4_port_device_type;
270	usb4->dev.parent = &port->sw->dev;
271	dev_set_name(&usb4->dev, "usb4_port%d", port->port);
272
273	ret = device_register(&usb4->dev);
274	if (ret) {
275		put_device(&usb4->dev);
276		return ERR_PTR(ret);
277	}
278
279	if (dev_fwnode(&usb4->dev)) {
280		ret = component_add(&usb4->dev, &connector_ops);
281		if (ret) {
282			dev_err(&usb4->dev, "failed to add component\n");
283			device_unregister(&usb4->dev);
284		}
285	}
286
287	if (!tb_is_upstream_port(port))
288		device_set_wakeup_capable(&usb4->dev, true);
289
290	pm_runtime_no_callbacks(&usb4->dev);
291	pm_runtime_set_active(&usb4->dev);
292	pm_runtime_enable(&usb4->dev);
293	pm_runtime_set_autosuspend_delay(&usb4->dev, TB_AUTOSUSPEND_DELAY);
294	pm_runtime_mark_last_busy(&usb4->dev);
295	pm_runtime_use_autosuspend(&usb4->dev);
296
297	return usb4;
298}
299
300/**
301 * usb4_port_device_remove() - Removes USB4 port device
302 * @usb4: USB4 port device
303 *
304 * Unregisters the USB4 port device from the system. The device will be
305 * released when the last reference is dropped.
306 */
307void usb4_port_device_remove(struct usb4_port *usb4)
308{
309	if (dev_fwnode(&usb4->dev))
310		component_del(&usb4->dev, &connector_ops);
311	device_unregister(&usb4->dev);
312}
313
314/**
315 * usb4_port_device_resume() - Resumes USB4 port device
316 * @usb4: USB4 port device
317 *
318 * Used to resume USB4 port device after sleep state.
319 */
320int usb4_port_device_resume(struct usb4_port *usb4)
321{
322	return usb4->offline ? usb4_port_offline(usb4) : 0;
323}