Re: [PATCH v2 03/12] usb: typec: API for controlling USB Type-C Multiplexers
From: Randy Dunlap
Date: Sun Feb 25 2018 - 14:22:56 EST
On 02/25/2018 07:25 AM, Hans de Goede wrote:
> From: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx>
>
> ---
> Documentation/driver-api/usb/typec.rst | 73 +++++++++++--
> drivers/usb/typec/Makefile | 1 +
> drivers/usb/typec/{typec.c => class.c} | 70 ++++++++++++
> drivers/usb/typec/mux.c | 188 +++++++++++++++++++++++++++++++++
> include/linux/usb/typec.h | 14 +++
> include/linux/usb/typec_mux.h | 55 ++++++++++
> 6 files changed, 390 insertions(+), 11 deletions(-)
> rename drivers/usb/typec/{typec.c => class.c} (95%)
> create mode 100644 drivers/usb/typec/mux.c
> create mode 100644 include/linux/usb/typec_mux.h
>
> diff --git a/Documentation/driver-api/usb/typec.rst b/Documentation/driver-api/usb/typec.rst
> index 8a7249f2ff04..091e4def3a39 100644
> --- a/Documentation/driver-api/usb/typec.rst
> +++ b/Documentation/driver-api/usb/typec.rst
> +
> +Multiplexer/DeMultiplexer Switches
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +USB Type-C connectors may have one or more mux/demux switches behind them. Since
> +the plugs can be inserted right-side-up or upside-down, a switch is needed to
> +route the correct data pairs from the connector to the USB controllers. If
> +Alternate or Accessory Modes are supported, an other switch is needed that can
another
> +route the pins on the connector to some other component besides USB. USB Type-C
> +Connector Class supplies an API for registering those switches.
> +
> +.. kernel-doc:: drivers/usb/typec/mux.c
> + :functions: typec_switch_register typec_switch_unregister typec_mux_register typec_mux_unregister
> +
> +In most cases the same physical mux will handle both the orientation and mode.
> +However, as the port drivers will be responsible of the orientation, and the
for the orientation,
> +alternate mode drivers of the mode, the two are always separated into their own
for the mode,
> +logical components: "mux" for the mode and "switch" for the orientation.
> +
> +When a port is registered, USB Type-C Connector Class requests both the mux and
> +the switch for the port. The drivers can then use the following API for
> +controlling them:
> +
> +.. kernel-doc:: drivers/usb/typec/class.c
> + :functions: typec_set_orientation typec_set_mode
> +
> +If the connector is dual-role capable, there may also be a switch for the data
> +role. USB Type-C Connector Class does not supply separate API for them. The
> +port drivers can use USB Role Class API with those.
> +
> +Illustration of the muxes behind a connector that supports an alternate mode:
> +
> + ------------------------
> + | Connector |
> + ------------------------
> + | |
> + ------------------------
> + \ Orientation /
> + --------------------
> + |
> + --------------------
> + / Mode \
> + ------------------------
> + / \
> + ------------------------ --------------------
> + | Alt Mode | / USB Role \
> + ------------------------ ------------------------
> + / \
> + ------------------------ ------------------------
> + | USB Host | | USB Device |
> + ------------------------ ------------------------
> diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
> new file mode 100644
> index 000000000000..3102238366ed
> --- /dev/null
> +++ b/drivers/usb/typec/mux.c
> @@ -0,0 +1,188 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/**
> + * USB Type-C Multiplexer/DeMultiplexer Switch support
> + *
> + * Copyright (C) 2018 Intel Corporation
> + * Author: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx>
> + * Hans de Goede <hdegoede@xxxxxxxxxx>
> + */
> +
> +#include <linux/device.h>
> +#include <linux/connection.h>
> +#include <linux/usb/typec_mux.h>
Needs: <linux/mutex.h> <linux/list.h> ...
> +static DEFINE_MUTEX(switch_lock);
> +static DEFINE_MUTEX(mux_lock);
> +static LIST_HEAD(switch_list);
> +static LIST_HEAD(mux_list);
> +
> +static void *typec_switch_match(struct devcon *con, int ep, void *data)
> +{
> + struct typec_switch *sw;
> +
> + list_for_each_entry(sw, &switch_list, entry)
> + if (!strcmp(con->endpoint[ep], dev_name(sw->dev)))
> + return sw;
> +
> + /*
> + * We only get called if a connection was found, tell the caller to
> + * wait for the switch to show-up.
show up.
> + */
> + return ERR_PTR(-EPROBE_DEFER);
> +}
> +
> +static void *typec_mux_match(struct devcon *con, int ep, void *data)
> +{
> + struct typec_mux *mux;
> +
> + list_for_each_entry(mux, &mux_list, entry)
> + if (!strcmp(con->endpoint[ep], dev_name(mux->dev)))
> + return mux;
> +
> + /*
> + * We only get called if a connection was found, tell the caller to
> + * wait for the switch to show-up.
show up.
> + */
> + return ERR_PTR(-EPROBE_DEFER);
> +}
> diff --git a/include/linux/usb/typec_mux.h b/include/linux/usb/typec_mux.h
> new file mode 100644
> index 000000000000..0ddaaa8b0ac1
> --- /dev/null
> +++ b/include/linux/usb/typec_mux.h
> @@ -0,0 +1,55 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#ifndef __USB_TYPEC_MUX
> +#define __USB_TYPEC_MUX
> +
> +#include <linux/list.h>
> +#include <linux/usb/typec.h>
> +
> +struct device;
> +
> +/**
> + * typec_switch - USB Type-C cable orientation switch
* struct typec_switch - USB Type-C cable orientation switch
> + * @dev: Switch device
> + * @entry: List entry
> + * @set: Callback to the driver for setting the orientation
> + *
> + * USB Type-C pin flipper switch routing the correct data pairs from the
> + * connector to the USB controller depending on the orientation of the cable
> + * plug.
> + */
> +struct typec_switch {
> + struct device *dev;
> + struct list_head entry;
> +
> + int (*set)(struct typec_switch *sw, enum typec_orientation orientation);
> +};
> +
> +/**
> + * typec_switch - USB Type-C connector pin mux
* struct typec_mux - USB Type-C connector pin mux
> + * @dev: Mux device
> + * @entry: List entry
> + * @set: Callback to the driver for setting the state of the mux
> + *
> + * Pin Multiplexer/DeMultiplexer switch routing the USB Type-C connector pins to
> + * different components depending on the requested mode of operation. Used with
> + * Accessory/Alternate modes.
> + */
> +struct typec_mux {
> + struct device *dev;
> + struct list_head entry;
> +
> + int (*set)(struct typec_mux *mux, int state);
> +};
ta.
--
~Randy