Re: [PATCH RFC 06/12] usb: typec: qcom: Add gen1 Type-C port support

From: David Heidelberg

Date: Sun Oct 18 2026 - 19:30:20 EST


On 26/09/2026 16:22, Bryan O'Donoghue wrote:
On 26/09/2026 13:40, David Heidelberg via B4 Relay wrote:
From: David Heidelberg <david@xxxxxxx>

Add a port backend for the first generation of the Qualcomm PMIC Type-C
block, found on PM660 and PMI8998.

On gen1 the Type-C CC logic is part of the charger's USBIN peripheral
(base 0x1300) instead of the standalone Type-C peripheral used by
PM8150B and later PMICs. All Type-C events (CC state change,
tCCDebounce done, VBUS change and error) are signalled through a single
aggregate "type-c-change" interrupt, the handler re-reads TYPEC_STATUS_4
to find out what changed. The PD PHY is register compatible with PM8150B
and is reused as is.

Differences to the PM8150B backend:
  - get_cc() returns -EBUSY until the hardware reports tCCDebounce done,
    instead of using a software debounce.
  - As a source, only the default and 1.5A Rp can be advertised, 3.0A
    requests are advertised as 1.5A.
  - The PBS workaround of the downstream SMB2 driver (TM_IO_DTEST4_SEL)
    is applied on every power role change.

VBUS sourcing is optional and only used when the connector provides
a vbus-supply, as the charger doesn't expose a VBUS regulator yet.

Assisted-by: LLM
Co-developed-by: Alexey Minnekhanov <alexeymin@xxxxxxxxxx>
Signed-off-by: Alexey Minnekhanov <alexeymin@xxxxxxxxxx>
Signed-off-by: David Heidelberg <david@xxxxxxx>
---
  drivers/usb/typec/tcpm/qcom/Makefile               |   1 +
  drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c      |   9 +
  .../typec/tcpm/qcom/qcom_pmic_typec_port_gen1.c    | 605 +++++++++++++++++++++
  .../typec/tcpm/qcom/qcom_pmic_typec_port_gen1.h    |  15 +
  4 files changed, 630 insertions(+)

diff --git a/drivers/usb/typec/tcpm/qcom/Makefile b/drivers/usb/typec/tcpm/ qcom/Makefile
index cc23042b94878..b8b9350184c19 100644
--- a/drivers/usb/typec/tcpm/qcom/Makefile
+++ b/drivers/usb/typec/tcpm/qcom/Makefile
@@ -1,7 +1,8 @@
  # SPDX-License-Identifier: GPL-2.0
  #
  obj-$(CONFIG_TYPEC_QCOM_PMIC)        += qcom_pmic_tcpm.o
  qcom_pmic_tcpm-y            += qcom_pmic_typec.o \
                         qcom_pmic_typec_port.o \
+                       qcom_pmic_typec_port_gen1.o \
                         qcom_pmic_typec_pdphy.o \
                         qcom_pmic_typec_pdphy_stub.o \
diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c b/drivers/usb/ typec/tcpm/qcom/qcom_pmic_typec.c
index 41aaae6bb3724..ea1d5b0927436 100644
--- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
+++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
@@ -12,16 +12,17 @@
  #include <linux/slab.h>
  #include <linux/usb/tcpm.h>
  #include <drm/bridge/aux-bridge.h>
  #include "qcom_pmic_typec.h"
  #include "qcom_pmic_typec_pdphy.h"
  #include "qcom_pmic_typec_port.h"
+#include "qcom_pmic_typec_port_gen1.h"
  typedef int (*pmic_typec_port_probe_fn)(struct platform_device *pdev,
                      struct pmic_typec *tcpm,
                      const struct pmic_typec_port_resources *res,
                      struct regmap *regmap, u32 base);
  struct pmic_typec_resources {
      const struct pmic_typec_pdphy_resources    *pdphy_res;
@@ -134,31 +135,39 @@ static void qcom_pmic_typec_remove(struct platform_device *pdev)
      struct pmic_typec *tcpm = platform_get_drvdata(pdev);
      tcpm->pdphy_stop(tcpm);
      tcpm->port_stop(tcpm);
      tcpm_unregister_port(tcpm->tcpm_port);
      fwnode_handle_put(tcpm->tcpc.fwnode);
  }
+static const struct pmic_typec_resources gen1_typec_res = {
+    .pdphy_res = &pm8150b_pdphy_res,
+    .port_res = &gen1_port_res,
+    .port_probe = qcom_pmic_typec_gen1_port_probe,
+};
+
  static const struct pmic_typec_resources pm8150b_typec_res = {
      .pdphy_res = &pm8150b_pdphy_res,
      .port_res = &pm8150b_port_res,
      .port_probe = qcom_pmic_typec_port_probe,
  };
  static const struct pmic_typec_resources pmi632_typec_res = {
      /* PD PHY not present */
      .port_res = &pm8150b_port_res,
      .port_probe = qcom_pmic_typec_port_probe,
  };
  static const struct of_device_id qcom_pmic_typec_table[] = {
+    { .compatible = "qcom,pm660-typec", .data = &gen1_typec_res },
      { .compatible = "qcom,pm8150b-typec", .data = &pm8150b_typec_res },
      { .compatible = "qcom,pmi632-typec", .data = &pmi632_typec_res },
+    { .compatible = "qcom,pmi8998-typec", .data = &gen1_typec_res },

I think this should be

> +    { .compatible = "qcom,pm660-typec", .data = &pm660_typec_res },
>       { .compatible = "qcom,pm8150b-typec", .data = &pm8150b_typec_res },
>       { .compatible = "qcom,pmi632-typec", .data = &pmi632_typec_res },
> +    { .compatible = "qcom,pmi8998-typec", .data = &pmi8998_typec_res },

Since I'm not sure "gen1" is a real thing and besides, I see this gen1/gen2/gen3 stuff in CAMSS and it means almost nothing. The silicon version is the salient thing.

Best I can do is GenZ.
But now seriously, I hoped someone from Qualcomm will chime in and tells me how is this type-c block generation properly called.

David

[...]