From: Sascha Hauer <sha@pengutronix.de>
To: Ahmad Fatoum <a.fatoum@pengutronix.de>
Cc: barebox@lists.infradead.org
Subject: Re: [PATCH v2 1/2] usb: add basic USB Type-C framework
Date: Wed, 21 Jun 2023 11:16:18 +0200 [thread overview]
Message-ID: <20230621091618.GD18491@pengutronix.de> (raw)
In-Reply-To: <20230621090329.2652672-1-a.fatoum@pengutronix.de>
On Wed, Jun 21, 2023 at 11:03:29AM +0200, Ahmad Fatoum wrote:
> Board code or user scripts may want to base their decisions on the
> state of a USB-C connector:
>
> - Is the USB role that of a USB device or of a USB host?
> - Is the board being powered externally?
> - Is a debug accessory attached?
>
> For this reason, we add here a very simplified Type-C driver core inspired
> by Linux that just registers a device and populates it with three parameters:
>
> - $dev.usb_role = { device, host }
> - $dev.pwr_role = { sink, source }
> - $dev.accessory = { none, audio, debug }
>
> These variables are updated by struct typec_operations::poll, which
> corresponds to the IRQ handler for the Linux drivers. The poll function
> is called on every variable access and early exits if no IRQ was
> indicated.
>
> In future, we may elect to register the poll function with the poller
> framework, so it's called cyclically, like we do for e.g. Ethernet link
> detection, but for now, this is probably sufficient.
>
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> ---
> v1 -> v2:
> - add missing <linux/usb/role.h> header from fixup
> - split framework from driver
Applied, thanks
Sascha
> ---
> Documentation/user/usb.rst | 12 ++
> drivers/usb/Kconfig | 2 +
> drivers/usb/Makefile | 1 +
> drivers/usb/typec/Kconfig | 6 +
> drivers/usb/typec/Makefile | 2 +
> drivers/usb/typec/class.c | 179 ++++++++++++++++++++++++++++++
> include/linux/usb/role.h | 12 ++
> include/linux/usb/typec.h | 54 +++++++++
> include/linux/usb/typec_altmode.h | 44 ++++++++
> 9 files changed, 312 insertions(+)
> create mode 100644 drivers/usb/typec/Kconfig
> create mode 100644 drivers/usb/typec/Makefile
> create mode 100644 drivers/usb/typec/class.c
> create mode 100644 include/linux/usb/role.h
> create mode 100644 include/linux/usb/typec.h
> create mode 100644 include/linux/usb/typec_altmode.h
>
> diff --git a/Documentation/user/usb.rst b/Documentation/user/usb.rst
> index f2f57ead98d4..20e223da93b5 100644
> --- a/Documentation/user/usb.rst
> +++ b/Documentation/user/usb.rst
> @@ -247,6 +247,18 @@ mode. Once a specific mode has been selected it can't be changed later anymore.
> musb-hdrc: 28/31 max ep, 16384/16384 memory
> barebox:/
>
> +USB Type-C support
> +------------------
> +
> +barebox can usually stay oblivious to the type of connector used. Sometimes though,
> +board code and user scripts may want to base their decisions on how a USB-C connector
> +is connected. Type C drivers can thus register with the Type C driver core to
> +export a number of device parameters:
> +
> +- ``$typec0.usb_role`` = { ``none``, ``device``, ``host`` }
> +- ``$typec0.pwr_role`` = { ``sink``, ``source`` }
> +- ``$typec0.accessory`` = { ``none``, ``audio``, ``debug`` }
> +
> USB Gadget autostart Support
> ----------------------------
>
> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
> index e43c28113f41..d66a75635d46 100644
> --- a/drivers/usb/Kconfig
> +++ b/drivers/usb/Kconfig
> @@ -24,6 +24,8 @@ source "drivers/usb/misc/Kconfig"
>
> endif
>
> +source "drivers/usb/typec/Kconfig"
> +
> source "drivers/usb/gadget/Kconfig"
>
> source "drivers/usb/musb/Kconfig"
> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
> index 8f1557d5d497..0cac50c0f39b 100644
> --- a/drivers/usb/Makefile
> +++ b/drivers/usb/Makefile
> @@ -8,5 +8,6 @@ obj-$(CONFIG_USB_STORAGE) += storage/
> obj-y += host/
> obj-y += otg/
> obj-y += gadget/
> +obj-y += typec/
> obj-$(CONFIG_USB) += misc/
>
> diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig
> new file mode 100644
> index 000000000000..56f10e6ca549
> --- /dev/null
> +++ b/drivers/usb/typec/Kconfig
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +
> +config TYPEC
> + prompt "Compile USB Type-C framework support" if COMPILE_TEST
> + bool
> diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
> new file mode 100644
> index 000000000000..6b8347f10c06
> --- /dev/null
> +++ b/drivers/usb/typec/Makefile
> @@ -0,0 +1,2 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +obj-$(CONFIG_TYPEC) += class.o
> diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
> new file mode 100644
> index 000000000000..7f498550f80e
> --- /dev/null
> +++ b/drivers/usb/typec/class.c
> @@ -0,0 +1,179 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * USB Type-C Connector Class
> + *
> + * Copyright (C) 2017, Intel Corporation
> + * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> + */
> +
> +#include <module.h>
> +#include <driver.h>
> +#include <linux/usb/role.h>
> +#include <linux/usb/typec.h>
> +#include <linux/usb/typec_altmode.h>
> +#include <param.h>
> +
> +enum typec_param_accessory {
> + TYPEC_PARAM_ACCESSORY_NONE,
> + TYPEC_PARAM_ACCESSORY_AUDIO,
> + TYPEC_PARAM_ACCESSORY_DEBUG,
> +};
> +
> +struct typec_port {
> + struct device dev;
> + const struct typec_operations *ops;
> + int pwr_role; /* enum typec_role */
> + int usb_role; /* enum usb_role role */
> + int accessory; /* enum typec_param_accessory */
> +};
> +
> +/**
> + * typec_set_pwr_role - Report power role change
> + * @port: The USB Type-C Port where the role was changed
> + * @role: The new data role
> + *
> + * This routine is used by the port drivers to report power role changes.
> + */
> +void typec_set_pwr_role(struct typec_port *port, enum typec_role role)
> +{
> + port->pwr_role = role;
> +}
> +EXPORT_SYMBOL_GPL(typec_set_pwr_role);
> +
> +static inline enum typec_param_accessory typec_mode_to_accessory(int mode)
> +{
> + switch (mode) {
> + case TYPEC_MODE_AUDIO:
> + return TYPEC_PARAM_ACCESSORY_AUDIO;
> + case TYPEC_MODE_DEBUG:
> + return TYPEC_PARAM_ACCESSORY_DEBUG;
> + default:
> + return TYPEC_PARAM_ACCESSORY_NONE;
> + }
> +}
> +
> +/**
> + * typec_set_mode - Set mode of operation for USB Type-C connector
> + * @port: USB Type-C connector
> + * @mode: Accessory Mode, USB Operation or Safe State
> + *
> + * Configure @port for Accessory Mode @mode. This function will configure the
> + * muxes needed for @mode.
> + */
> +int typec_set_mode(struct typec_port *port, int mode)
> +{
> + port->accessory = typec_mode_to_accessory(mode);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(typec_set_mode);
> +
> +/**
> + * typec_set_role - Set USB role for a Type-C connector
> + * @port: USB Type-C connector
> + * @role: USB role to be switched to
> + *
> + * Set USB role @role for @sw. This is equivalent to Linux
> + * usb_role_switch_set_role();
> + */
> +int typec_set_role(struct typec_port *port, enum usb_role role)
> +{
> + port->usb_role = role;
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(typec_set_role);
> +
> +/**
> + * typec_get_drvdata - Return private driver data pointer
> + * @port: USB Type-C port
> + */
> +void *typec_get_drvdata(struct typec_port *port)
> +{
> + return port->dev.priv;
> +}
> +EXPORT_SYMBOL_GPL(typec_get_drvdata);
> +
> +static int typec_register_port_dev(struct typec_port *port, const char *name, int id)
> +{
> + port->dev.id = id;
> + dev_set_name(&port->dev, name);
> +
> + return register_device(&port->dev);
> +}
> +
> +static const char * const usb_role_names[] = {
> + [USB_ROLE_NONE] = "none",
> + [USB_ROLE_HOST] = "host",
> + [USB_ROLE_DEVICE] = "device",
> +};
> +
> +static const char * const pwr_role_names[] = {
> + [TYPEC_SINK] = "sink",
> + [TYPEC_SOURCE] = "source",
> +};
> +
> +static const char * const accessory_names[] = {
> + [TYPEC_PARAM_ACCESSORY_NONE] = "none",
> + [TYPEC_PARAM_ACCESSORY_AUDIO] = "audio", /* analog */
> + [TYPEC_PARAM_ACCESSORY_DEBUG] = "debug",
> +};
> +
> +static int typec_param_update(struct param_d *p, void *priv)
> +{
> + struct typec_port *port = priv;
> +
> + return port->ops->poll(port);
> +}
> +
> +/**
> + * typec_register_port - Register a USB Type-C Port
> + * @parent: Parent device
> + * @cap: Description of the port
> + *
> + * Registers a device for USB Type-C Port described in @cap.
> + *
> + * Returns handle to the port on success or ERR_PTR on failure.
> + */
> +struct typec_port *typec_register_port(struct device *parent,
> + const struct typec_capability *cap)
> +{
> + struct typec_port *port;
> + struct device *dev;
> + const char *alias;
> + int ret;
> +
> + port = kzalloc(sizeof(*port), GFP_KERNEL);
> + if (!port)
> + return ERR_PTR(-ENOMEM);
> +
> + port->ops = cap->ops;
> + dev = &port->dev;
> + dev->parent = parent;
> + dev->of_node = cap->of_node;
> + dev->priv = cap->driver_data;
> +
> + alias = dev->of_node ? of_alias_get(dev->of_node) : NULL;
> + if (alias)
> + ret = typec_register_port_dev(port, alias, DEVICE_ID_SINGLE);
> + if (!alias || ret)
> + ret = typec_register_port_dev(port, "typec", DEVICE_ID_DYNAMIC);
> +
> + if (ret)
> + return ERR_PTR(ret);
> +
> + of_platform_device_dummy_drv(dev);
> + if (dev->of_node)
> + dev->of_node->dev = dev;
> +
> + dev_add_param_enum(dev, "usb_role", param_set_readonly, typec_param_update,
> + &port->usb_role, usb_role_names,
> + ARRAY_SIZE(usb_role_names), port);
> + dev_add_param_enum(dev, "pwr_role", param_set_readonly, typec_param_update,
> + &port->pwr_role, pwr_role_names,
> + ARRAY_SIZE(pwr_role_names), port);
> + dev_add_param_enum(dev, "accessory", param_set_readonly, typec_param_update,
> + &port->accessory, accessory_names,
> + ARRAY_SIZE(accessory_names), port);
> +
> + return port;
> +}
> +EXPORT_SYMBOL_GPL(typec_register_port);
> diff --git a/include/linux/usb/role.h b/include/linux/usb/role.h
> new file mode 100644
> index 000000000000..bf78db7e6fa8
> --- /dev/null
> +++ b/include/linux/usb/role.h
> @@ -0,0 +1,12 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#ifndef __LINUX_USB_ROLE_H
> +#define __LINUX_USB_ROLE_H
> +
> +enum usb_role {
> + USB_ROLE_NONE,
> + USB_ROLE_HOST,
> + USB_ROLE_DEVICE,
> +};
> +
> +#endif /* __LINUX_USB_ROLE_H */
> diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
> new file mode 100644
> index 000000000000..315dee95e47f
> --- /dev/null
> +++ b/include/linux/usb/typec.h
> @@ -0,0 +1,54 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef __LINUX_USB_TYPEC_H
> +#define __LINUX_USB_TYPEC_H
> +
> +#include <linux/types.h>
> +#include <linux/usb/role.h>
> +
> +struct typec_port;
> +
> +struct device;
> +struct device_node;
> +
> +enum typec_role {
> + TYPEC_SINK,
> + TYPEC_SOURCE,
> +};
> +
> +enum typec_accessory {
> + TYPEC_ACCESSORY_NONE,
> + TYPEC_ACCESSORY_AUDIO,
> + TYPEC_ACCESSORY_DEBUG,
> +};
> +
> +struct typec_operations {
> + int (*poll)(struct typec_port *port);
> +};
> +
> +/*
> + * struct typec_capability - USB Type-C Port Capabilities
> + * @driver_data: Private pointer for driver specific info
> + * @ops: Port operations vector
> + *
> + * Static capabilities of a single USB Type-C port.
> + */
> +struct typec_capability {
> + void *driver_data;
> +
> + const struct typec_operations *ops;
> + struct device_node *of_node;
> +};
> +
> +struct typec_port *typec_register_port(struct device *parent,
> + const struct typec_capability *cap);
> +
> +void typec_set_pwr_role(struct typec_port *port, enum typec_role role);
> +
> +int typec_set_mode(struct typec_port *port, int mode);
> +
> +int typec_set_role(struct typec_port *port, enum usb_role role);
> +
> +void *typec_get_drvdata(struct typec_port *port);
> +
> +#endif /* __LINUX_USB_TYPEC_H */
> diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h
> new file mode 100644
> index 000000000000..ffa4a8f75420
> --- /dev/null
> +++ b/include/linux/usb/typec_altmode.h
> @@ -0,0 +1,44 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef __USB_TYPEC_ALTMODE_H
> +#define __USB_TYPEC_ALTMODE_H
> +
> +/*
> + * These are the connector states (USB, Safe and Alt Mode) defined in USB Type-C
> + * Specification. SVID specific connector states are expected to follow and
> + * start from the value TYPEC_STATE_MODAL.
> + */
> +enum {
> + TYPEC_STATE_SAFE, /* USB Safe State */
> + TYPEC_STATE_USB, /* USB Operation */
> + TYPEC_STATE_MODAL, /* Alternate Modes */
> +};
> +
> +/*
> + * For the muxes there is no difference between Accessory Modes and Alternate
> + * Modes, so the Accessory Modes are supplied with specific modal state values
> + * here. Unlike with Alternate Modes, where the mux will be linked with the
> + * alternate mode device, the mux for Accessory Modes will be linked with the
> + * port device instead.
> + *
> + * Port drivers can use TYPEC_MODE_AUDIO and TYPEC_MODE_DEBUG as the mode
> + * value for typec_set_mode() when accessory modes are supported.
> + *
> + * USB4 also requires that the pins on the connector are repurposed, just like
> + * Alternate Modes. USB4 mode is however not entered with the Enter Mode Command
> + * like the Alternate Modes are, but instead with a special Enter_USB Message.
> + * The Enter_USB Message can also be used for setting to connector to operate in
> + * USB 3.2 or in USB 2.0 mode instead of USB4.
> + *
> + * The Enter_USB specific "USB Modes" are also supplied here as special modal
> + * state values, just like the Accessory Modes.
> + */
> +enum {
> + TYPEC_MODE_USB2 = TYPEC_STATE_MODAL, /* USB 2.0 mode */
> + TYPEC_MODE_USB3, /* USB 3.2 mode */
> + TYPEC_MODE_USB4, /* USB4 mode */
> + TYPEC_MODE_AUDIO, /* Audio Accessory */
> + TYPEC_MODE_DEBUG, /* Debug Accessory */
> +};
> +
> +#endif /* __USB_TYPEC_ALTMODE_H */
> --
> 2.39.2
>
>
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
prev parent reply other threads:[~2023-06-21 9:17 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-21 9:03 Ahmad Fatoum
2023-06-21 9:03 ` [PATCH v2 2/2] usb: add basic TUSB320 Type-C controller support Ahmad Fatoum
2023-06-21 9:16 ` Sascha Hauer [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230621091618.GD18491@pengutronix.de \
--to=sha@pengutronix.de \
--cc=a.fatoum@pengutronix.de \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox