Linux Audio

Check our new training course

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