Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e52678a authored by Heikki Krogerus's avatar Heikki Krogerus Committed by Will McVicker
Browse files

UPSTREAM: usb: typec: mux: Find the muxes by also matching against the device node



When the connections are defined in firmware, struct
device_connection will have the fwnode member pointing to
the device node (struct fwnode_handle) of the requested
device, and the endpoint will not be used at all in that
case.

Bug: 150877929
Acked-by: default avatarHans de Goede <hdegoede@redhat.com>
Reviewed-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: default avatarJun Li <jun.li@nxp.com>
Signed-off-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Change-Id: I9e109b61a63ed005d419ee59c5fbad48903835b3
Signed-off-by: default avatarWill McVicker <willmcvicker@google.com>
(cherry picked from commit 96a6d031ca9930938bd66d0052fc7ed2b56e3583)
parent 75d8663e
Loading
Loading
Loading
Loading
+74 −12
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/usb/typec_mux.h>

static DEFINE_MUTEX(switch_lock);
@@ -23,15 +25,25 @@ static void *typec_switch_match(struct device_connection *con, int ep,
{
	struct typec_switch *sw;

	if (!con->fwnode) {
		list_for_each_entry(sw, &switch_list, entry)
			if (!strcmp(con->endpoint[ep], dev_name(sw->dev)))
				return sw;
		return ERR_PTR(-EPROBE_DEFER);
	}

	/*
	 * We only get called if a connection was found, tell the caller to
	 * wait for the switch to show up.
	 * With OF graph the mux node must have a boolean device property named
	 * "orientation-switch".
	 */
	return ERR_PTR(-EPROBE_DEFER);
	if (con->id && !fwnode_property_present(con->fwnode, con->id))
		return NULL;

	list_for_each_entry(sw, &switch_list, entry)
		if (dev_fwnode(sw->dev) == con->fwnode)
			return sw;

	return con->id ? ERR_PTR(-EPROBE_DEFER) : NULL;
}

/**
@@ -112,17 +124,67 @@ EXPORT_SYMBOL_GPL(typec_switch_unregister);

static void *typec_mux_match(struct device_connection *con, int ep, void *data)
{
	const struct typec_altmode_desc *desc = data;
	struct typec_mux *mux;
	size_t nval;
	bool match;
	u16 *val;
	int i;

	if (!con->fwnode) {
		list_for_each_entry(mux, &mux_list, entry)
			if (!strcmp(con->endpoint[ep], dev_name(mux->dev)))
				return mux;
		return ERR_PTR(-EPROBE_DEFER);
	}

	/*
	 * We only get called if a connection was found, tell the caller to
	 * wait for the switch to show up.
	 * Check has the identifier already been "consumed". If it
	 * has, no need to do any extra connection identification.
	 */
	return ERR_PTR(-EPROBE_DEFER);
	match = !con->id;
	if (match)
		goto find_mux;

	/* Accessory Mode muxes */
	if (!desc) {
		match = fwnode_property_present(con->fwnode, "accessory");
		if (match)
			goto find_mux;
		return NULL;
	}

	/* Alternate Mode muxes */
	nval = fwnode_property_read_u16_array(con->fwnode, "svid", NULL, 0);
	if (nval <= 0)
		return NULL;

	val = kcalloc(nval, sizeof(*val), GFP_KERNEL);
	if (!val)
		return ERR_PTR(-ENOMEM);

	nval = fwnode_property_read_u16_array(con->fwnode, "svid", val, nval);
	if (nval < 0) {
		kfree(val);
		return ERR_PTR(nval);
	}

	for (i = 0; i < nval; i++) {
		match = val[i] == desc->svid;
		if (match) {
			kfree(val);
			goto find_mux;
		}
	}
	kfree(val);
	return NULL;

find_mux:
	list_for_each_entry(mux, &mux_list, entry)
		if (dev_fwnode(mux->dev) == con->fwnode)
			return mux;

	return match ? ERR_PTR(-EPROBE_DEFER) : NULL;
}

/**