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/acpi.h>
10 #include <linux/pm_runtime.h>
11 
12 #include "tb.h"
13 
14 static ssize_t link_show(struct device *dev, struct device_attribute *attr,
15 			 char *buf)
16 {
17 	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
18 	struct tb_port *port = usb4->port;
19 	struct tb *tb = port->sw->tb;
20 	const char *link;
21 
22 	if (mutex_lock_interruptible(&tb->lock))
23 		return -ERESTARTSYS;
24 
25 	if (tb_is_upstream_port(port))
26 		link = port->sw->link_usb4 ? "usb4" : "tbt";
27 	else if (tb_port_has_remote(port))
28 		link = port->remote->sw->link_usb4 ? "usb4" : "tbt";
29 	else
30 		link = "none";
31 
32 	mutex_unlock(&tb->lock);
33 
34 	return sysfs_emit(buf, "%s\n", link);
35 }
36 static DEVICE_ATTR_RO(link);
37 
38 static struct attribute *common_attrs[] = {
39 	&dev_attr_link.attr,
40 	NULL
41 };
42 
43 static const struct attribute_group common_group = {
44 	.attrs = common_attrs,
45 };
46 
47 static const struct attribute_group *usb4_port_device_groups[] = {
48 	&common_group,
49 	NULL
50 };
51 
52 static void usb4_port_device_release(struct device *dev)
53 {
54 	struct usb4_port *usb4 = container_of(dev, struct usb4_port, dev);
55 
56 	kfree(usb4);
57 }
58 
59 struct device_type usb4_port_device_type = {
60 	.name = "usb4_port",
61 	.groups = usb4_port_device_groups,
62 	.release = usb4_port_device_release,
63 };
64 
65 /**
66  * usb4_port_device_add() - Add USB4 port device
67  * @port: Lane 0 adapter port to add the USB4 port
68  *
69  * Creates and registers a USB4 port device for @port. Returns the new
70  * USB4 port device pointer or ERR_PTR() in case of error.
71  */
72 struct usb4_port *usb4_port_device_add(struct tb_port *port)
73 {
74 	struct usb4_port *usb4;
75 	int ret;
76 
77 	usb4 = kzalloc(sizeof(*usb4), GFP_KERNEL);
78 	if (!usb4)
79 		return ERR_PTR(-ENOMEM);
80 
81 	usb4->port = port;
82 	usb4->dev.type = &usb4_port_device_type;
83 	usb4->dev.parent = &port->sw->dev;
84 	dev_set_name(&usb4->dev, "usb4_port%d", port->port);
85 
86 	ret = device_register(&usb4->dev);
87 	if (ret) {
88 		put_device(&usb4->dev);
89 		return ERR_PTR(ret);
90 	}
91 
92 	pm_runtime_no_callbacks(&usb4->dev);
93 	pm_runtime_set_active(&usb4->dev);
94 	pm_runtime_enable(&usb4->dev);
95 	pm_runtime_set_autosuspend_delay(&usb4->dev, TB_AUTOSUSPEND_DELAY);
96 	pm_runtime_mark_last_busy(&usb4->dev);
97 	pm_runtime_use_autosuspend(&usb4->dev);
98 
99 	return usb4;
100 }
101 
102 /**
103  * usb4_port_device_remove() - Removes USB4 port device
104  * @usb4: USB4 port device
105  *
106  * Unregisters the USB4 port device from the system. The device will be
107  * released when the last reference is dropped.
108  */
109 void usb4_port_device_remove(struct usb4_port *usb4)
110 {
111 	device_unregister(&usb4->dev);
112 }
113