All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] platform/chrome: Type-C switch driver and Type-C framework updates
@ 2022-06-29 23:32 Prashant Malani
  2022-06-29 23:32 ` [PATCH 1/9] usb: typec: Add support for retimers Prashant Malani
                   ` (8 more replies)
  0 siblings, 9 replies; 15+ messages in thread
From: Prashant Malani @ 2022-06-29 23:32 UTC (permalink / raw)
  To: linux-kernel, linux-usb, chrome-platform
  Cc: bleung, heikki.krogerus, Prashant Malani, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel, Tzung-Bi Shih

This series introduces a retimer class to the USB Type-C framework,
It also introduces a Chrome EC (Embedded Controller) switch driver which
registers the aforementioned retimer switches as well as mode-switches.

Patch 1 and 2 introduce the retimer class and associated functions to
the Type-C common code.

Patches 3-7 add the cros-typec-switch driver

Patches 8-9 update cros-ec-typec to get and use retimer switch handles

Submission suggestion (as always, open to better suggestions):
- Patch 1 and 2 can go through the USB repo.
- Patch 3-9 can go through the chrome-platform repo. Since they depend
  on patches 1 and 2, we can create an "topic branch" off of
  usb-next once Patch 1 and 2 are submitted, and then apply Patches 3-9
  on top of that "topic branch" before merging it back into
  chrome-platform's for-next branch

Prashant Malani (9):
  usb: typec: Add support for retimers
  usb: typec: Add retimer handle to port
  platform/chrome: Add Type-C mux set command definitions
  platform/chrome: cros_typec_switch: Add switch driver
  platform/chrome: cros_typec_switch: Set EC retimer
  platform/chrome: cros_typec_switch: Add event check
  platform/chrome: cros_typec_switch: Register mode switches
  platform/chrome: cros_ec_typec: Cleanup switch handle return paths
  platform/chrome: cros_ec_typec: Get retimer handle

 MAINTAINERS                                   |   1 +
 drivers/platform/chrome/Kconfig               |  11 +
 drivers/platform/chrome/Makefile              |   1 +
 drivers/platform/chrome/cros_ec_typec.c       |  50 ++-
 drivers/platform/chrome/cros_typec_switch.c   | 332 ++++++++++++++++++
 drivers/usb/typec/Makefile                    |   2 +-
 drivers/usb/typec/class.c                     |  17 +-
 drivers/usb/typec/class.h                     |   2 +
 drivers/usb/typec/retimer.c                   | 168 +++++++++
 drivers/usb/typec/retimer.h                   |  15 +
 .../linux/platform_data/cros_ec_commands.h    |  18 +
 include/linux/usb/typec_retimer.h             |  45 +++
 12 files changed, 653 insertions(+), 9 deletions(-)
 create mode 100644 drivers/platform/chrome/cros_typec_switch.c
 create mode 100644 drivers/usb/typec/retimer.c
 create mode 100644 drivers/usb/typec/retimer.h
 create mode 100644 include/linux/usb/typec_retimer.h

-- 
2.37.0.rc0.161.g10f37bed90-goog


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/9] usb: typec: Add support for retimers
  2022-06-29 23:32 [PATCH 0/9] platform/chrome: Type-C switch driver and Type-C framework updates Prashant Malani
@ 2022-06-29 23:32 ` Prashant Malani
  2022-06-30  8:17   ` Heikki Krogerus
  2022-06-29 23:32 ` [PATCH 2/9] usb: typec: Add retimer handle to port Prashant Malani
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Prashant Malani @ 2022-06-29 23:32 UTC (permalink / raw)
  To: linux-kernel, linux-usb, chrome-platform
  Cc: bleung, heikki.krogerus, Prashant Malani, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel

Introduce a retimer device class and associated functions that register
and use retimer "switch" devices. These operate in a manner similar to
the "mode-switch" and help configure retimers that exist between the
Type-C connector and host controller(s).

Type C ports can be linked to retimers using firmware node device
references (again, in a manner similar to "mode-switch").

Signed-off-by: Prashant Malani <pmalani@chromium.org>
---
 drivers/usb/typec/Makefile        |   2 +-
 drivers/usb/typec/class.c         |   9 +-
 drivers/usb/typec/class.h         |   1 +
 drivers/usb/typec/retimer.c       | 168 ++++++++++++++++++++++++++++++
 drivers/usb/typec/retimer.h       |  15 +++
 include/linux/usb/typec_retimer.h |  45 ++++++++
 6 files changed, 238 insertions(+), 2 deletions(-)
 create mode 100644 drivers/usb/typec/retimer.c
 create mode 100644 drivers/usb/typec/retimer.h
 create mode 100644 include/linux/usb/typec_retimer.h

diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
index 2f174cd3e5df..4955d9af0811 100644
--- a/drivers/usb/typec/Makefile
+++ b/drivers/usb/typec/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_TYPEC)		+= typec.o
-typec-y				:= class.o mux.o bus.o pd.o
+typec-y				:= class.o mux.o bus.o pd.o retimer.o
 typec-$(CONFIG_ACPI)		+= port-mapper.o
 obj-$(CONFIG_TYPEC)		+= altmodes/
 obj-$(CONFIG_TYPEC_TCPM)	+= tcpm/
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index bbc46b14f99a..2fa0b3718d23 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -2299,10 +2299,14 @@ static int __init typec_init(void)
 	if (ret)
 		goto err_unregister_bus;
 
-	ret = class_register(&typec_class);
+	ret = class_register(&typec_retimer_class);
 	if (ret)
 		goto err_unregister_mux_class;
 
+	ret = class_register(&typec_class);
+	if (ret)
+		goto err_unregister_retimer_class;
+
 	ret = usb_power_delivery_init();
 	if (ret)
 		goto err_unregister_class;
@@ -2312,6 +2316,9 @@ static int __init typec_init(void)
 err_unregister_class:
 	class_unregister(&typec_class);
 
+err_unregister_retimer_class:
+	class_unregister(&typec_retimer_class);
+
 err_unregister_mux_class:
 	class_unregister(&typec_mux_class);
 
diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h
index b531f9853bc0..1bb1da124109 100644
--- a/drivers/usb/typec/class.h
+++ b/drivers/usb/typec/class.h
@@ -76,6 +76,7 @@ extern const struct device_type typec_port_dev_type;
 #define is_typec_port(dev) ((dev)->type == &typec_port_dev_type)
 
 extern struct class typec_mux_class;
+extern struct class typec_retimer_class;
 extern struct class typec_class;
 
 #if defined(CONFIG_ACPI)
diff --git a/drivers/usb/typec/retimer.c b/drivers/usb/typec/retimer.c
new file mode 100644
index 000000000000..2fa0aeb9363c
--- /dev/null
+++ b/drivers/usb/typec/retimer.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2022 Google LLC
+ *
+ * USB Type-C Retimer support.
+ * Author: Prashant Malani <pmalani@chromium.org>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+
+#include "class.h"
+#include "retimer.h"
+
+static bool dev_name_ends_with(struct device *dev, const char *suffix)
+{
+	const char *name = dev_name(dev);
+	const int name_len = strlen(name);
+	const int suffix_len = strlen(suffix);
+
+	if (suffix_len > name_len)
+		return false;
+
+	return strcmp(name + (name_len - suffix_len), suffix) == 0;
+}
+
+static int retimer_fwnode_match(struct device *dev, const void *fwnode)
+{
+	return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-retimer");
+}
+
+static void *typec_retimer_match(struct fwnode_handle *fwnode, const char *id, void *data)
+{
+	struct device *dev  = class_find_device(&typec_retimer_class, NULL, fwnode,
+						retimer_fwnode_match);
+
+	return dev ? to_typec_retimer(dev) : ERR_PTR(-EPROBE_DEFER);
+}
+
+/**
+ * fwnode_typec_retimer_get - Find USB Type-C retimer.
+ * @fwnode: The caller device node.
+ *
+ * Finds a retimer linked to the caller. This function is primarily meant for the
+ * Type-C drivers. Returns a reference to the retimer on success, NULL if no
+ * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection
+ * was found but the retimer has not been enumerated yet.
+ */
+struct typec_retimer *fwnode_typec_retimer_get(struct fwnode_handle *fwnode)
+{
+	struct typec_retimer *retimer;
+
+	retimer = fwnode_connection_find_match(fwnode, "retimer-switch", NULL, typec_retimer_match);
+	if (!IS_ERR_OR_NULL(retimer))
+		WARN_ON(!try_module_get(retimer->dev.parent->driver->owner));
+
+	return retimer;
+}
+EXPORT_SYMBOL_GPL(fwnode_typec_retimer_get);
+
+/**
+ * typec_retimer_put - Release handle to a retimer.
+ * @retimer: USB Type-C Connector Retimer.
+ *
+ * Decrements reference count for @retimer.
+ */
+void typec_retimer_put(struct typec_retimer *retimer)
+{
+	if (!IS_ERR_OR_NULL(retimer)) {
+		module_put(retimer->dev.parent->driver->owner);
+		put_device(&retimer->dev);
+	}
+}
+EXPORT_SYMBOL_GPL(typec_retimer_put);
+
+int typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state)
+{
+	if (IS_ERR_OR_NULL(retimer))
+		return 0;
+
+	return retimer->set(retimer, state);
+}
+EXPORT_SYMBOL_GPL(typec_retimer_set);
+
+static void typec_retimer_release(struct device *dev)
+{
+	kfree(to_typec_retimer(dev));
+}
+
+static const struct device_type typec_retimer_dev_type = {
+	.name = "retimer_switch",
+	.release = typec_retimer_release,
+};
+
+/**
+ * typec_retimer_register - Register a retimer device.
+ * @parent: Parent device.
+ * @desc: Retimer description.
+ *
+ * Some USB Type-C connectors have their physical lines routed through retimers before they
+ * reach muxes or host controllers. In some cases (for example: using alternate modes)
+ * these retimers need to be reconfigured appropriately. This function registers retimer
+ * switches which route and potentially modify the signals on the Type C physical lines
+ * enroute to the host controllers.
+ */
+struct typec_retimer *
+typec_retimer_register(struct device *parent, const struct typec_retimer_desc *desc)
+{
+	struct typec_retimer *retimer;
+	int ret;
+
+	if (!desc || !desc->set)
+		return ERR_PTR(-EINVAL);
+
+	retimer = kzalloc(sizeof(*retimer), GFP_KERNEL);
+	if (!retimer)
+		return ERR_PTR(-ENOMEM);
+
+	retimer->set = desc->set;
+
+	device_initialize(&retimer->dev);
+	retimer->dev.parent = parent;
+	retimer->dev.fwnode = desc->fwnode;
+	retimer->dev.class = &typec_retimer_class;
+	retimer->dev.type = &typec_retimer_dev_type;
+	retimer->dev.driver_data = desc->drvdata;
+	dev_set_name(&retimer->dev, "%s-retimer",
+		     desc->name ? desc->name : dev_name(parent));
+
+	ret = device_add(&retimer->dev);
+	if (ret) {
+		dev_err(parent, "failed to register retimer (%d)\n", ret);
+		put_device(&retimer->dev);
+		return ERR_PTR(ret);
+	}
+
+	return retimer;
+}
+EXPORT_SYMBOL_GPL(typec_retimer_register);
+
+/**
+ * typec_retimer_unregister - Unregister retimer device.
+ * @retimer: USB Type-C Connector retimer.
+ *
+ * Unregister retimer that was registered with typec_retimer_register().
+ */
+void typec_retimer_unregister(struct typec_retimer *retimer)
+{
+	if (!IS_ERR_OR_NULL(retimer))
+		device_unregister(&retimer->dev);
+}
+EXPORT_SYMBOL_GPL(typec_retimer_unregister);
+
+void *typec_retimer_get_drvdata(struct typec_retimer *retimer)
+{
+	return dev_get_drvdata(&retimer->dev);
+}
+EXPORT_SYMBOL_GPL(typec_retimer_get_drvdata);
+
+struct class typec_retimer_class = {
+	.name = "typec_retimer",
+	.owner = THIS_MODULE,
+};
diff --git a/drivers/usb/typec/retimer.h b/drivers/usb/typec/retimer.h
new file mode 100644
index 000000000000..fa15951d4846
--- /dev/null
+++ b/drivers/usb/typec/retimer.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __USB_TYPEC_RETIMER__
+#define __USB_TYPEC_RETIMER__
+
+#include <linux/usb/typec_retimer.h>
+
+struct typec_retimer {
+	struct device dev;
+	typec_retimer_set_fn_t set;
+};
+
+#define to_typec_retimer(_dev_) container_of(_dev_, struct typec_retimer, dev)
+
+#endif /* __USB_TYPEC_RETIMER__ */
diff --git a/include/linux/usb/typec_retimer.h b/include/linux/usb/typec_retimer.h
new file mode 100644
index 000000000000..5e036b3360e2
--- /dev/null
+++ b/include/linux/usb/typec_retimer.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __USB_TYPEC_RETIMER
+#define __USB_TYPEC_RETIMER
+
+#include <linux/property.h>
+#include <linux/usb/typec.h>
+
+struct device;
+struct typec_retimer;
+struct typec_altmode;
+struct fwnode_handle;
+
+struct typec_retimer_state {
+	struct typec_altmode *alt;
+	unsigned long mode;
+	void *data;
+};
+
+typedef int (*typec_retimer_set_fn_t)(struct typec_retimer *retimer,
+				      struct typec_retimer_state *state);
+
+struct typec_retimer_desc {
+	struct fwnode_handle *fwnode;
+	typec_retimer_set_fn_t set;
+	const char *name;
+	void *drvdata;
+};
+
+struct typec_retimer *fwnode_typec_retimer_get(struct fwnode_handle *fwnode);
+void typec_retimer_put(struct typec_retimer *retimer);
+int typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state);
+
+static inline struct typec_retimer *typec_retimer_get(struct device *dev)
+{
+	return fwnode_typec_retimer_get(dev_fwnode(dev));
+}
+
+struct typec_retimer *
+typec_retimer_register(struct device *parent, const struct typec_retimer_desc *desc);
+void typec_retimer_unregister(struct typec_retimer *retimer);
+
+void *typec_retimer_get_drvdata(struct typec_retimer *retimer);
+
+#endif /* __USB_TYPEC_RETIMER */
-- 
2.37.0.rc0.161.g10f37bed90-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/9] usb: typec: Add retimer handle to port
  2022-06-29 23:32 [PATCH 0/9] platform/chrome: Type-C switch driver and Type-C framework updates Prashant Malani
  2022-06-29 23:32 ` [PATCH 1/9] usb: typec: Add support for retimers Prashant Malani
@ 2022-06-29 23:32 ` Prashant Malani
  2022-06-30  8:27   ` Heikki Krogerus
  2022-06-29 23:32 ` [PATCH 3/9] platform/chrome: Add Type-C mux set command definitions Prashant Malani
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Prashant Malani @ 2022-06-29 23:32 UTC (permalink / raw)
  To: linux-kernel, linux-usb, chrome-platform
  Cc: bleung, heikki.krogerus, Prashant Malani, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel

Similar to mux and orientation switch, add a handle for registered
retimer to the port, so that it has handles to the various switches
connected to it.

Signed-off-by: Prashant Malani <pmalani@chromium.org>
---
 drivers/usb/typec/class.c | 8 ++++++++
 drivers/usb/typec/class.h | 1 +
 2 files changed, 9 insertions(+)

diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 2fa0b3718d23..2bc5fbdb25dd 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/usb/pd_vdo.h>
 #include <linux/usb/typec_mux.h>
+#include <linux/usb/typec_retimer.h>
 
 #include "bus.h"
 #include "class.h"
@@ -2249,6 +2250,13 @@ struct typec_port *typec_register_port(struct device *parent,
 		return ERR_PTR(ret);
 	}
 
+	port->retimer = typec_retimer_get(&port->dev);
+	if (IS_ERR(port->retimer)) {
+		ret = PTR_ERR(port->retimer);
+		put_device(&port->dev);
+		return ERR_PTR(ret);
+	}
+
 	ret = device_add(&port->dev);
 	if (ret) {
 		dev_err(parent, "failed to register port (%d)\n", ret);
diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h
index 1bb1da124109..97520406929e 100644
--- a/drivers/usb/typec/class.h
+++ b/drivers/usb/typec/class.h
@@ -55,6 +55,7 @@ struct typec_port {
 	enum typec_orientation		orientation;
 	struct typec_switch		*sw;
 	struct typec_mux		*mux;
+	struct typec_retimer		*retimer;
 
 	const struct typec_capability	*cap;
 	const struct typec_operations   *ops;
-- 
2.37.0.rc0.161.g10f37bed90-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 3/9] platform/chrome: Add Type-C mux set command definitions
  2022-06-29 23:32 [PATCH 0/9] platform/chrome: Type-C switch driver and Type-C framework updates Prashant Malani
  2022-06-29 23:32 ` [PATCH 1/9] usb: typec: Add support for retimers Prashant Malani
  2022-06-29 23:32 ` [PATCH 2/9] usb: typec: Add retimer handle to port Prashant Malani
@ 2022-06-29 23:32 ` Prashant Malani
  2022-06-29 23:32 ` [PATCH 4/9] platform/chrome: cros_typec_switch: Add switch driver Prashant Malani
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Prashant Malani @ 2022-06-29 23:32 UTC (permalink / raw)
  To: linux-kernel, linux-usb, chrome-platform
  Cc: bleung, heikki.krogerus, Prashant Malani, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel, Tzung-Bi Shih

Copy EC header definitions for the USB Type-C Mux control command from
the EC code base. Also pull in "TBT_UFP_REPLY" definitions, since that
is the prior entry in the enum.

These headers are already present in the EC code base. [1]

[1] https://chromium.googlesource.com/chromiumos/platform/ec/+/b80f85a94a423273c1638ef7b662c56931a138dd/include/ec_commands.h

Signed-off-by: Prashant Malani <pmalani@chromium.org>
---
 include/linux/platform_data/cros_ec_commands.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index 8cfa8cfca77e..a3945c5e7f50 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -5722,8 +5722,21 @@ enum typec_control_command {
 	TYPEC_CONTROL_COMMAND_EXIT_MODES,
 	TYPEC_CONTROL_COMMAND_CLEAR_EVENTS,
 	TYPEC_CONTROL_COMMAND_ENTER_MODE,
+	TYPEC_CONTROL_COMMAND_TBT_UFP_REPLY,
+	TYPEC_CONTROL_COMMAND_USB_MUX_SET,
 };
 
+/* Replies the AP may specify to the TBT EnterMode command as a UFP */
+enum typec_tbt_ufp_reply {
+	TYPEC_TBT_UFP_REPLY_NAK,
+	TYPEC_TBT_UFP_REPLY_ACK,
+};
+
+struct typec_usb_mux_set {
+	uint8_t mux_index;	/* Index of the mux to set in the chain */
+	uint8_t mux_flags;	/* USB_PD_MUX_*-encoded USB mux state to set */
+} __ec_align1;
+
 struct ec_params_typec_control {
 	uint8_t port;
 	uint8_t command;	/* enum typec_control_command */
@@ -5737,6 +5750,8 @@ struct ec_params_typec_control {
 	union {
 		uint32_t clear_events_mask;
 		uint8_t mode_to_enter;      /* enum typec_mode */
+		uint8_t tbt_ufp_reply;      /* enum typec_tbt_ufp_reply */
+		struct typec_usb_mux_set mux_params;
 		uint8_t placeholder[128];
 	};
 } __ec_align1;
@@ -5815,6 +5830,9 @@ enum tcpc_cc_polarity {
 #define PD_STATUS_EVENT_SOP_DISC_DONE		BIT(0)
 #define PD_STATUS_EVENT_SOP_PRIME_DISC_DONE	BIT(1)
 #define PD_STATUS_EVENT_HARD_RESET		BIT(2)
+#define PD_STATUS_EVENT_DISCONNECTED		BIT(3)
+#define PD_STATUS_EVENT_MUX_0_SET_DONE		BIT(4)
+#define PD_STATUS_EVENT_MUX_1_SET_DONE		BIT(5)
 
 struct ec_params_typec_status {
 	uint8_t port;
-- 
2.37.0.rc0.161.g10f37bed90-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 4/9] platform/chrome: cros_typec_switch: Add switch driver
  2022-06-29 23:32 [PATCH 0/9] platform/chrome: Type-C switch driver and Type-C framework updates Prashant Malani
                   ` (2 preceding siblings ...)
  2022-06-29 23:32 ` [PATCH 3/9] platform/chrome: Add Type-C mux set command definitions Prashant Malani
@ 2022-06-29 23:32 ` Prashant Malani
  2022-06-29 23:32 ` [PATCH 5/9] platform/chrome: cros_typec_switch: Set EC retimer Prashant Malani
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Prashant Malani @ 2022-06-29 23:32 UTC (permalink / raw)
  To: linux-kernel, linux-usb, chrome-platform
  Cc: bleung, heikki.krogerus, Prashant Malani, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel

Introduce a driver to configure USB Type-C mode switches and retimers
which are controlled by the Chrome OS EC (Embedded Controller).
This allows Type-C port drivers, as well as alternate mode drivers to
configure their relevant mode switches and retimers according to the
Type-C state they want to achieve.

ACPI devices with ID GOOG001A will bind to this driver.

Currently, we only register a retimer switch with a stub set function.
Subsequent patches will implement the host command set functionality,
and introduce mode switches.

Signed-off-by: Prashant Malani <pmalani@chromium.org>
---
 MAINTAINERS                                 |   1 +
 drivers/platform/chrome/Kconfig             |  11 ++
 drivers/platform/chrome/Makefile            |   1 +
 drivers/platform/chrome/cros_typec_switch.c | 171 ++++++++++++++++++++
 4 files changed, 184 insertions(+)
 create mode 100644 drivers/platform/chrome/cros_typec_switch.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 7533cb27adc0..35ea91c619b7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4752,6 +4752,7 @@ M:	Prashant Malani <pmalani@chromium.org>
 L:	chrome-platform@lists.linux.dev
 S:	Maintained
 F:	drivers/platform/chrome/cros_ec_typec.c
+F:	drivers/platform/chrome/cros_typec_switch.c
 
 CHROMEOS EC USB PD NOTIFY DRIVER
 M:	Prashant Malani <pmalani@chromium.org>
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index 717299cbccac..c62a514a087f 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -265,6 +265,17 @@ config CHROMEOS_PRIVACY_SCREEN
 	  this should probably always be built into the kernel to avoid or
 	  minimize drm probe deferral.
 
+config CROS_TYPEC_SWITCH
+	tristate "ChromeOS EC Type-C Switch Control"
+	depends on MFD_CROS_EC_DEV && TYPEC
+	default MFD_CROS_EC_DEV
+	help
+	  If you say Y here, you get support for configuring the Chrome OS EC Type C
+	  muxes and retimers.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called cros_typec_switch.
+
 source "drivers/platform/chrome/wilco_ec/Kconfig"
 
 endif # CHROMEOS_PLATFORMS
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index 52f5a2dde8b8..0dcaf6a7ed27 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_CHROMEOS_TBMC)		+= chromeos_tbmc.o
 obj-$(CONFIG_CROS_EC)			+= cros_ec.o
 obj-$(CONFIG_CROS_EC_I2C)		+= cros_ec_i2c.o
 obj-$(CONFIG_CROS_EC_ISHTP)		+= cros_ec_ishtp.o
+obj-$(CONFIG_CROS_TYPEC_SWITCH)		+= cros_typec_switch.o
 obj-$(CONFIG_CROS_EC_RPMSG)		+= cros_ec_rpmsg.o
 obj-$(CONFIG_CROS_EC_SPI)		+= cros_ec_spi.o
 cros_ec_lpcs-objs			:= cros_ec_lpc.o cros_ec_lpc_mec.o
diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c
new file mode 100644
index 000000000000..1a795f613543
--- /dev/null
+++ b/drivers/platform/chrome/cros_typec_switch.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2022 Google LLC
+ *
+ * This driver provides the ability to configure Type C muxes and retimers which are controlled by
+ * the Chrome OS EC.
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/platform_data/cros_ec_commands.h>
+#include <linux/platform_device.h>
+#include <linux/usb/typec_retimer.h>
+
+#define DRV_NAME "cros-typec-switch"
+
+/* Handles and other relevant data required for each port's switches. */
+struct cros_typec_port {
+	int port_num;
+	struct typec_retimer *retimer;
+	struct cros_typec_switch_data *sdata;
+};
+
+/* Driver-specific data. */
+struct cros_typec_switch_data {
+	struct device *dev;
+	struct cros_ec_device *ec;
+	struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS];
+};
+
+static int
+cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state)
+{
+	return 0;
+}
+
+void cros_typec_unregister_switches(struct cros_typec_switch_data *sdata)
+{
+	int i;
+
+	for (i = 0; i < EC_USB_PD_MAX_PORTS; i++) {
+		if (!sdata->ports[i])
+			continue;
+		typec_retimer_unregister(sdata->ports[i]->retimer);
+	}
+}
+
+int cros_typec_register_retimer(struct cros_typec_port *port, struct fwnode_handle *fwnode)
+{
+	struct typec_retimer_desc retimer_desc = {
+		.fwnode = fwnode,
+		.drvdata = port,
+		.name = fwnode_get_name(fwnode),
+		.set = cros_typec_retimer_set,
+	};
+
+	port->retimer = typec_retimer_register(port->sdata->dev, &retimer_desc);
+	if (IS_ERR(port->retimer))
+		return PTR_ERR(port->retimer);
+
+	return 0;
+}
+
+static int cros_typec_register_switches(struct cros_typec_switch_data *sdata)
+{
+	struct cros_typec_port *port = NULL;
+	struct device *dev = sdata->dev;
+	struct fwnode_handle *fwnode;
+	struct acpi_device *adev;
+	unsigned long long index;
+	int ret = 0;
+	int nports;
+
+	nports = device_get_child_node_count(dev);
+	if (nports == 0) {
+		dev_err(dev, "No switch devices found.\n");
+		return -ENODEV;
+	}
+
+	device_for_each_child_node(dev, fwnode) {
+		port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+		if (!port) {
+			ret = -ENOMEM;
+			goto err_switch;
+		}
+
+		adev = to_acpi_device_node(fwnode);
+		if (!adev) {
+			dev_err(fwnode->dev, "Couldn't get ACPI device handle\n");
+			ret = -ENODEV;
+			goto err_switch;
+		}
+
+		ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index);
+		if (ACPI_FAILURE(ret)) {
+			dev_err(fwnode->dev, "_ADR wasn't evaluated\n");
+			ret = -ENODATA;
+			goto err_switch;
+		}
+
+		if (index < 0 || index >= EC_USB_PD_MAX_PORTS) {
+			dev_err(fwnode->dev, "Invalid port index number: %llu", index);
+			ret = -EINVAL;
+			goto err_switch;
+		}
+		port->sdata = sdata;
+		port->port_num = index;
+		sdata->ports[index] = port;
+
+		ret = cros_typec_register_retimer(port, fwnode);
+		if (ret) {
+			dev_err(dev, "Retimer switch register failed\n");
+			goto err_switch;
+		}
+
+		dev_dbg(dev, "Retimer switch registered for index %llu\n", index);
+	}
+
+	return 0;
+err_switch:
+	cros_typec_unregister_switches(sdata);
+	return ret;
+}
+
+static int cros_typec_switch_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cros_typec_switch_data *sdata;
+
+	sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL);
+	if (!sdata)
+		return -ENOMEM;
+
+	sdata->dev = dev;
+	sdata->ec = dev_get_drvdata(pdev->dev.parent);
+
+	platform_set_drvdata(pdev, sdata);
+
+	return cros_typec_register_switches(sdata);
+}
+
+static int cros_typec_switch_remove(struct platform_device *pdev)
+{
+	struct cros_typec_switch_data *sdata = platform_get_drvdata(pdev);
+
+	cros_typec_unregister_switches(sdata);
+	return 0;
+}
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cros_typec_switch_acpi_id[] = {
+	{ "GOOG001A", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, cros_typec_switch_acpi_id);
+#endif
+
+static struct platform_driver cros_typec_switch_driver = {
+	.driver	= {
+		.name = DRV_NAME,
+		.acpi_match_table = ACPI_PTR(cros_typec_switch_acpi_id),
+	},
+	.probe = cros_typec_switch_probe,
+	.remove = cros_typec_switch_remove,
+};
+
+module_platform_driver(cros_typec_switch_driver);
+
+MODULE_AUTHOR("Prashant Malani <pmalani@chromium.org>");
+MODULE_DESCRIPTION("Chrome OS EC Type C Switch control");
+MODULE_LICENSE("GPL");
-- 
2.37.0.rc0.161.g10f37bed90-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 5/9] platform/chrome: cros_typec_switch: Set EC retimer
  2022-06-29 23:32 [PATCH 0/9] platform/chrome: Type-C switch driver and Type-C framework updates Prashant Malani
                   ` (3 preceding siblings ...)
  2022-06-29 23:32 ` [PATCH 4/9] platform/chrome: cros_typec_switch: Add switch driver Prashant Malani
@ 2022-06-29 23:32 ` Prashant Malani
  2022-06-29 23:32 ` [PATCH 6/9] platform/chrome: cros_typec_switch: Add event check Prashant Malani
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Prashant Malani @ 2022-06-29 23:32 UTC (permalink / raw)
  To: linux-kernel, linux-usb, chrome-platform
  Cc: bleung, heikki.krogerus, Prashant Malani, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel, Tzung-Bi Shih

Invoke Chrome EC host commands to set EC-controlled retimer switches to
the state the Type-C framework instructs.

Signed-off-by: Prashant Malani <pmalani@chromium.org>
---
 drivers/platform/chrome/cros_typec_switch.c | 56 ++++++++++++++++++++-
 1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c
index 1a795f613543..9faa442dd81a 100644
--- a/drivers/platform/chrome/cros_typec_switch.c
+++ b/drivers/platform/chrome/cros_typec_switch.c
@@ -9,7 +9,10 @@
 #include <linux/acpi.h>
 #include <linux/module.h>
 #include <linux/platform_data/cros_ec_commands.h>
+#include <linux/platform_data/cros_ec_proto.h>
 #include <linux/platform_device.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_dp.h>
 #include <linux/usb/typec_retimer.h>
 
 #define DRV_NAME "cros-typec-switch"
@@ -28,10 +31,61 @@ struct cros_typec_switch_data {
 	struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS];
 };
 
+static int cros_typec_cmd_mux_set(struct cros_typec_switch_data *sdata, int port_num, u8 index,
+				  u8 state)
+{
+	struct typec_usb_mux_set params = {
+		.mux_index = index,
+		.mux_flags = state,
+	};
+
+	struct ec_params_typec_control req = {
+		.port = port_num,
+		.command = TYPEC_CONTROL_COMMAND_USB_MUX_SET,
+		.mux_params = params,
+	};
+
+	return cros_ec_command(sdata->ec, 0, EC_CMD_TYPEC_CONTROL, &req,
+			       sizeof(req), NULL, 0);
+}
+
+static int cros_typec_get_mux_state(unsigned long mode, struct typec_altmode *alt)
+{
+	int ret = -EOPNOTSUPP;
+
+	if (mode == TYPEC_STATE_SAFE)
+		ret = USB_PD_MUX_SAFE_MODE;
+	else if (mode == TYPEC_STATE_USB)
+		ret = USB_PD_MUX_USB_ENABLED;
+	else if (alt && alt->svid == USB_TYPEC_DP_SID)
+		ret = USB_PD_MUX_DP_ENABLED;
+
+	return ret;
+}
+
+/*
+ * The Chrome EC treats both mode-switches and retimers as "muxes" for the purposes of the
+ * host command API. This common function configures and verifies the retimer/mode-switch
+ * according to the provided setting.
+ */
+static int cros_typec_configure_mux(struct cros_typec_switch_data *sdata, int port_num, int index,
+				    unsigned long mode, struct typec_altmode *alt)
+{
+	int ret = cros_typec_get_mux_state(mode, alt);
+
+	if (ret < 0)
+		return ret;
+
+	return cros_typec_cmd_mux_set(sdata, port_num, index, (u8)ret);
+}
+
 static int
 cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state)
 {
-	return 0;
+	struct cros_typec_port *port = typec_retimer_get_drvdata(retimer);
+
+	/* Retimers have index 1. */
+	return cros_typec_configure_mux(port->sdata, port->port_num, 1, state->mode, state->alt);
 }
 
 void cros_typec_unregister_switches(struct cros_typec_switch_data *sdata)
-- 
2.37.0.rc0.161.g10f37bed90-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 6/9] platform/chrome: cros_typec_switch: Add event check
  2022-06-29 23:32 [PATCH 0/9] platform/chrome: Type-C switch driver and Type-C framework updates Prashant Malani
                   ` (4 preceding siblings ...)
  2022-06-29 23:32 ` [PATCH 5/9] platform/chrome: cros_typec_switch: Set EC retimer Prashant Malani
@ 2022-06-29 23:32 ` Prashant Malani
  2022-06-29 23:32 ` [PATCH 7/9] platform/chrome: cros_typec_switch: Register mode switches Prashant Malani
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Prashant Malani @ 2022-06-29 23:32 UTC (permalink / raw)
  To: linux-kernel, linux-usb, chrome-platform
  Cc: bleung, heikki.krogerus, Prashant Malani, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel, Tzung-Bi Shih

The Chrome EC updates Type-C status events when mux set requests from
the Application Processor (AP) are completed. Add a check to the
flow of configuring muxes to look for this status done bit, so that
the driver is aware that the mux set completed successfully or not.

Signed-off-by: Prashant Malani <pmalani@chromium.org>
---
 drivers/platform/chrome/cros_typec_switch.c | 72 ++++++++++++++++++++-
 1 file changed, 70 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c
index 9faa442dd81a..a226f828514f 100644
--- a/drivers/platform/chrome/cros_typec_switch.c
+++ b/drivers/platform/chrome/cros_typec_switch.c
@@ -7,6 +7,8 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <linux/module.h>
 #include <linux/platform_data/cros_ec_commands.h>
 #include <linux/platform_data/cros_ec_proto.h>
@@ -63,6 +65,40 @@ static int cros_typec_get_mux_state(unsigned long mode, struct typec_altmode *al
 	return ret;
 }
 
+static int cros_typec_send_clear_event(struct cros_typec_switch_data *sdata, int port_num,
+				       u32 events_mask)
+{
+	struct ec_params_typec_control req = {
+		.port = port_num,
+		.command = TYPEC_CONTROL_COMMAND_CLEAR_EVENTS,
+		.clear_events_mask = events_mask,
+	};
+
+	return cros_ec_command(sdata->ec, 0, EC_CMD_TYPEC_CONTROL, &req,
+			       sizeof(req), NULL, 0);
+}
+
+bool cros_typec_check_event(struct cros_typec_switch_data *sdata, int port_num, u32 mask)
+{
+	struct ec_response_typec_status resp;
+	struct ec_params_typec_status req = {
+		.port = port_num,
+	};
+	int ret;
+
+	ret = cros_ec_command(sdata->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req),
+			      &resp, sizeof(resp));
+	if (ret < 0) {
+		dev_warn(sdata->dev, "EC_CMD_TYPEC_STATUS failed for port: %d\n", port_num);
+		return false;
+	}
+
+	if (resp.events & mask)
+		return true;
+
+	return false;
+}
+
 /*
  * The Chrome EC treats both mode-switches and retimers as "muxes" for the purposes of the
  * host command API. This common function configures and verifies the retimer/mode-switch
@@ -71,12 +107,44 @@ static int cros_typec_get_mux_state(unsigned long mode, struct typec_altmode *al
 static int cros_typec_configure_mux(struct cros_typec_switch_data *sdata, int port_num, int index,
 				    unsigned long mode, struct typec_altmode *alt)
 {
-	int ret = cros_typec_get_mux_state(mode, alt);
+	unsigned long end;
+	u32 event_mask;
+	u8 mux_state;
+	int ret;
+
+	ret = cros_typec_get_mux_state(mode, alt);
+	if (ret < 0)
+		return ret;
+	mux_state = (u8)ret;
 
+	/* Clear any old mux set done event. */
+	if (index == 0)
+		event_mask = PD_STATUS_EVENT_MUX_0_SET_DONE;
+	else
+		event_mask = PD_STATUS_EVENT_MUX_1_SET_DONE;
+
+	ret = cros_typec_send_clear_event(sdata, port_num, event_mask);
+	if (ret < 0)
+		return ret;
+
+	/* Send the set command. */
+	ret = cros_typec_cmd_mux_set(sdata, port_num, index, mux_state);
 	if (ret < 0)
 		return ret;
 
-	return cros_typec_cmd_mux_set(sdata, port_num, index, (u8)ret);
+	/* Check for the mux set done event. */
+	end = jiffies + msecs_to_jiffies(1000);
+	do {
+		if (cros_typec_check_event(sdata, port_num, event_mask))
+			return 0;
+
+		usleep_range(500, 1000);
+	} while (time_before(jiffies, end));
+
+	dev_err(sdata->dev, "Timed out waiting for mux set done on index: %d, state: %d\n",
+		index, mux_state);
+
+	return -ETIMEDOUT;
 }
 
 static int
-- 
2.37.0.rc0.161.g10f37bed90-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 7/9] platform/chrome: cros_typec_switch: Register mode switches
  2022-06-29 23:32 [PATCH 0/9] platform/chrome: Type-C switch driver and Type-C framework updates Prashant Malani
                   ` (5 preceding siblings ...)
  2022-06-29 23:32 ` [PATCH 6/9] platform/chrome: cros_typec_switch: Add event check Prashant Malani
@ 2022-06-29 23:32 ` Prashant Malani
  2022-06-29 23:32 ` [PATCH 8/9] platform/chrome: cros_ec_typec: Cleanup switch handle return paths Prashant Malani
  2022-06-29 23:32 ` [PATCH 9/9] platform/chrome: cros_ec_typec: Get retimer handle Prashant Malani
  8 siblings, 0 replies; 15+ messages in thread
From: Prashant Malani @ 2022-06-29 23:32 UTC (permalink / raw)
  To: linux-kernel, linux-usb, chrome-platform
  Cc: bleung, heikki.krogerus, Prashant Malani, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel

Register mode switch devices for Type C connectors, when they are
specified by firmware. These control Type C configuration for any USB
Type-C mode switches (sometimes known as "muxes") which are controlled
by the Chrome EC.

Signed-off-by: Prashant Malani <pmalani@chromium.org>
---
 drivers/platform/chrome/cros_typec_switch.c | 39 +++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c
index a226f828514f..2ea42e6596b9 100644
--- a/drivers/platform/chrome/cros_typec_switch.c
+++ b/drivers/platform/chrome/cros_typec_switch.c
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/usb/typec_altmode.h>
 #include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
 #include <linux/usb/typec_retimer.h>
 
 #define DRV_NAME "cros-typec-switch"
@@ -22,6 +23,7 @@
 /* Handles and other relevant data required for each port's switches. */
 struct cros_typec_port {
 	int port_num;
+	struct typec_mux_dev *mode_switch;
 	struct typec_retimer *retimer;
 	struct cros_typec_switch_data *sdata;
 };
@@ -147,6 +149,15 @@ static int cros_typec_configure_mux(struct cros_typec_switch_data *sdata, int po
 	return -ETIMEDOUT;
 }
 
+static int
+cros_typec_mode_switch_set(struct typec_mux_dev *mode_switch, struct typec_mux_state *state)
+{
+	struct cros_typec_port *port = typec_mux_get_drvdata(mode_switch);
+
+	/* Mode switches have index 0. */
+	return cros_typec_configure_mux(port->sdata, port->port_num, 0, state->mode, state->alt);
+}
+
 static int
 cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state)
 {
@@ -164,9 +175,26 @@ void cros_typec_unregister_switches(struct cros_typec_switch_data *sdata)
 		if (!sdata->ports[i])
 			continue;
 		typec_retimer_unregister(sdata->ports[i]->retimer);
+		typec_mux_unregister(sdata->ports[i]->mode_switch);
 	}
 }
 
+int cros_typec_register_mode_switch(struct cros_typec_port *port, struct fwnode_handle *fwnode)
+{
+	struct typec_mux_desc mode_switch_desc = {
+		.fwnode = fwnode,
+		.drvdata = port,
+		.name = fwnode_get_name(fwnode),
+		.set = cros_typec_mode_switch_set,
+	};
+
+	port->mode_switch = typec_mux_register(port->sdata->dev, &mode_switch_desc);
+	if (IS_ERR(port->mode_switch))
+		return PTR_ERR(port->mode_switch);
+
+	return 0;
+}
+
 int cros_typec_register_retimer(struct cros_typec_port *port, struct fwnode_handle *fwnode)
 {
 	struct typec_retimer_desc retimer_desc = {
@@ -236,6 +264,17 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata)
 		}
 
 		dev_dbg(dev, "Retimer switch registered for index %llu\n", index);
+
+		if (!fwnode_property_read_bool(fwnode, "mode-switch"))
+			continue;
+
+		ret = cros_typec_register_mode_switch(port, fwnode);
+		if (ret) {
+			dev_err(dev, "Mode switch register failed\n");
+			goto err_switch;
+		}
+
+		dev_dbg(dev, "Mode switch registered for index %llu\n", index);
 	}
 
 	return 0;
-- 
2.37.0.rc0.161.g10f37bed90-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 8/9] platform/chrome: cros_ec_typec: Cleanup switch handle return paths
  2022-06-29 23:32 [PATCH 0/9] platform/chrome: Type-C switch driver and Type-C framework updates Prashant Malani
                   ` (6 preceding siblings ...)
  2022-06-29 23:32 ` [PATCH 7/9] platform/chrome: cros_typec_switch: Register mode switches Prashant Malani
@ 2022-06-29 23:32 ` Prashant Malani
  2022-06-29 23:32 ` [PATCH 9/9] platform/chrome: cros_ec_typec: Get retimer handle Prashant Malani
  8 siblings, 0 replies; 15+ messages in thread
From: Prashant Malani @ 2022-06-29 23:32 UTC (permalink / raw)
  To: linux-kernel, linux-usb, chrome-platform
  Cc: bleung, heikki.krogerus, Prashant Malani, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel, Tzung-Bi Shih

Some of the return paths for the cros_typec_get_switch_handles()
aren't necessary. Clean up the return paths to only undo the handle
get's which succeeded.

Signed-off-by: Prashant Malani <pmalani@chromium.org>
---
 drivers/platform/chrome/cros_ec_typec.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 7cb2e35c4ded..39e6fd4491a9 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -157,12 +157,10 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port,
 	return 0;
 
 role_sw_err:
-	usb_role_switch_put(port->role_sw);
-ori_sw_err:
 	typec_switch_put(port->ori_sw);
-mux_err:
+ori_sw_err:
 	typec_mux_put(port->mux);
-
+mux_err:
 	return -ENODEV;
 }
 
-- 
2.37.0.rc0.161.g10f37bed90-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 9/9] platform/chrome: cros_ec_typec: Get retimer handle
  2022-06-29 23:32 [PATCH 0/9] platform/chrome: Type-C switch driver and Type-C framework updates Prashant Malani
                   ` (7 preceding siblings ...)
  2022-06-29 23:32 ` [PATCH 8/9] platform/chrome: cros_ec_typec: Cleanup switch handle return paths Prashant Malani
@ 2022-06-29 23:32 ` Prashant Malani
  8 siblings, 0 replies; 15+ messages in thread
From: Prashant Malani @ 2022-06-29 23:32 UTC (permalink / raw)
  To: linux-kernel, linux-usb, chrome-platform
  Cc: bleung, heikki.krogerus, Prashant Malani, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel, Tzung-Bi Shih

Where available, obtain the handle to retimer switch specified via
firmware, and update the mux configuration callsites to add retimer
support for supported modes.

Signed-off-by: Prashant Malani <pmalani@chromium.org>
---
 drivers/platform/chrome/cros_ec_typec.c | 44 +++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 3 deletions(-)

diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 39e6fd4491a9..38c4ac754ea9 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -20,6 +20,7 @@
 #include <linux/usb/typec_altmode.h>
 #include <linux/usb/typec_dp.h>
 #include <linux/usb/typec_mux.h>
+#include <linux/usb/typec_retimer.h>
 #include <linux/usb/typec_tbt.h>
 #include <linux/usb/role.h>
 
@@ -53,6 +54,7 @@ struct cros_typec_port {
 	struct usb_pd_identity c_identity;
 	struct typec_switch *ori_sw;
 	struct typec_mux *mux;
+	struct typec_retimer *retimer;
 	struct usb_role_switch *role_sw;
 
 	/* Variables keeping track of switch state. */
@@ -142,6 +144,12 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port,
 		goto mux_err;
 	}
 
+	port->retimer = fwnode_typec_retimer_get(fwnode);
+	if (IS_ERR(port->retimer)) {
+		dev_dbg(dev, "Retimer handle not found.\n");
+		goto retimer_sw_err;
+	}
+
 	port->ori_sw = fwnode_typec_switch_get(fwnode);
 	if (IS_ERR(port->ori_sw)) {
 		dev_dbg(dev, "Orientation switch handle not found.\n");
@@ -159,6 +167,8 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port,
 role_sw_err:
 	typec_switch_put(port->ori_sw);
 ori_sw_err:
+	typec_retimer_put(port->retimer);
+retimer_sw_err:
 	typec_mux_put(port->mux);
 mux_err:
 	return -ENODEV;
@@ -203,6 +213,21 @@ static void cros_typec_unregister_altmodes(struct cros_typec_data *typec, int po
 	}
 }
 
+/*
+ * Map the Type-C Mux state to retimer state and call the retimer set function. We need this
+ * because we re-use the Type-C mux state for retimers.
+ */
+static int cros_typec_retimer_set(struct typec_retimer  *retimer, struct typec_mux_state state)
+{
+	struct typec_retimer_state rstate = {
+		.alt = state.alt,
+		.mode = state.mode,
+		.data = state.data,
+	};
+
+	return typec_retimer_set(retimer, &rstate);
+}
+
 static int cros_typec_usb_disconnect_state(struct cros_typec_port *port)
 {
 	port->state.alt = NULL;
@@ -211,6 +236,7 @@ static int cros_typec_usb_disconnect_state(struct cros_typec_port *port)
 
 	usb_role_switch_set_role(port->role_sw, USB_ROLE_NONE);
 	typec_switch_set(port->ori_sw, TYPEC_ORIENTATION_NONE);
+	cros_typec_retimer_set(port->retimer, port->state);
 
 	return typec_mux_set(port->mux, &port->state);
 }
@@ -381,9 +407,14 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
 
 static int cros_typec_usb_safe_state(struct cros_typec_port *port)
 {
+	int ret;
 	port->state.mode = TYPEC_STATE_SAFE;
 
-	return typec_mux_set(port->mux, &port->state);
+	ret = cros_typec_retimer_set(port->retimer, port->state);
+	if (!ret)
+		ret = typec_mux_set(port->mux, &port->state);
+
+	return ret;
 }
 
 /*
@@ -480,7 +511,11 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec,
 	port->state.data = &dp_data;
 	port->state.mode = TYPEC_MODAL_STATE(ffs(pd_ctrl->dp_mode));
 
-	return typec_mux_set(port->mux, &port->state);
+	ret = cros_typec_retimer_set(port->retimer, port->state);
+	if (!ret)
+		ret = typec_mux_set(port->mux, &port->state);
+
+	return ret;
 }
 
 static int cros_typec_enable_usb4(struct cros_typec_data *typec,
@@ -569,7 +604,10 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
 	} else if (port->mux_flags & USB_PD_MUX_USB_ENABLED) {
 		port->state.alt = NULL;
 		port->state.mode = TYPEC_STATE_USB;
-		ret = typec_mux_set(port->mux, &port->state);
+
+		ret = cros_typec_retimer_set(port->retimer, port->state);
+		if (!ret)
+			ret = typec_mux_set(port->mux, &port->state);
 	} else {
 		dev_dbg(typec->dev,
 			"Unrecognized mode requested, mux flags: %x\n",
-- 
2.37.0.rc0.161.g10f37bed90-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/9] usb: typec: Add support for retimers
  2022-06-29 23:32 ` [PATCH 1/9] usb: typec: Add support for retimers Prashant Malani
@ 2022-06-30  8:17   ` Heikki Krogerus
  2022-06-30 10:18     ` Mika Westerberg
  2022-06-30 17:13     ` Prashant Malani
  0 siblings, 2 replies; 15+ messages in thread
From: Heikki Krogerus @ 2022-06-30  8:17 UTC (permalink / raw)
  To: Prashant Malani
  Cc: linux-kernel, linux-usb, chrome-platform, bleung, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel,
	Mika Westerberg

On Wed, Jun 29, 2022 at 11:32:19PM +0000, Prashant Malani wrote:
> Introduce a retimer device class and associated functions that register
> and use retimer "switch" devices. These operate in a manner similar to
> the "mode-switch" and help configure retimers that exist between the
> Type-C connector and host controller(s).
> 
> Type C ports can be linked to retimers using firmware node device
> references (again, in a manner similar to "mode-switch").
> 
> Signed-off-by: Prashant Malani <pmalani@chromium.org>

Cool! This looks really good to me.

I'll add Mika here, just to keep him in the loop. Thunderbolt/USB4 can
control the same physical retimers over the SBU line. Right now there
is no conflict, but I think we want to later be able to use these
devices to upgrade the retimer firmware, and that is something that
the Thunderbolt/USB4 already does. So let's keep an eye on this.

I wonder, would it make sense to later make the thunderbolt_retimer
devices also part of the device class that's introduced here? I think
that way it would be easier to later figure out which
thunderbolt_retimer and which retimer_switch represent the same
physical retimer. And perhaps it would also be more clear for the user
space to have a single device class for the retimers?

Maybe the device class could be named just "retimer", and the device
type could then be named "typec_retimer" instead of "retimer_switch"?

thanks,

> ---
>  drivers/usb/typec/Makefile        |   2 +-
>  drivers/usb/typec/class.c         |   9 +-
>  drivers/usb/typec/class.h         |   1 +
>  drivers/usb/typec/retimer.c       | 168 ++++++++++++++++++++++++++++++
>  drivers/usb/typec/retimer.h       |  15 +++
>  include/linux/usb/typec_retimer.h |  45 ++++++++
>  6 files changed, 238 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/usb/typec/retimer.c
>  create mode 100644 drivers/usb/typec/retimer.h
>  create mode 100644 include/linux/usb/typec_retimer.h
> 
> diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
> index 2f174cd3e5df..4955d9af0811 100644
> --- a/drivers/usb/typec/Makefile
> +++ b/drivers/usb/typec/Makefile
> @@ -1,6 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0
>  obj-$(CONFIG_TYPEC)		+= typec.o
> -typec-y				:= class.o mux.o bus.o pd.o
> +typec-y				:= class.o mux.o bus.o pd.o retimer.o
>  typec-$(CONFIG_ACPI)		+= port-mapper.o
>  obj-$(CONFIG_TYPEC)		+= altmodes/
>  obj-$(CONFIG_TYPEC_TCPM)	+= tcpm/
> diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
> index bbc46b14f99a..2fa0b3718d23 100644
> --- a/drivers/usb/typec/class.c
> +++ b/drivers/usb/typec/class.c
> @@ -2299,10 +2299,14 @@ static int __init typec_init(void)
>  	if (ret)
>  		goto err_unregister_bus;
>  
> -	ret = class_register(&typec_class);
> +	ret = class_register(&typec_retimer_class);
>  	if (ret)
>  		goto err_unregister_mux_class;
>  
> +	ret = class_register(&typec_class);
> +	if (ret)
> +		goto err_unregister_retimer_class;
> +
>  	ret = usb_power_delivery_init();
>  	if (ret)
>  		goto err_unregister_class;
> @@ -2312,6 +2316,9 @@ static int __init typec_init(void)
>  err_unregister_class:
>  	class_unregister(&typec_class);
>  
> +err_unregister_retimer_class:
> +	class_unregister(&typec_retimer_class);
> +
>  err_unregister_mux_class:
>  	class_unregister(&typec_mux_class);
>  
> diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h
> index b531f9853bc0..1bb1da124109 100644
> --- a/drivers/usb/typec/class.h
> +++ b/drivers/usb/typec/class.h
> @@ -76,6 +76,7 @@ extern const struct device_type typec_port_dev_type;
>  #define is_typec_port(dev) ((dev)->type == &typec_port_dev_type)
>  
>  extern struct class typec_mux_class;
> +extern struct class typec_retimer_class;
>  extern struct class typec_class;
>  
>  #if defined(CONFIG_ACPI)
> diff --git a/drivers/usb/typec/retimer.c b/drivers/usb/typec/retimer.c
> new file mode 100644
> index 000000000000..2fa0aeb9363c
> --- /dev/null
> +++ b/drivers/usb/typec/retimer.c
> @@ -0,0 +1,168 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2022 Google LLC
> + *
> + * USB Type-C Retimer support.
> + * Author: Prashant Malani <pmalani@chromium.org>
> + *
> + */
> +
> +#include <linux/device.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/property.h>
> +#include <linux/slab.h>
> +
> +#include "class.h"
> +#include "retimer.h"
> +
> +static bool dev_name_ends_with(struct device *dev, const char *suffix)
> +{
> +	const char *name = dev_name(dev);
> +	const int name_len = strlen(name);
> +	const int suffix_len = strlen(suffix);
> +
> +	if (suffix_len > name_len)
> +		return false;
> +
> +	return strcmp(name + (name_len - suffix_len), suffix) == 0;
> +}
> +
> +static int retimer_fwnode_match(struct device *dev, const void *fwnode)
> +{
> +	return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-retimer");
> +}
> +
> +static void *typec_retimer_match(struct fwnode_handle *fwnode, const char *id, void *data)
> +{
> +	struct device *dev  = class_find_device(&typec_retimer_class, NULL, fwnode,
> +						retimer_fwnode_match);
> +
> +	return dev ? to_typec_retimer(dev) : ERR_PTR(-EPROBE_DEFER);
> +}
> +
> +/**
> + * fwnode_typec_retimer_get - Find USB Type-C retimer.
> + * @fwnode: The caller device node.
> + *
> + * Finds a retimer linked to the caller. This function is primarily meant for the
> + * Type-C drivers. Returns a reference to the retimer on success, NULL if no
> + * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection
> + * was found but the retimer has not been enumerated yet.
> + */
> +struct typec_retimer *fwnode_typec_retimer_get(struct fwnode_handle *fwnode)
> +{
> +	struct typec_retimer *retimer;
> +
> +	retimer = fwnode_connection_find_match(fwnode, "retimer-switch", NULL, typec_retimer_match);
> +	if (!IS_ERR_OR_NULL(retimer))
> +		WARN_ON(!try_module_get(retimer->dev.parent->driver->owner));
> +
> +	return retimer;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_typec_retimer_get);
> +
> +/**
> + * typec_retimer_put - Release handle to a retimer.
> + * @retimer: USB Type-C Connector Retimer.
> + *
> + * Decrements reference count for @retimer.
> + */
> +void typec_retimer_put(struct typec_retimer *retimer)
> +{
> +	if (!IS_ERR_OR_NULL(retimer)) {
> +		module_put(retimer->dev.parent->driver->owner);
> +		put_device(&retimer->dev);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(typec_retimer_put);
> +
> +int typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state)
> +{
> +	if (IS_ERR_OR_NULL(retimer))
> +		return 0;
> +
> +	return retimer->set(retimer, state);
> +}
> +EXPORT_SYMBOL_GPL(typec_retimer_set);
> +
> +static void typec_retimer_release(struct device *dev)
> +{
> +	kfree(to_typec_retimer(dev));
> +}
> +
> +static const struct device_type typec_retimer_dev_type = {
> +	.name = "retimer_switch",
> +	.release = typec_retimer_release,
> +};
> +
> +/**
> + * typec_retimer_register - Register a retimer device.
> + * @parent: Parent device.
> + * @desc: Retimer description.
> + *
> + * Some USB Type-C connectors have their physical lines routed through retimers before they
> + * reach muxes or host controllers. In some cases (for example: using alternate modes)
> + * these retimers need to be reconfigured appropriately. This function registers retimer
> + * switches which route and potentially modify the signals on the Type C physical lines
> + * enroute to the host controllers.
> + */
> +struct typec_retimer *
> +typec_retimer_register(struct device *parent, const struct typec_retimer_desc *desc)
> +{
> +	struct typec_retimer *retimer;
> +	int ret;
> +
> +	if (!desc || !desc->set)
> +		return ERR_PTR(-EINVAL);
> +
> +	retimer = kzalloc(sizeof(*retimer), GFP_KERNEL);
> +	if (!retimer)
> +		return ERR_PTR(-ENOMEM);
> +
> +	retimer->set = desc->set;
> +
> +	device_initialize(&retimer->dev);
> +	retimer->dev.parent = parent;
> +	retimer->dev.fwnode = desc->fwnode;
> +	retimer->dev.class = &typec_retimer_class;
> +	retimer->dev.type = &typec_retimer_dev_type;
> +	retimer->dev.driver_data = desc->drvdata;
> +	dev_set_name(&retimer->dev, "%s-retimer",
> +		     desc->name ? desc->name : dev_name(parent));
> +
> +	ret = device_add(&retimer->dev);
> +	if (ret) {
> +		dev_err(parent, "failed to register retimer (%d)\n", ret);
> +		put_device(&retimer->dev);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return retimer;
> +}
> +EXPORT_SYMBOL_GPL(typec_retimer_register);
> +
> +/**
> + * typec_retimer_unregister - Unregister retimer device.
> + * @retimer: USB Type-C Connector retimer.
> + *
> + * Unregister retimer that was registered with typec_retimer_register().
> + */
> +void typec_retimer_unregister(struct typec_retimer *retimer)
> +{
> +	if (!IS_ERR_OR_NULL(retimer))
> +		device_unregister(&retimer->dev);
> +}
> +EXPORT_SYMBOL_GPL(typec_retimer_unregister);
> +
> +void *typec_retimer_get_drvdata(struct typec_retimer *retimer)
> +{
> +	return dev_get_drvdata(&retimer->dev);
> +}
> +EXPORT_SYMBOL_GPL(typec_retimer_get_drvdata);
> +
> +struct class typec_retimer_class = {
> +	.name = "typec_retimer",
> +	.owner = THIS_MODULE,
> +};
> diff --git a/drivers/usb/typec/retimer.h b/drivers/usb/typec/retimer.h
> new file mode 100644
> index 000000000000..fa15951d4846
> --- /dev/null
> +++ b/drivers/usb/typec/retimer.h
> @@ -0,0 +1,15 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef __USB_TYPEC_RETIMER__
> +#define __USB_TYPEC_RETIMER__
> +
> +#include <linux/usb/typec_retimer.h>
> +
> +struct typec_retimer {
> +	struct device dev;
> +	typec_retimer_set_fn_t set;
> +};
> +
> +#define to_typec_retimer(_dev_) container_of(_dev_, struct typec_retimer, dev)
> +
> +#endif /* __USB_TYPEC_RETIMER__ */
> diff --git a/include/linux/usb/typec_retimer.h b/include/linux/usb/typec_retimer.h
> new file mode 100644
> index 000000000000..5e036b3360e2
> --- /dev/null
> +++ b/include/linux/usb/typec_retimer.h
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef __USB_TYPEC_RETIMER
> +#define __USB_TYPEC_RETIMER
> +
> +#include <linux/property.h>
> +#include <linux/usb/typec.h>
> +
> +struct device;
> +struct typec_retimer;
> +struct typec_altmode;
> +struct fwnode_handle;
> +
> +struct typec_retimer_state {
> +	struct typec_altmode *alt;
> +	unsigned long mode;
> +	void *data;
> +};
> +
> +typedef int (*typec_retimer_set_fn_t)(struct typec_retimer *retimer,
> +				      struct typec_retimer_state *state);
> +
> +struct typec_retimer_desc {
> +	struct fwnode_handle *fwnode;
> +	typec_retimer_set_fn_t set;
> +	const char *name;
> +	void *drvdata;
> +};
> +
> +struct typec_retimer *fwnode_typec_retimer_get(struct fwnode_handle *fwnode);
> +void typec_retimer_put(struct typec_retimer *retimer);
> +int typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state);
> +
> +static inline struct typec_retimer *typec_retimer_get(struct device *dev)
> +{
> +	return fwnode_typec_retimer_get(dev_fwnode(dev));
> +}
> +
> +struct typec_retimer *
> +typec_retimer_register(struct device *parent, const struct typec_retimer_desc *desc);
> +void typec_retimer_unregister(struct typec_retimer *retimer);
> +
> +void *typec_retimer_get_drvdata(struct typec_retimer *retimer);
> +
> +#endif /* __USB_TYPEC_RETIMER */
> -- 
> 2.37.0.rc0.161.g10f37bed90-goog

-- 
heikki

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/9] usb: typec: Add retimer handle to port
  2022-06-29 23:32 ` [PATCH 2/9] usb: typec: Add retimer handle to port Prashant Malani
@ 2022-06-30  8:27   ` Heikki Krogerus
  2022-06-30 17:16     ` Prashant Malani
  0 siblings, 1 reply; 15+ messages in thread
From: Heikki Krogerus @ 2022-06-30  8:27 UTC (permalink / raw)
  To: Prashant Malani
  Cc: linux-kernel, linux-usb, chrome-platform, bleung, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel

Hi,

On Wed, Jun 29, 2022 at 11:32:20PM +0000, Prashant Malani wrote:
> Similar to mux and orientation switch, add a handle for registered
> retimer to the port, so that it has handles to the various switches
> connected to it.
> 
> Signed-off-by: Prashant Malani <pmalani@chromium.org>
> ---
>  drivers/usb/typec/class.c | 8 ++++++++
>  drivers/usb/typec/class.h | 1 +
>  2 files changed, 9 insertions(+)
> 
> diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
> index 2fa0b3718d23..2bc5fbdb25dd 100644
> --- a/drivers/usb/typec/class.c
> +++ b/drivers/usb/typec/class.c
> @@ -12,6 +12,7 @@
>  #include <linux/slab.h>
>  #include <linux/usb/pd_vdo.h>
>  #include <linux/usb/typec_mux.h>
> +#include <linux/usb/typec_retimer.h>
>  
>  #include "bus.h"
>  #include "class.h"
> @@ -2249,6 +2250,13 @@ struct typec_port *typec_register_port(struct device *parent,
>  		return ERR_PTR(ret);
>  	}
>  
> +	port->retimer = typec_retimer_get(&port->dev);
> +	if (IS_ERR(port->retimer)) {
> +		ret = PTR_ERR(port->retimer);
> +		put_device(&port->dev);
> +		return ERR_PTR(ret);
> +	}
> +
>  	ret = device_add(&port->dev);
>  	if (ret) {
>  		dev_err(parent, "failed to register port (%d)\n", ret);

I think you need to release the reference with typec_retimer_put() in
typec_release().

I guess we can look handle this later, but there can actually be two
onboard retimers for each connector.

thanks,

> diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h
> index 1bb1da124109..97520406929e 100644
> --- a/drivers/usb/typec/class.h
> +++ b/drivers/usb/typec/class.h
> @@ -55,6 +55,7 @@ struct typec_port {
>  	enum typec_orientation		orientation;
>  	struct typec_switch		*sw;
>  	struct typec_mux		*mux;
> +	struct typec_retimer		*retimer;
>  
>  	const struct typec_capability	*cap;
>  	const struct typec_operations   *ops;

-- 
heikki

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/9] usb: typec: Add support for retimers
  2022-06-30  8:17   ` Heikki Krogerus
@ 2022-06-30 10:18     ` Mika Westerberg
  2022-06-30 17:13     ` Prashant Malani
  1 sibling, 0 replies; 15+ messages in thread
From: Mika Westerberg @ 2022-06-30 10:18 UTC (permalink / raw)
  To: Heikki Krogerus
  Cc: Prashant Malani, linux-kernel, linux-usb, chrome-platform,
	bleung, Daisuke Nojiri, Dustin L. Howett, Greg Kroah-Hartman,
	Guenter Roeck, Gustavo A. R. Silva, Kees Cook, Sebastian Reichel

On Thu, Jun 30, 2022 at 11:17:59AM +0300, Heikki Krogerus wrote:
> On Wed, Jun 29, 2022 at 11:32:19PM +0000, Prashant Malani wrote:
> > Introduce a retimer device class and associated functions that register
> > and use retimer "switch" devices. These operate in a manner similar to
> > the "mode-switch" and help configure retimers that exist between the
> > Type-C connector and host controller(s).
> > 
> > Type C ports can be linked to retimers using firmware node device
> > references (again, in a manner similar to "mode-switch").
> > 
> > Signed-off-by: Prashant Malani <pmalani@chromium.org>
> 
> Cool! This looks really good to me.
> 
> I'll add Mika here, just to keep him in the loop. Thunderbolt/USB4 can
> control the same physical retimers over the SBU line. Right now there
> is no conflict, but I think we want to later be able to use these
> devices to upgrade the retimer firmware, and that is something that
> the Thunderbolt/USB4 already does. So let's keep an eye on this.
> 
> I wonder, would it make sense to later make the thunderbolt_retimer
> devices also part of the device class that's introduced here? I think
> that way it would be easier to later figure out which
> thunderbolt_retimer and which retimer_switch represent the same
> physical retimer. And perhaps it would also be more clear for the user
> space to have a single device class for the retimers?

I agree this makes sense.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/9] usb: typec: Add support for retimers
  2022-06-30  8:17   ` Heikki Krogerus
  2022-06-30 10:18     ` Mika Westerberg
@ 2022-06-30 17:13     ` Prashant Malani
  1 sibling, 0 replies; 15+ messages in thread
From: Prashant Malani @ 2022-06-30 17:13 UTC (permalink / raw)
  To: Heikki Krogerus
  Cc: linux-kernel, linux-usb, chrome-platform, bleung, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel,
	Mika Westerberg

Hi Heikki,

Thanks for taking a look.

On Thu, Jun 30, 2022 at 1:18 AM Heikki Krogerus
<heikki.krogerus@linux.intel.com> wrote:
>
> On Wed, Jun 29, 2022 at 11:32:19PM +0000, Prashant Malani wrote:
> > Introduce a retimer device class and associated functions that register
> > and use retimer "switch" devices. These operate in a manner similar to
> > the "mode-switch" and help configure retimers that exist between the
> > Type-C connector and host controller(s).
> >
> > Type C ports can be linked to retimers using firmware node device
> > references (again, in a manner similar to "mode-switch").
> >
> > Signed-off-by: Prashant Malani <pmalani@chromium.org>
>
> Cool! This looks really good to me.
>
> I'll add Mika here, just to keep him in the loop. Thunderbolt/USB4 can
> control the same physical retimers over the SBU line. Right now there
> is no conflict, but I think we want to later be able to use these
> devices to upgrade the retimer firmware, and that is something that
> the Thunderbolt/USB4 already does. So let's keep an eye on this.
>
> I wonder, would it make sense to later make the thunderbolt_retimer
> devices also part of the device class that's introduced here? I think
> that way it would be easier to later figure out which
> thunderbolt_retimer and which retimer_switch represent the same
> physical retimer. And perhaps it would also be more clear for the user
> space to have a single device class for the retimers?
>
> Maybe the device class could be named just "retimer", and the device
> type could then be named "typec_retimer" instead of "retimer_switch"?

Sure, I will make this modification in v2.
I assume we can still keep the firmware node handle as "retimer-switch"
to keep it aligned with "mode-switch" and "orientation-switch".

Thanks,

-Prashant

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/9] usb: typec: Add retimer handle to port
  2022-06-30  8:27   ` Heikki Krogerus
@ 2022-06-30 17:16     ` Prashant Malani
  0 siblings, 0 replies; 15+ messages in thread
From: Prashant Malani @ 2022-06-30 17:16 UTC (permalink / raw)
  To: Heikki Krogerus
  Cc: linux-kernel, linux-usb, chrome-platform, bleung, Daisuke Nojiri,
	Dustin L. Howett, Greg Kroah-Hartman, Guenter Roeck,
	Gustavo A. R. Silva, Kees Cook, Sebastian Reichel

HI Heikki,

On Thu, Jun 30, 2022 at 1:27 AM Heikki Krogerus
<heikki.krogerus@linux.intel.com> wrote:
>
> Hi,
>
> On Wed, Jun 29, 2022 at 11:32:20PM +0000, Prashant Malani wrote:
> > Similar to mux and orientation switch, add a handle for registered
> > retimer to the port, so that it has handles to the various switches
> > connected to it.
> >
> > Signed-off-by: Prashant Malani <pmalani@chromium.org>
> > ---
> >  drivers/usb/typec/class.c | 8 ++++++++
> >  drivers/usb/typec/class.h | 1 +
> >  2 files changed, 9 insertions(+)
> >
> > diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
> > index 2fa0b3718d23..2bc5fbdb25dd 100644
> > --- a/drivers/usb/typec/class.c
> > +++ b/drivers/usb/typec/class.c
> > @@ -12,6 +12,7 @@
> >  #include <linux/slab.h>
> >  #include <linux/usb/pd_vdo.h>
> >  #include <linux/usb/typec_mux.h>
> > +#include <linux/usb/typec_retimer.h>
> >
> >  #include "bus.h"
> >  #include "class.h"
> > @@ -2249,6 +2250,13 @@ struct typec_port *typec_register_port(struct device *parent,
> >               return ERR_PTR(ret);
> >       }
> >
> > +     port->retimer = typec_retimer_get(&port->dev);
> > +     if (IS_ERR(port->retimer)) {
> > +             ret = PTR_ERR(port->retimer);
> > +             put_device(&port->dev);
> > +             return ERR_PTR(ret);
> > +     }
> > +
> >       ret = device_add(&port->dev);
> >       if (ret) {
> >               dev_err(parent, "failed to register port (%d)\n", ret);
>
> I think you need to release the reference with typec_retimer_put() in
> typec_release().

I knew I was forgetting something...
I'll fix this in v2.

>
> I guess we can look handle this later, but there can actually be two
> onboard retimers for each connector.

You're referring to the cascaded case right? OK, I'll bear this in mind for
later series (right now the EC exposes just 1 interface for retimer).

Thanks,

-Prashant

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2022-06-30 17:16 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-29 23:32 [PATCH 0/9] platform/chrome: Type-C switch driver and Type-C framework updates Prashant Malani
2022-06-29 23:32 ` [PATCH 1/9] usb: typec: Add support for retimers Prashant Malani
2022-06-30  8:17   ` Heikki Krogerus
2022-06-30 10:18     ` Mika Westerberg
2022-06-30 17:13     ` Prashant Malani
2022-06-29 23:32 ` [PATCH 2/9] usb: typec: Add retimer handle to port Prashant Malani
2022-06-30  8:27   ` Heikki Krogerus
2022-06-30 17:16     ` Prashant Malani
2022-06-29 23:32 ` [PATCH 3/9] platform/chrome: Add Type-C mux set command definitions Prashant Malani
2022-06-29 23:32 ` [PATCH 4/9] platform/chrome: cros_typec_switch: Add switch driver Prashant Malani
2022-06-29 23:32 ` [PATCH 5/9] platform/chrome: cros_typec_switch: Set EC retimer Prashant Malani
2022-06-29 23:32 ` [PATCH 6/9] platform/chrome: cros_typec_switch: Add event check Prashant Malani
2022-06-29 23:32 ` [PATCH 7/9] platform/chrome: cros_typec_switch: Register mode switches Prashant Malani
2022-06-29 23:32 ` [PATCH 8/9] platform/chrome: cros_ec_typec: Cleanup switch handle return paths Prashant Malani
2022-06-29 23:32 ` [PATCH 9/9] platform/chrome: cros_ec_typec: Get retimer handle Prashant Malani

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.