Re: [PATCH v2 2/2] usb: typec: Add support for Parade PS8830 Type-C Retimer

From: Dmitry Baryshkov
Date: Sun Oct 06 2024 - 11:41:09 EST


On Fri, Oct 04, 2024 at 04:57:38PM GMT, Abel Vesa wrote:
> The Parade PS8830 is a Type-C muti-protocol retimer controlled over I2C.
> It provides both altmode and orientation handling.
>
> Add a driver with support for the following modes:
> - DP 4lanes
> - DP 2lanes + USB3
> - USB3
>
> Signed-off-by: Abel Vesa <abel.vesa@xxxxxxxxxx>
> ---
> drivers/usb/typec/mux/Kconfig | 10 +
> drivers/usb/typec/mux/Makefile | 1 +
> drivers/usb/typec/mux/ps8830.c | 424 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 435 insertions(+)
>
> diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig
> index ce7db6ad30572a0a74890f5f11944fb3ff07f635..48613b67f1c5dacd14d54baf91c3066377cf97be 100644
> --- a/drivers/usb/typec/mux/Kconfig
> +++ b/drivers/usb/typec/mux/Kconfig
> @@ -56,6 +56,16 @@ config TYPEC_MUX_NB7VPQ904M
> Say Y or M if your system has a On Semiconductor NB7VPQ904M Type-C
> redriver chip found on some devices with a Type-C port.
>
> +config TYPEC_MUX_PS8830
> + tristate "Parade PS8830 Type-C retimer driver"
> + depends on I2C
> + depends on DRM || DRM=n
> + select DRM_AUX_BRIDGE if DRM_BRIDGE && OF
> + select REGMAP_I2C
> + help
> + Say Y or M if your system has a Parade PS8830 Type-C retimer chip
> + found on some devices with a Type-C port.
> +
> config TYPEC_MUX_PTN36502
> tristate "NXP PTN36502 Type-C redriver driver"
> depends on I2C
> diff --git a/drivers/usb/typec/mux/Makefile b/drivers/usb/typec/mux/Makefile
> index bb96f30267af05b33b9277dcf1cc0e1527d2dcdd..4b23b12cfe45a0ff8a37f38c7ba050f572d556e7 100644
> --- a/drivers/usb/typec/mux/Makefile
> +++ b/drivers/usb/typec/mux/Makefile
> @@ -6,5 +6,6 @@ obj-$(CONFIG_TYPEC_MUX_PI3USB30532) += pi3usb30532.o
> obj-$(CONFIG_TYPEC_MUX_INTEL_PMC) += intel_pmc_mux.o
> obj-$(CONFIG_TYPEC_MUX_IT5205) += it5205.o
> obj-$(CONFIG_TYPEC_MUX_NB7VPQ904M) += nb7vpq904m.o
> +obj-$(CONFIG_TYPEC_MUX_PS8830) += ps8830.o
> obj-$(CONFIG_TYPEC_MUX_PTN36502) += ptn36502.o
> obj-$(CONFIG_TYPEC_MUX_WCD939X_USBSS) += wcd939x-usbss.o
> diff --git a/drivers/usb/typec/mux/ps8830.c b/drivers/usb/typec/mux/ps8830.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..58990f7860bf77ec12d00f0d3df3a40735bbf9d8
> --- /dev/null
> +++ b/drivers/usb/typec/mux/ps8830.c
> @@ -0,0 +1,424 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Parade PS8830 usb retimer driver
> + *
> + * Copyright (C) 2024 Linaro Ltd.
> + */
> +
> +#include <drm/bridge/aux-bridge.h>
> +#include <linux/clk.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.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>
> +
> +struct ps8830_retimer {
> + struct i2c_client *client;
> + struct gpio_desc *reset_gpio;
> + struct regmap *regmap;
> + struct typec_switch_dev *sw;
> + struct typec_retimer *retimer;
> + struct clk *xo_clk;
> + struct regulator *vdd_supply;
> + struct regulator *vdd33_supply;
> + struct regulator *vdd33_cap_supply;
> + struct regulator *vddat_supply;
> + struct regulator *vddar_supply;
> + struct regulator *vddio_supply;
> +
> + struct typec_switch *typec_switch;
> + struct typec_mux *typec_mux;
> +
> + struct mutex lock; /* protect non-concurrent retimer & switch */
> +
> + enum typec_orientation orientation;
> + unsigned long mode;
> + int cfg[3];
> +};
> +
> +static void ps8830_write(struct ps8830_retimer *retimer, int cfg0, int cfg1, int cfg2)
> +{
> + if (cfg0 == retimer->cfg[0] &&
> + cfg1 == retimer->cfg[1] &&
> + cfg2 == retimer->cfg[2])
> + return;
> +
> + retimer->cfg[0] = cfg0;
> + retimer->cfg[1] = cfg1;
> + retimer->cfg[2] = cfg2;
> +
> + regmap_write(retimer->regmap, 0x0, cfg0);
> + regmap_write(retimer->regmap, 0x1, cfg1);
> + regmap_write(retimer->regmap, 0x2, cfg2);
> +}

This looks like a reimplementation of regcache. Is it really necessary?

> +
> +static void ps8830_configure(struct ps8830_retimer *retimer, int cfg0, int cfg1, int cfg2)
> +{
> + /* Write safe-mode config before switching to new config */

Why is this required?

> + ps8830_write(retimer, 0x1, 0x0, 0x0);
> +
> + ps8830_write(retimer, cfg0, cfg1, cfg2);
> +}
> +
> +static int ps8380_set(struct ps8830_retimer *retimer)
> +{
> + int cfg0 = 0x00;
> + int cfg1 = 0x00;
> + int cfg2 = 0x00;
> +
> + if (retimer->orientation == TYPEC_ORIENTATION_NONE ||
> + retimer->mode == TYPEC_STATE_SAFE) {
> + ps8830_write(retimer, 0x1, 0x0, 0x0);
> + return 0;
> + }
> +
> + if (retimer->orientation == TYPEC_ORIENTATION_NORMAL)
> + cfg0 = 0x01;
> + else
> + cfg0 = 0x03;
> +
> + switch (retimer->mode) {
> + /* USB3 Only */
> + case TYPEC_STATE_USB:
> + cfg0 |= 0x20;
> + break;
> +

The TYPEC_DP clauses should only be used if state->alt->swid is set to
USB_TYPEC_DP_SID. Other altmodes share id space for their states.

> + /* DP Only */
> + case TYPEC_DP_STATE_C:
> + cfg1 = 0x85;
> + break;
> +
> + case TYPEC_DP_STATE_E:
> + cfg1 = 0x81;
> + break;
> +
> + /* DP + USB */
> + case TYPEC_DP_STATE_D:
> + cfg0 |= 0x20;
> + cfg1 = 0x85;
> + break;

CDE, please.

> +
> + default:
> + return -EOPNOTSUPP;
> + }
> +
> + ps8830_configure(retimer, cfg0, cfg1, cfg2);
> +
> + return 0;
> +}
> +

--
With best wishes
Dmitry