summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Michalec <tm@semihalf.com>2022-04-07 20:21:00 +0200
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-05-06 15:47:22 +0000
commit086009f55adcee29e4d3d8d8d0379d13a99ce946 (patch)
treebd3f7b923a71e4f1282c6617f95f1888b244f0c9
parent52b10fc3261a28a5debae0f0e772bb67b3aee3b1 (diff)
downloadchrome-ec-086009f55adcee29e4d3d8d8d0379d13a99ce946.tar.gz
zephyr: move USB mux configuration into the device tree
Create a separated usb_muxes.c file in the shim layer to define the usb_muxes array. Additional USB muxes in a chain are created in the same file. Common properties of the usb_mux DTS node are in cros-ec,usb-mux.yaml file. BUG=b:227757117 TEST=zmake testall BRANCH=none Signed-off-by: Tomasz Michalec <tm@semihalf.com> Change-Id: I6cb26404b5cb44c6fce29f4176ebb6707af71d21 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3575157 Commit-Queue: Tomasz Michalec <tmichalec@google.com> Reviewed-by: Keith Short <keithshort@chromium.org> Reviewed-by: Denis Brockus <dbrockus@chromium.org> Tested-by: Tomasz Michalec <tmichalec@google.com>
-rw-r--r--include/usb_mux.h12
-rw-r--r--zephyr/dts/bindings/usbc/mux/cros-ec,usbc-mux-virtual.yaml9
-rw-r--r--zephyr/dts/bindings/usbc/mux/cros-ec,usbc-mux.yaml25
-rw-r--r--zephyr/dts/bindings/usbc/mux/ite,it5205.yaml23
-rw-r--r--zephyr/dts/bindings/usbc/mux/ti,tusb1064.yaml39
-rw-r--r--zephyr/dts/bindings/usbc/named-usbc-port.yaml10
-rw-r--r--zephyr/include/dt-bindings/usbc_mux.h18
-rw-r--r--zephyr/shim/include/usbc/it5205_usb_mux.h22
-rw-r--r--zephyr/shim/include/usbc/tusb1064_usb_mux.h34
-rw-r--r--zephyr/shim/include/usbc/usb_muxes.h289
-rw-r--r--zephyr/shim/include/usbc/virtual_usb_mux.h20
-rw-r--r--zephyr/shim/src/CMakeLists.txt1
-rw-r--r--zephyr/shim/src/usb_muxes.c61
13 files changed, 563 insertions, 0 deletions
diff --git a/include/usb_mux.h b/include/usb_mux.h
index e251d74f4c..13573f8b82 100644
--- a/include/usb_mux.h
+++ b/include/usb_mux.h
@@ -14,11 +14,23 @@
#include "usb_charge.h"
#include "usb_pd.h"
+/*
+ * If compiling with Zephyr, include the USB_MUX_FLAG_ definitions that are
+ * shared with device tree
+ */
+#ifdef CONFIG_ZEPHYR
+
+#include "dt-bindings/usbc_mux.h"
+
+#else /* !CONFIG_ZEPHYR */
+
/* Flags used for usb_mux.flags */
#define USB_MUX_FLAG_NOT_TCPC BIT(0) /* TCPC/MUX device used only as MUX */
#define USB_MUX_FLAG_SET_WITHOUT_FLIP BIT(1) /* SET should not flip */
#define USB_MUX_FLAG_RESETS_IN_G3 BIT(2) /* Mux chip will reset in G3 */
+#endif /* CONFIG_ZEPHYR */
+
/*
* USB-C mux state
*
diff --git a/zephyr/dts/bindings/usbc/mux/cros-ec,usbc-mux-virtual.yaml b/zephyr/dts/bindings/usbc/mux/cros-ec,usbc-mux-virtual.yaml
new file mode 100644
index 0000000000..cadeb6d35b
--- /dev/null
+++ b/zephyr/dts/bindings/usbc/mux/cros-ec,usbc-mux-virtual.yaml
@@ -0,0 +1,9 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: USB-C Virtual USB MUX
+
+include: cros-ec,usbc-mux.yaml
+
+compatible: "cros-ec,usbc-mux-virtual"
diff --git a/zephyr/dts/bindings/usbc/mux/cros-ec,usbc-mux.yaml b/zephyr/dts/bindings/usbc/mux/cros-ec,usbc-mux.yaml
new file mode 100644
index 0000000000..21cb8e0a3f
--- /dev/null
+++ b/zephyr/dts/bindings/usbc/mux/cros-ec,usbc-mux.yaml
@@ -0,0 +1,25 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: Common properties for USB-C mux
+
+properties:
+ flags:
+ type: int
+ required: false
+ default: 0
+ description: |
+ Mask of flags defined in dt-bindings/usbc_mux.h
+
+ board-init:
+ type: string
+ required: false
+ description: |
+ Name of function used as board_init callback
+
+ board-set:
+ type: string
+ required: false
+ description: |
+ Name of function used as board_set callback
diff --git a/zephyr/dts/bindings/usbc/mux/ite,it5205.yaml b/zephyr/dts/bindings/usbc/mux/ite,it5205.yaml
new file mode 100644
index 0000000000..4d4c360d47
--- /dev/null
+++ b/zephyr/dts/bindings/usbc/mux/ite,it5205.yaml
@@ -0,0 +1,23 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: ITE IT5205 USB Type-C 3:2 alternate mode MUX
+
+include: cros-ec,usbc-mux.yaml
+
+compatible: "ite,it5205"
+
+properties:
+ port:
+ type: phandle
+ required: true
+ description: phandle to the named i2c port
+
+ i2c-addr-flags:
+ type: string
+ required: true
+ description: I2C address of chip
+ enum:
+ - IT5205_I2C_ADDR1_FLAGS
+ - IT5205_I2C_ADDR2_FLAGS
diff --git a/zephyr/dts/bindings/usbc/mux/ti,tusb1064.yaml b/zephyr/dts/bindings/usbc/mux/ti,tusb1064.yaml
new file mode 100644
index 0000000000..ff28ef9eb2
--- /dev/null
+++ b/zephyr/dts/bindings/usbc/mux/ti,tusb1064.yaml
@@ -0,0 +1,39 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: |
+ TI TUSB1064 and TUSB1044 USB-C MUX, device variant depends on
+ CONFIG_USB_MUX_TUSB1044
+
+include: cros-ec,usbc-mux.yaml
+
+compatible: "ti,tusb1064"
+
+properties:
+ port:
+ type: phandle
+ required: true
+ description: phandle to the named i2c port
+
+ i2c-addr-flags:
+ type: string
+ required: true
+ description: I2C address of chip
+ enum:
+ - TUSB1064_I2C_ADDR0_FLAGS
+ - TUSB1064_I2C_ADDR1_FLAGS
+ - TUSB1064_I2C_ADDR2_FLAGS
+ - TUSB1064_I2C_ADDR3_FLAGS
+ - TUSB1064_I2C_ADDR4_FLAGS
+ - TUSB1064_I2C_ADDR5_FLAGS
+ - TUSB1064_I2C_ADDR6_FLAGS
+ - TUSB1064_I2C_ADDR7_FLAGS
+ - TUSB1064_I2C_ADDR8_FLAGS
+ - TUSB1064_I2C_ADDR9_FLAGS
+ - TUSB1064_I2C_ADDR10_FLAGS
+ - TUSB1064_I2C_ADDR11_FLAGS
+ - TUSB1064_I2C_ADDR12_FLAGS
+ - TUSB1064_I2C_ADDR13_FLAGS
+ - TUSB1064_I2C_ADDR14_FLAGS
+ - TUSB1064_I2C_ADDR15_FLAGS
diff --git a/zephyr/dts/bindings/usbc/named-usbc-port.yaml b/zephyr/dts/bindings/usbc/named-usbc-port.yaml
index 77ee50ea60..bcd9c7a2b4 100644
--- a/zephyr/dts/bindings/usbc/named-usbc-port.yaml
+++ b/zephyr/dts/bindings/usbc/named-usbc-port.yaml
@@ -8,6 +8,16 @@ compatible: "named-usbc-port"
include: base.yaml
+properties:
+ usb-muxes:
+ type: phandles
+ required: false
+ description: |
+ List of USB-C muxes and retimers for the USB-C port. The USB-C subsystem
+ traverses this list in the order specified. The phandles are references to
+ cros-ec,usbc-mux nodes.
+
+
# Example:
# usbc {
# #address-cells = <1>;
diff --git a/zephyr/include/dt-bindings/usbc_mux.h b/zephyr/include/dt-bindings/usbc_mux.h
new file mode 100644
index 0000000000..8cfe38340f
--- /dev/null
+++ b/zephyr/include/dt-bindings/usbc_mux.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef DT_BINDINGS_USBC_MUX_H_
+#define DT_BINDINGS_USBC_MUX_H_
+
+#ifndef BIT
+#define BIT(n) (1U << n)
+#endif
+
+/* Flags used for cros-ec,usbc-mux flags property / struct usb_mux.flags */
+#define USB_MUX_FLAG_NOT_TCPC BIT(0) /* TCPC/MUX device used only as MUX */
+#define USB_MUX_FLAG_SET_WITHOUT_FLIP BIT(1) /* SET should not flip */
+#define USB_MUX_FLAG_RESETS_IN_G3 BIT(2) /* Mux chip will reset in G3 */
+
+#endif /* DT_BINDINGS_USBC_MUX_H_ */
diff --git a/zephyr/shim/include/usbc/it5205_usb_mux.h b/zephyr/shim/include/usbc/it5205_usb_mux.h
new file mode 100644
index 0000000000..58412e0bd3
--- /dev/null
+++ b/zephyr/shim/include/usbc/it5205_usb_mux.h
@@ -0,0 +1,22 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __ZEPHYR_SHIM_IT5205_USB_MUX_H
+#define __ZEPHYR_SHIM_IT5205_USB_MUX_H
+
+#include "usb_mux/it5205_public.h"
+
+#define IT5205_USB_MUX_COMPAT ite_it5205
+
+#define USB_MUX_CONFIG_IT5205(mux_id, port_id, idx) \
+ { \
+ USB_MUX_COMMON_FIELDS(mux_id, port_id, idx), \
+ .driver = &it5205_usb_mux_driver, \
+ .i2c_port = I2C_PORT(DT_PHANDLE(mux_id, port)), \
+ .i2c_addr_flags = \
+ DT_STRING_UPPER_TOKEN(mux_id, i2c_addr_flags), \
+ }
+
+#endif /* __ZEPHYR_SHIM_IT5205_USB_MUX_H */
diff --git a/zephyr/shim/include/usbc/tusb1064_usb_mux.h b/zephyr/shim/include/usbc/tusb1064_usb_mux.h
new file mode 100644
index 0000000000..dcab760b7b
--- /dev/null
+++ b/zephyr/shim/include/usbc/tusb1064_usb_mux.h
@@ -0,0 +1,34 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __ZEPHYR_SHIM_TUSB1064_USB_MUX_H
+#define __ZEPHYR_SHIM_TUSB1064_USB_MUX_H
+
+#include "driver/usb_mux/tusb1064.h"
+
+#define TUSB1064_USB_MUX_COMPAT ti_tusb1064
+
+#if defined(CONFIG_USB_MUX_TUSB1044)
+#define USB_MUX_CONFIG_TUSB1064(mux_id, port_id, idx) \
+ { \
+ USB_MUX_COMMON_FIELDS(mux_id, port_id, idx), \
+ .driver = &tusb1064_usb_mux_driver, \
+ .i2c_port = I2C_PORT(DT_PHANDLE(mux_id, port)), \
+ .i2c_addr_flags = \
+ DT_STRING_UPPER_TOKEN(mux_id, i2c_addr_flags), \
+ .hpd_update = &tusb1044_hpd_update, \
+ }
+#else
+#define USB_MUX_CONFIG_TUSB1064(mux_id, port_id, idx) \
+ { \
+ USB_MUX_COMMON_FIELDS(mux_id, port_id, idx), \
+ .driver = &tusb1064_usb_mux_driver, \
+ .i2c_port = I2C_PORT(DT_PHANDLE(mux_id, port)), \
+ .i2c_addr_flags = \
+ DT_STRING_UPPER_TOKEN(mux_id, i2c_addr_flags), \
+ }
+#endif /* defined(CONFIG_USB_MUX_TUSB1044) */
+
+#endif /* __ZEPHYR_SHIM_TUBS1064_USB_MUX_H */
diff --git a/zephyr/shim/include/usbc/usb_muxes.h b/zephyr/shim/include/usbc/usb_muxes.h
new file mode 100644
index 0000000000..09ad3824a0
--- /dev/null
+++ b/zephyr/shim/include/usbc/usb_muxes.h
@@ -0,0 +1,289 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef ZEPHYR_CHROME_USBC_USB_MUXES_H
+#define ZEPHYR_CHROME_USBC_USB_MUXES_H
+
+#include <devicetree.h>
+#include <sys/util_macro.h>
+#include "usb_mux.h"
+#include "usbc/it5205_usb_mux.h"
+#include "usbc/tusb1064_usb_mux.h"
+#include "usbc/virtual_usb_mux.h"
+
+/**
+ * @brief List of USB mux drivers compatibles and their configurations. Each
+ * element of list has to have (compatible, config) format.
+ */
+#define USB_MUX_DRIVERS \
+ (IT5205_USB_MUX_COMPAT, USB_MUX_CONFIG_IT5205), \
+ (TUSB1064_USB_MUX_COMPAT, USB_MUX_CONFIG_TUSB1064), \
+ (VIRTUAL_USB_MUX_COMPAT, USB_MUX_CONFIG_VIRTUAL)
+
+/**
+ * @brief Get compatible from @p driver
+ *
+ * @param driver USB mux driver description in format (compatible, config)
+ */
+#define USB_MUX_DRIVER_GET_COMPAT(driver) GET_ARG_N(1, __DEBRACKET driver)
+
+/**
+ * @brief Get configuration from @p driver
+ *
+ * @param driver USB mux driver description in format (compatible, config)
+ */
+#define USB_MUX_DRIVER_GET_CONFIG(driver) GET_ARG_N(2, __DEBRACKET driver)
+
+/**
+ * @brief USB mux port number based on parent node in DTS
+ *
+ * @param port_id USBC node ID
+ */
+#define USB_MUX_PORT(port_id) DT_REG_ADDR(port_id)
+
+/**
+ * @brief Name of USB mux structure if node is not EMPTY. Note, that root of
+ * chain is not referred by this name, but usb_muxes[USB_MUX_PORT(id)].
+ *
+ * @param mux_id USB mux node ID
+ */
+#define USB_MUX_STRUCT_NAME(mux_id) \
+ COND_CODE_0(IS_EMPTY(mux_id), (DT_CAT(USB_MUX_NODE_, mux_id)), (EMPTY))
+
+/**
+ * @brief USB muxes in chain should be constant only if configuration
+ * cannot change in runtime
+ */
+#define MAYBE_CONST COND_CODE_1(CONFIG_PLATFORM_EC_USB_MUX_RUNTIME_CONFIG, \
+ (), (const))
+
+/**
+ * @brief Declaration of USB mux structure
+ *
+ * @param mux_id USB mux node ID
+ */
+#define USB_MUX_STRUCT_DECLARE(mux_id) \
+ MAYBE_CONST struct usb_mux USB_MUX_STRUCT_NAME(mux_id)
+
+/**
+ * @brief Get pointer by referencing @p name or NULL if @p name is EMPTY
+ *
+ * @param name Identifier to reference
+ */
+#define USB_MUX_POINTER_OR_NULL(name) \
+ COND_CODE_0(IS_EMPTY(name), (&name), (NULL))
+
+/**
+ * @brief Get node id of @p idx USB mux in chain
+ *
+ * @param idx Position of USB mux in chain
+ * @param port_id USBC node ID
+ */
+#define USB_MUX_GET_CHAIN_N(idx, port_id) \
+ DT_PHANDLE_BY_IDX(port_id, usb_muxes, idx)
+
+/**
+ * @brief Get node id of next USB mux in chain or EMPTY if it is last mux
+ *
+ * @param port_id USBC node ID
+ * @param idx Position of USB mux in chain
+ */
+#define USB_MUX_NEXT(port_id, idx) \
+ GET_ARG_N(2, GET_ARGS_LESS_N(idx, \
+ LISTIFY(DT_PROP_LEN(port_id, usb_muxes), \
+ USB_MUX_GET_CHAIN_N, (,), port_id)), \
+ EMPTY)
+
+/**
+ * @brief Get pointer to next USB mux in chain or NULL if it is last mux
+ *
+ * @param port_id USBC node ID
+ * @param idx Position of USB mux in chain
+ */
+#define USB_MUX_NEXT_POINTER(port_id, idx) \
+ USB_MUX_POINTER_OR_NULL(USB_MUX_STRUCT_NAME(USB_MUX_NEXT(port_id, idx)))
+
+/**
+ * @brief Generate pointer to function from @p cb_name property or NULL
+ * if property doesn't exist
+ *
+ * @param mux_id USB mux node ID
+ * @param cb_name Name of property with callback function
+ */
+#define USB_MUX_CALLBACK_OR_NULL(mux_id, cb_name) \
+ USB_MUX_POINTER_OR_NULL(DT_STRING_TOKEN_OR(mux_id, cb_name, EMPTY))
+
+/**
+ * @brief Set struct usb_mux fields common for all USB muxes
+ *
+ * @param mux_id USB mux node ID
+ * @param port_id USBC node ID
+ * @param idx Position of USB mux in chain
+ */
+#define USB_MUX_COMMON_FIELDS(mux_id, port_id, idx) \
+ .usb_port = USB_MUX_PORT(port_id), \
+ .next_mux = USB_MUX_NEXT_POINTER(port_id, idx), \
+ .board_init = USB_MUX_CALLBACK_OR_NULL(mux_id, board_init), \
+ .board_set = USB_MUX_CALLBACK_OR_NULL(mux_id, board_set), \
+ .flags = DT_PROP(mux_id, flags)
+
+/**
+ * @brief Expands to 1 if @p mux_id has @p compat compatible. It is required
+ * to makes sure that @p compat is expanded before DT_NODE_HAS_COMPAT
+ *
+ * @param mux_id USB mux node ID
+ * @param compat USB mux driver compatible
+ */
+#define USB_MUX_IS_COMPATIBLE(mux_id, compat) \
+ DT_NODE_HAS_COMPAT(mux_id, compat)
+
+/**
+ * @brief Expands to @p driver config if @p mux_id is compatible with @p driver
+ *
+ * @param driver USB mux driver description in format (compatible, config)
+ * @param mux_id USB mux node ID
+ */
+#define USB_MUX_DRIVER_CONFIG_IF_COMPAT(driver, mux_id) \
+ COND_CODE_1(USB_MUX_IS_COMPATIBLE( \
+ mux_id, USB_MUX_DRIVER_GET_COMPAT(driver)), \
+ (USB_MUX_DRIVER_GET_CONFIG(driver)), ())
+
+/**
+ * @brief Find driver from USB_MUX_DRIVERS that is compatible with @p mux_id
+ *
+ * @param mux_id USB mux node ID
+ */
+#define USB_MUX_FIND_DRIVER_CONFIG(mux_id) \
+ FOR_EACH_FIXED_ARG(USB_MUX_DRIVER_CONFIG_IF_COMPAT, (), mux_id, \
+ USB_MUX_DRIVERS)
+
+/**
+ * @brief Get driver configuration macro for @p mux_id and call @p op
+ *
+ * @param mux_id USB mux node ID
+ * @param port_id USBC node ID
+ * @param idx Position of USB mux in chain
+ * @param op Operation to perform on USB muxes
+ */
+#define USB_MUX_CALL_OP(mux_id, port_id, idx, op) \
+ op(mux_id, port_id, idx, USB_MUX_FIND_DRIVER_CONFIG(mux_id))
+
+/**
+ * @brief Get USB mux node ID and call USB_MUX_CALL_OP
+ *
+ * @param port_id USBC node ID
+ * @param idx Position of USB mux in chain
+ * @param op Operation to perform on USB muxes
+ */
+#define USB_MUX_DO(port_id, idx, op) \
+ USB_MUX_CALL_OP(DT_PHANDLE_BY_IDX(port_id, usb_muxes, idx), \
+ port_id, idx, op)
+
+/**
+ * @brief Declare USB mux structure
+ *
+ * @param mux_id USB mux node ID
+ * @param port_id USBC node ID
+ * @param idx Position of USB mux in chain
+ * @param conf Driver configuration function
+ */
+#define USB_MUX_DECLARE(mux_id, port_id, idx, conf) \
+ extern USB_MUX_STRUCT_DECLARE(mux_id);
+
+/**
+ * @brief Define USB mux structure using driver USB_MUX_CONFIG_* macro
+ *
+ * @param mux_id USB mux node ID
+ * @param port_id USBC node ID
+ * @param idx Position of USB mux in chain
+ * @param conf Driver configuration function
+ */
+#define USB_MUX_DEFINE(mux_id, port_id, idx, conf) \
+ USB_MUX_STRUCT_DECLARE(mux_id) = conf(mux_id, port_id, idx);
+
+/**
+ * @brief Define entry of usb_muxes array using driver USB_MUX_CONFIG_* macro
+ *
+ * @param mux_id USB mux node ID
+ * @param port_id USBC node ID
+ * @param idx Position of USB mux in chain
+ * @param conf Driver configuration function
+ */
+#define USB_MUX_ARRAY(mux_id, port_id, idx, conf) \
+ [USB_MUX_PORT(port_id)] = conf(mux_id, port_id, idx),
+
+/**
+ * @brief Call @p op with first mux in chain
+ *
+ * @param port_id USBC node ID
+ * @param op Operation to perform on USB mux first in chain. Needs to accept
+ * USB mux node ID, USBC port node ID, position in chain, and driver
+ * config as arguments.
+ */
+#define USB_MUX_FIRST(port_id, op) \
+ USB_MUX_DO(port_id, 0, op)
+
+/**
+ * @brief Call USB_MUX_DO if @p idx is not 0 (is not first mux in chain)
+ *
+ * @param port_id USBC node ID
+ * @param unused2 This argument is expected by DT_FOREACH_PROP_ELEM_VARGS
+ * @param idx Position of USB mux in chain
+ * @param op Operation to perform on USB muxes
+ */
+#define USB_MUX_DO_SKIP_FIRST(port_id, unused2, idx, op) \
+ COND_CODE_1(UTIL_BOOL(idx), (USB_MUX_DO(port_id, idx, op)), ())
+
+/**
+ * @brief Call @p op with every mux in chain expect the first one
+ *
+ * @param port_id USBC node ID
+ * @param op Operation to perform on USB muxes. Needs to accept USB mux node
+ * ID, USBC port node ID, position in chain, and driver config as
+ * arguments.
+ */
+#define USB_MUX_NO_FIRST(port_id, op) \
+ DT_FOREACH_PROP_ELEM_VARGS(port_id, usb_muxes, \
+ USB_MUX_DO_SKIP_FIRST, op)
+
+/**
+ * @brief If @p port_id has usb_muxes property, call @p op with every mux in
+ * chain that passes @p filter
+ *
+ * @param port_id USBC node ID
+ * @param filter Macro that should filter USB muxes and call @p op on them.
+ * It has @p port_id and @p op as arguments. It is called
+ * only for @p port_id that has usb_muxes property.
+ * @param op Operation to perform on USB muxes. Needs to accept USB mux node
+ * ID, USBC port node ID, position in chain, and driver config as
+ * arguments.
+ */
+#define USB_MUX_USBC_PORT_HAS_MUXES(port_id, filter, op) \
+ COND_CODE_1(DT_NODE_HAS_PROP(port_id, usb_muxes), \
+ (filter(port_id, op)), ())
+
+/**
+ * @brief For every USBC port that has muxes, call @p op with every mux in chain
+ * that passes @p filter
+ *
+ * @param filter Macro that should filter USB muxes and call @p op on them.
+ * It has USBC port node ID and @p op as arguments. It is called
+ * only for USBC ports that have usb_muxes property.
+ * @param op Operation to perform on USB muxes. Needs to accept USB mux node
+ * ID, USBC port node ID, position in chain, and driver config as
+ * arguments.
+ */
+#define USB_MUX_FOREACH_USBC_PORT(filter, op) \
+ DT_FOREACH_STATUS_OKAY_VARGS(named_usbc_port, \
+ USB_MUX_USBC_PORT_HAS_MUXES, \
+ filter, op)
+
+/**
+ * Forward declare all usb_mux structures e.g.
+ * MAYBE_CONST struct usb_mux USB_MUX_NODE_<node_id>;
+ */
+USB_MUX_FOREACH_USBC_PORT(USB_MUX_NO_FIRST, USB_MUX_DECLARE)
+
+#endif /* ZEPHYR_CHROME_USBC_USB_MUXES_H */
diff --git a/zephyr/shim/include/usbc/virtual_usb_mux.h b/zephyr/shim/include/usbc/virtual_usb_mux.h
new file mode 100644
index 0000000000..5f4c2fb466
--- /dev/null
+++ b/zephyr/shim/include/usbc/virtual_usb_mux.h
@@ -0,0 +1,20 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __ZEPHYR_SHIM_VIRTUAL_USB_MUX_H
+#define __ZEPHYR_SHIM_VIRTUAL_USB_MUX_H
+
+#include "usb_mux.h"
+
+#define VIRTUAL_USB_MUX_COMPAT cros_ec_usbc_mux_virtual
+
+#define USB_MUX_CONFIG_VIRTUAL(mux_id, port_id, idx) \
+ { \
+ USB_MUX_COMMON_FIELDS(mux_id, port_id, idx), \
+ .driver = &virtual_usb_mux_driver, \
+ .hpd_update = &virtual_hpd_update, \
+ }
+
+#endif /* __ZEPHYR_SHIM_VIRTUAL_USB_MUX_H */
diff --git a/zephyr/shim/src/CMakeLists.txt b/zephyr/shim/src/CMakeLists.txt
index ffc3331f06..dce9c57dac 100644
--- a/zephyr/shim/src/CMakeLists.txt
+++ b/zephyr/shim/src/CMakeLists.txt
@@ -72,3 +72,4 @@ zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_USB_PD_TCPM_TCPCI
zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_USBA usba.c)
zephyr_library_sources_ifdef(CONFIG_AP_PWRSEQ power_host_sleep_api.c)
+zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_USB_MUX usb_muxes.c)
diff --git a/zephyr/shim/src/usb_muxes.c b/zephyr/shim/src/usb_muxes.c
new file mode 100644
index 0000000000..e162478fec
--- /dev/null
+++ b/zephyr/shim/src/usb_muxes.c
@@ -0,0 +1,61 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <devicetree.h>
+#include <sys/util_macro.h>
+#include "usb_mux.h"
+#include "usbc/usb_muxes.h"
+
+/**
+ * @brief Macro that can be used in USB_MUX_FOREACH_USBC_PORT as filter
+ * argument. It allows to evaluate to "1 ||" for each named USBC port
+ * that has usb-muxes property.
+ */
+#define USB_MUX_PORT_HAS_MUX(unused1, unused2) 1 ||
+
+/**
+ * Check if there is any named USBC port with usb-muxes property. It evaluates
+ * to "1 || 1 || ... 1 || 0" when there are multiple named USBC ports with
+ * usb-muxes property and to "0" when any named USBC port has usb-muxes
+ * property.
+ *
+ * This prevents creating struct usb_mux usb_muxes[] for platforms that didn't
+ * migrate USB mux configuration to DTS yet.
+ */
+#if USB_MUX_FOREACH_USBC_PORT(USB_MUX_PORT_HAS_MUX, _) 0
+
+/**
+ * Define root of each USB muxes chain e.g.
+ * [0] = {
+ * .usb_port = 0,
+ * .next_mux = &USB_MUX_NODE_DT_N_S_usbc_S_port0_0_S_it5205_mux_0,
+ * .board_init = &board_init,
+ * .board_set = NULL,
+ * .flags = 0,
+ * .driver = &virtual_usb_mux_driver,
+ * .hpd_update = &virtual_hpd_update,
+ * },
+ * [1] = { ... },
+ */
+MAYBE_CONST struct usb_mux usb_muxes[] = {
+ USB_MUX_FOREACH_USBC_PORT(USB_MUX_FIRST, USB_MUX_ARRAY)
+};
+
+/**
+ * Define all USB muxes except roots e.g.
+ * MAYBE_CONST struct usb_mux USB_MUX_NODE_DT_N_S_usbc_S_port0_0_S_mux_0 = {
+ * .usb_port = 0,
+ * .next_mux = NULL,
+ * .board_init = NULL,
+ * .board_set = NULL,
+ * .flags = 0,
+ * .driver = &virtual_usb_mux_driver,
+ * .hpd_update = &virtual_hpd_update,
+ * };
+ * MAYBE_CONST struct usb_mux USB_MUX_NODE_<node_id> = { ... };
+ */
+USB_MUX_FOREACH_USBC_PORT(USB_MUX_NO_FIRST, USB_MUX_DEFINE)
+
+#endif /* #if USB_MUX_FOREACH_USBC_PORT(USB_MUX_PORT_HAS_MUX, _) */