* [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation
@ 2026-09-26 12:40 David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 01/12] usb: typec: tcpm: qcom: Release the connector fwnode reference David Heidelberg via B4 Relay
` (11 more replies)
0 siblings, 12 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
This series adds basic USB Type-C support for 1st gen devices, covering
configurations that do not require VBUS power (e.g. devices using
externally powered docks).
VBUS support will be added in a follow-up series after this one is merged.
Supporting VBUS will likely require refactoring parts of the SMBX charger
support, which is why it is not included here.
Tested with an externally powered dock station:
- Pixel 3 / 3 XL
- SHIFT 6mq
- OnePlus 6
Tested with an additional, not-yet-included VBUS patch for non-powered
devices:
- Xiaomi Redmi Note 7
- Xiaomi Mi Pad 4
Credits to everyone who has contributed to Type-C enablement before:
Casey Connolly
Zachary Dry — LLM generation and testing
Max Furman — LLM generation and testing
Signed-off-by: David Heidelberg <david@ixit.cz>
---
Alexey Minnekhanov (1):
arm64: dts: qcom: pm660: Add USB Type-C port controller node
David Heidelberg (11):
usb: typec: tcpm: qcom: Release the connector fwnode reference
dt-bindings: usb: qcom,pmic-typec: Update example with vbus-supply
dt-bindings: usb: Add Qualcomm 1st-gen PMIC Type-C
usb: typec: qcom: Make PMIC port probe selectable
usb: typec: qcom: Make typec_port accept also different structure
usb: typec: qcom: Add gen1 Type-C port support
arm64: dts: qcom: pmi8998: Add USB Type-C port controller node
arm64: dts: qcom: sdm670-google-common: Enable USB Type-C port controller
arm64: dts: qcom: sdm845-google-common: Enable USB Type-C port controller
arm64: dts: qcom: sdm845-oneplus-common: Enable USB Type-C port controller
arm64: dts: qcom: sdm845-shift-axolotl: Enable USB Type-C port controller
.../devicetree/bindings/mfd/qcom,spmi-pmic.yaml | 4 +-
.../bindings/usb/qcom,pmic-typec-gen1.yaml | 130 +++++
.../devicetree/bindings/usb/qcom,pmic-typec.yaml | 3 +-
arch/arm64/boot/dts/qcom/pm660.dtsi | 27 +
arch/arm64/boot/dts/qcom/pmi8998.dtsi | 27 +
arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi | 51 +-
arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi | 59 +-
.../arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 48 +-
arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts | 62 ++-
drivers/usb/typec/tcpm/qcom/Makefile | 1 +
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c | 20 +-
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h | 2 +-
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c | 2 +
.../typec/tcpm/qcom/qcom_pmic_typec_port_gen1.c | 605 +++++++++++++++++++++
.../typec/tcpm/qcom/qcom_pmic_typec_port_gen1.h | 15 +
15 files changed, 1045 insertions(+), 11 deletions(-)
---
base-commit: 7079a12d7506b07fb53b54a664bfad5fa9b16d70
change-id: 20260922-typec-6c48ef7ac8b0
Best regards,
--
David Heidelberg <david@ixit.cz>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 01/12] usb: typec: tcpm: qcom: Release the connector fwnode reference
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 02/12] dt-bindings: usb: qcom,pmic-typec: Update example with vbus-supply David Heidelberg via B4 Relay
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: David Heidelberg <david@ixit.cz>
device_get_named_child_node() returns the connector node with its
reference count incremented, but the port probe never drops it. The node
is only needed for the VBUS regulator lookup, so release it right after.
Assisted-by: LLM
Fixes: 506927b6bf29 ("usb: typec: tcpm: qcom: prefer VBUS supply from the connector node")
Signed-off-by: David Heidelberg <david@ixit.cz>
---
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c
index bf985efe1cd6b..f8308d66b9d67 100644
--- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c
+++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c
@@ -5,16 +5,17 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/string_choices.h>
#include <linux/usb/tcpm.h>
#include <linux/usb/typec_mux.h>
#include <linux/workqueue.h>
@@ -723,16 +724,17 @@ int qcom_pmic_typec_port_probe(struct platform_device *pdev,
connector = device_get_named_child_node(dev, "connector");
if (!connector)
return -EINVAL;
pmic_typec_port->vdd_vbus = devm_of_regulator_get_optional(dev,
to_of_node(connector),
"vbus");
+ fwnode_handle_put(connector);
if (pmic_typec_port->vdd_vbus == ERR_PTR(-ENODEV))
pmic_typec_port->vdd_vbus = devm_regulator_get(dev, "vdd-vbus");
if (IS_ERR(pmic_typec_port->vdd_vbus))
return PTR_ERR(pmic_typec_port->vdd_vbus);
pmic_typec_port->dev = dev;
pmic_typec_port->base = base;
pmic_typec_port->regmap = regmap;
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 02/12] dt-bindings: usb: qcom,pmic-typec: Update example with vbus-supply
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 01/12] usb: typec: tcpm: qcom: Release the connector fwnode reference David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 03/12] dt-bindings: usb: Add Qualcomm 1st-gen PMIC Type-C David Heidelberg via B4 Relay
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: David Heidelberg <david@ixit.cz>
The vdd-vbus-supply is deprecated, thus don't suggest deprecated usage in
example.
Assisted-by: LLM
Signed-off-by: David Heidelberg <david@ixit.cz>
---
Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml b/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml
index ba790c4488b76..2c8b11e92fb28 100644
--- a/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml
+++ b/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml
@@ -163,29 +163,30 @@ examples:
"sig-rx",
"msg-tx",
"msg-rx",
"msg-tx-failed",
"msg-tx-discarded",
"msg-rx-discarded",
"fr-swap";
- vdd-vbus-supply = <&pm8150b_vbus>;
vdd-pdphy-supply = <&vreg_l2a_3p1>;
connector {
compatible = "usb-c-connector";
power-role = "source";
data-role = "dual";
self-powered;
source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_DUAL_ROLE |
PDO_FIXED_USB_COMM | PDO_FIXED_DATA_SWAP)>;
+ vbus-supply = <&pm8150b_vbus>;
+
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
pmic_typec_hs_in: endpoint {
remote-endpoint = <&usb_hs_out>;
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 03/12] dt-bindings: usb: Add Qualcomm 1st-gen PMIC Type-C
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 01/12] usb: typec: tcpm: qcom: Release the connector fwnode reference David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 02/12] dt-bindings: usb: qcom,pmic-typec: Update example with vbus-supply David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 04/12] usb: typec: qcom: Make PMIC port probe selectable David Heidelberg via B4 Relay
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: David Heidelberg <david@ixit.cz>
Add a binding for the first generation of the Qualcomm PMIC USB Type-C
port controller, found on the PM660 and PMI8998 PMICs.
Unlike the later standalone Type-C peripheral at 0x1500 (e.g. PM8150B),
the gen1 Type-C CC logic is part of the charger's USBIN peripheral
(base 0x1300) and signals all Type-C events (CC state change,
tCCDebounce done, VBUS change and error) through a single aggregate
"type-c-change" interrupt. The USB PD PHY at 0x1700 is register
compatible with PM8150B.
The different interrupt set and register layout make it a separate
binding rather than another variant of qcom,pmic-typec. As with PM8150B,
the Type-C block and PD PHY are described as a separate SPMI node from
the charger.
Allow typec nodes of the Qualcomm SPMI PMIC to use the new binding as
well.
Assisted-by: LLM
Signed-off-by: David Heidelberg <david@ixit.cz>
---
.../devicetree/bindings/mfd/qcom,spmi-pmic.yaml | 4 +-
.../bindings/usb/qcom,pmic-typec-gen1.yaml | 130 +++++++++++++++++++++
2 files changed, 133 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
index 5e0ed30a9a466..d7a43aa423c8a 100644
--- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
+++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
@@ -199,17 +199,19 @@ patternProperties:
$ref: /schemas/thermal/qcom,spmi-temp-alarm.yaml#
"^temperature-sensor@[0-9a-f]+$":
type: object
$ref: /schemas/thermal/qcom,pm8775-mbg-tm.yaml#
"^typec@[0-9a-f]+$":
type: object
- $ref: /schemas/usb/qcom,pmic-typec.yaml#
+ oneOf:
+ - $ref: /schemas/usb/qcom,pmic-typec.yaml#
+ - $ref: /schemas/usb/qcom,pmic-typec-gen1.yaml#
"^usb-detect@[0-9a-f]+$":
type: object
$ref: /schemas/extcon/qcom,pm8941-misc.yaml#
"^usb-vbus-regulator@[0-9a-f]+$":
type: object
$ref: /schemas/regulator/qcom,usb-vbus-regulator.yaml#
diff --git a/Documentation/devicetree/bindings/usb/qcom,pmic-typec-gen1.yaml b/Documentation/devicetree/bindings/usb/qcom,pmic-typec-gen1.yaml
new file mode 100644
index 0000000000000..8e93719fac3d1
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/qcom,pmic-typec-gen1.yaml
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/qcom,pmic-typec-gen1.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm PMIC USB Type-C block (gen1)
+
+maintainers:
+ - David Heidelberg <david@ixit.cz>
+
+description:
+ First generation of the Qualcomm PMIC Type-C port controller.
+
+properties:
+ compatible:
+ enum:
+ - qcom,pm660-typec
+ - qcom,pmi8998-typec
+
+ reg:
+ items:
+ - description: USBIN peripheral base (Type-C CC logic)
+ - description: USB PD PHY peripheral base
+
+ interrupts:
+ items:
+ - description: Type-C change - CC state, tCCDebounce done, VBUS change or error
+ - description: Power Domain Signal TX - HardReset or CableReset signal TX
+ - description: Power Domain Signal RX - HardReset or CableReset signal RX
+ - description: Power Domain TX complete
+ - description: Power Domain RX complete
+ - description: Power Domain TX fail
+ - description: Power Domain TX message discard
+ - description: Power Domain RX message discard
+ - description: Power Domain Fast Role Swap event
+
+ interrupt-names:
+ items:
+ - const: type-c-change
+ - const: sig-tx
+ - const: sig-rx
+ - const: msg-tx
+ - const: msg-rx
+ - const: msg-tx-failed
+ - const: msg-tx-discarded
+ - const: msg-rx-discarded
+ - const: fr-swap
+
+ vdd-pdphy-supply:
+ description: VDD regulator supply to the PDPHY.
+
+ connector:
+ type: object
+ $ref: /schemas/connector/usb-connector.yaml#
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - interrupt-names
+ - vdd-pdphy-supply
+ - connector
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/usb/pd.h>
+
+ pmic {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ typec@1300 {
+ compatible = "qcom,pmi8998-typec";
+ reg = <0x1300>,
+ <0x1700>;
+
+ interrupts = <0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x4 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x6 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x7 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "type-c-change",
+ "sig-tx",
+ "sig-rx",
+ "msg-tx",
+ "msg-rx",
+ "msg-tx-failed",
+ "msg-tx-discarded",
+ "msg-rx-discarded",
+ "fr-swap";
+
+ vdd-pdphy-supply = <&vreg_l24a_3p075>;
+
+ connector {
+ compatible = "usb-c-connector";
+
+ power-role = "dual";
+ data-role = "dual";
+ try-power-role = "sink";
+
+ source-pdos = <PDO_FIXED(5000, 900, PDO_FIXED_DUAL_ROLE |
+ PDO_FIXED_USB_COMM | PDO_FIXED_DATA_SWAP)>;
+ sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_DUAL_ROLE |
+ PDO_FIXED_USB_COMM | PDO_FIXED_DATA_SWAP)>;
+ op-sink-microwatt = <15000000>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ endpoint {
+ remote-endpoint = <&usb_dwc3_hs>;
+ };
+ };
+ };
+ };
+ };
+ };
+...
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 04/12] usb: typec: qcom: Make PMIC port probe selectable
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
` (2 preceding siblings ...)
2026-09-26 12:40 ` [PATCH RFC 03/12] dt-bindings: usb: Add Qualcomm 1st-gen PMIC Type-C David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 05/12] usb: typec: qcom: Make typec_port accept also different structure David Heidelberg via B4 Relay
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: David Heidelberg <david@ixit.cz>
This is a preparation for extending the support with 1st generation
Type-C.
Assisted-by: LLM
Co-developed-by: Alexey Minnekhanov <alexeymin@minlexx.ru>
Signed-off-by: Alexey Minnekhanov <alexeymin@minlexx.ru>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
index d770e58bc16cf..41aaae6bb3724 100644
--- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
+++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
@@ -13,19 +13,25 @@
#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"
+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;
const struct pmic_typec_port_resources *port_res;
+ pmic_typec_port_probe_fn port_probe;
};
static int qcom_pmic_typec_init(struct tcpc_dev *tcpc)
{
return 0;
}
static int qcom_pmic_typec_probe(struct platform_device *pdev)
@@ -55,18 +61,17 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)
dev_err(dev, "Failed to get regmap\n");
return -ENODEV;
}
ret = of_property_read_u32_index(np, "reg", 0, &base);
if (ret)
return ret;
- ret = qcom_pmic_typec_port_probe(pdev, tcpm,
- res->port_res, regmap, base);
+ ret = res->port_probe(pdev, tcpm, res->port_res, regmap, base);
if (ret)
return ret;
if (res->pdphy_res) {
ret = of_property_read_u32_index(np, "reg", 1, &base);
if (ret)
return ret;
@@ -132,21 +137,23 @@ static void qcom_pmic_typec_remove(struct platform_device *pdev)
tcpm->port_stop(tcpm);
tcpm_unregister_port(tcpm->tcpm_port);
fwnode_handle_put(tcpm->tcpc.fwnode);
}
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,pm8150b-typec", .data = &pm8150b_typec_res },
{ .compatible = "qcom,pmi632-typec", .data = &pmi632_typec_res },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_pmic_typec_table);
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 05/12] usb: typec: qcom: Make typec_port accept also different structure
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
` (3 preceding siblings ...)
2026-09-26 12:40 ` [PATCH RFC 04/12] usb: typec: qcom: Make PMIC port probe selectable David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 06/12] usb: typec: qcom: Add gen1 Type-C port support David Heidelberg via B4 Relay
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: David Heidelberg <david@ixit.cz>
This is needed by followup commit introducing 1st gen of type-c support.
Assisted-by: LLM
Co-developed-by: Alexey Minnekhanov <alexeymin@minlexx.ru>
Signed-off-by: Alexey Minnekhanov <alexeymin@minlexx.ru>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h
index 3c75820c91876..6f89d296ad151 100644
--- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h
+++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h
@@ -6,17 +6,17 @@
#ifndef __QCOM_PMIC_TYPEC_H__
#define __QCOM_PMIC_TYPEC_H__
struct pmic_typec {
struct device *dev;
struct tcpm_port *tcpm_port;
struct tcpc_dev tcpc;
struct pmic_typec_pdphy *pmic_typec_pdphy;
- struct pmic_typec_port *pmic_typec_port;
+ void *pmic_typec_port;
int (*pdphy_start)(struct pmic_typec *tcpm,
struct tcpm_port *tcpm_port);
void (*pdphy_stop)(struct pmic_typec *tcpm);
int (*port_start)(struct pmic_typec *tcpm,
struct tcpm_port *tcpm_port);
void (*port_stop)(struct pmic_typec *tcpm);
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 06/12] usb: typec: qcom: Add gen1 Type-C port support
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
` (4 preceding siblings ...)
2026-09-26 12:40 ` [PATCH RFC 05/12] usb: typec: qcom: Make typec_port accept also different structure David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 07/12] arm64: dts: qcom: pm660: Add USB Type-C port controller node David Heidelberg via B4 Relay
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: David Heidelberg <david@ixit.cz>
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@minlexx.ru>
Signed-off-by: Alexey Minnekhanov <alexeymin@minlexx.ru>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
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 },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_pmic_typec_table);
static struct platform_driver qcom_pmic_typec_driver = {
.driver = {
.name = "qcom,pmic-typec",
.of_match_table = qcom_pmic_typec_table,
diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port_gen1.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port_gen1.c
new file mode 100644
index 0000000000000..b4e3e49664f9d
--- /dev/null
+++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port_gen1.c
@@ -0,0 +1,605 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Qualcomm Type-C port backend (1st gen)
+ *
+ * GEN1 predates the standalone PM8150B-style Type-C register block.
+ * Its CC/role controls live in the USBIN peripheral, while the PD PHY
+ * is a separate PMIC peripheral.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/usb/tcpm.h>
+
+#include "qcom_pmic_typec.h"
+#include "qcom_pmic_typec_port.h"
+#include "qcom_pmic_typec_port_gen1.h"
+
+/* USBIN Type-C status */
+#define TYPEC_STATUS_1_REG 0x0b
+#define UFP_TYPEC_MASK GENMASK(7, 5)
+#define UFP_TYPEC_RDSTD BIT(7)
+#define UFP_TYPEC_RD1P5 BIT(6)
+#define UFP_TYPEC_RD3P0 BIT(5)
+
+#define TYPEC_STATUS_2_REG 0x0c
+#define DFP_TYPEC_MASK GENMASK(3, 0)
+#define DFP_RD_OPEN BIT(3)
+#define DFP_RD_RA_VCONN BIT(2)
+#define DFP_RD_RD BIT(1)
+#define DFP_RA_RA BIT(0)
+
+#define TYPEC_STATUS_4_REG 0x0e
+#define UFP_DFP_MODE_STATUS BIT(7)
+#define TYPEC_VBUS_STATUS BIT(6)
+#define TYPEC_VBUS_ERROR BIT(5)
+#define TYPEC_DEBOUNCE_DONE BIT(4)
+#define CC_ORIENTATION BIT(1)
+#define CC_ATTACHED BIT(0)
+
+/* USBIN Type-C configuration */
+#define TYPEC_CFG_REG 0x58
+#define TYPEC_OR_U_USB BIT(0)
+
+#define TYPEC_CFG_2_REG 0x59
+#define EN_TRY_SOURCE_MODE BIT(3)
+#define EN_80UA_180UA_CUR_SOURCE BIT(0)
+
+#define TYPEC_CFG_3_REG 0x5a
+#define EN_TRYSINK_MODE BIT(2)
+
+#define TYPEC_INTRPT_ENB_REG 0x67
+#define VBUS_ERROR_INT_EN BIT(5)
+#define DEBOUNCE_DONE_INT_EN BIT(3)
+#define CCSTATE_CHANGE_INT_EN BIT(2)
+#define VBUS_DEASSERT_INT_EN BIT(1)
+#define VBUS_ASSERT_INT_EN BIT(0)
+
+#define TYPEC_SW_CTRL_REG 0x68
+#define VCONN_EN_ORIENTATION BIT(6)
+#define VCONN_EN_SRC BIT(4)
+#define VCONN_EN_VALUE BIT(3)
+#define POWER_ROLE_CMD_MASK GENMASK(2, 0)
+#define UFP_EN_CMD BIT(2)
+#define DFP_EN_CMD BIT(1)
+#define TYPEC_DISABLE_CMD BIT(0)
+
+/* GEN1 TYPEC_PBS_WA_BIT workaround used by the downstream SMB2 driver. */
+#define MISC_BASE_OFFSET 0x300
+#define TM_IO_DTEST4_SEL 0xe9
+#define PBS_CRUDE_SENSOR_ENABLE 0xa5
+
+/* Interrupt numbers */
+#define PMIC_TYPEC_CHANGE_IRQ 0x0
+
+struct gen1_typec_port {
+ struct device *dev;
+ struct tcpm_port *tcpm_port;
+ struct regmap *regmap;
+ u32 base;
+ int irq;
+
+ struct regulator *vbus;
+ bool vbus_enabled;
+ bool vbus_present;
+ bool vbus_valid;
+ struct mutex lock; /* serializes register RMW and VBUS state */
+};
+
+const struct pmic_typec_port_resources gen1_port_res = {
+ .nr_irqs = 1,
+ .irq_params = {
+ {
+ .irq_name = "type-c-change",
+ .virq = PMIC_TYPEC_CHANGE_IRQ,
+ },
+ },
+};
+
+/*
+ * Failure of this workaround write is non-fatal and
+ * we can continue with the role transition.
+ */
+static void gen1_typec_pbs_wa(struct gen1_typec_port *port, bool sink)
+{
+ unsigned int val = sink ? 0 : PBS_CRUDE_SENSOR_ENABLE;
+ int ret;
+
+ ret = regmap_write(port->regmap, port->base +
+ MISC_BASE_OFFSET + TM_IO_DTEST4_SEL, val);
+ if (!ret)
+ return;
+
+ dev_warn(port->dev,
+ "failed to update GEN1 Type-C PBS workaround: %d\n",
+ ret);
+}
+
+static int gen1_typec_set_power_role(struct gen1_typec_port *port,
+ unsigned int role)
+{
+ int ret;
+
+ gen1_typec_pbs_wa(port, role == UFP_EN_CMD);
+
+ ret = regmap_update_bits(port->regmap,
+ port->base + TYPEC_SW_CTRL_REG,
+ POWER_ROLE_CMD_MASK, role);
+ if (ret)
+ dev_err(port->dev, "failed to set Type-C power role: %d\n", ret);
+
+ return ret;
+}
+
+static int gen1_typec_get_vbus(struct tcpc_dev *tcpc)
+{
+ struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+ struct gen1_typec_port *port = tcpm->pmic_typec_port;
+ unsigned int status;
+ int ret;
+
+ mutex_lock(&port->lock);
+ ret = regmap_read(port->regmap, port->base +
+ TYPEC_STATUS_4_REG, &status);
+ if (ret)
+ ret = port->vbus_enabled;
+ else
+ ret = port->vbus_enabled || !!(status & TYPEC_VBUS_STATUS);
+ mutex_unlock(&port->lock);
+
+ return ret;
+}
+
+static int gen1_typec_set_vbus(struct tcpc_dev *tcpc, bool on, bool sink)
+{
+ struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+ struct gen1_typec_port *port = tcpm->pmic_typec_port;
+ bool changed = false;
+ int ret = 0;
+
+ if (!port->vbus)
+ return 0;
+
+ mutex_lock(&port->lock);
+
+ if (port->vbus_enabled == on)
+ goto out;
+
+ if (on)
+ ret = regulator_enable(port->vbus);
+ else
+ ret = regulator_disable(port->vbus);
+
+ if (!ret) {
+ port->vbus_enabled = on;
+ changed = true;
+ }
+
+out:
+ mutex_unlock(&port->lock);
+
+ /*
+ * set_vbus() may run during tcpm_register_port() before port_start()
+ * provides tcpm_port. Once registered, notify TCPM whenever the
+ * source regulator actually changes state. get_vbus() also accounts
+ * for vbus_enabled when GEN1 does not reflect sourced VBUS in
+ * TYPEC_VBUS_STATUS.
+ */
+ if (changed && port->tcpm_port)
+ tcpm_vbus_change(port->tcpm_port);
+
+ return ret;
+}
+
+static int gen1_typec_get_cc(struct tcpc_dev *tcpc,
+ enum typec_cc_status *cc1,
+ enum typec_cc_status *cc2)
+{
+ struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+ struct gen1_typec_port *port = tcpm->pmic_typec_port;
+ enum typec_cc_status active = TYPEC_CC_OPEN;
+ unsigned int status1, status2, status4;
+ bool orientation_cc2;
+ int ret;
+
+ *cc1 = TYPEC_CC_OPEN;
+ *cc2 = TYPEC_CC_OPEN;
+
+ mutex_lock(&port->lock);
+
+ ret = regmap_read(port->regmap, port->base +
+ TYPEC_STATUS_4_REG, &status4);
+ if (ret)
+ goto out;
+
+ if (!(status4 & CC_ATTACHED))
+ goto out;
+
+ /*
+ * CC is not stable until tCCDebounce has elapsed. TCPM ignores
+ * -EBUSY and the DEBOUNCE_DONE interrupt triggers a new read.
+ */
+ if (!(status4 & TYPEC_DEBOUNCE_DONE)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = regmap_read(port->regmap, port->base +
+ TYPEC_STATUS_1_REG, &status1);
+ if (ret)
+ goto out;
+
+ ret = regmap_read(port->regmap, port->base +
+ TYPEC_STATUS_2_REG, &status2);
+ if (ret)
+ goto out;
+
+ orientation_cc2 = !!(status4 & CC_ORIENTATION);
+
+ if (status4 & UFP_DFP_MODE_STATUS) {
+ /* Local port is DFP/source; decode the partner's Rd/Ra. */
+ switch (status2 & DFP_TYPEC_MASK) {
+ case DFP_RA_RA:
+ *cc1 = TYPEC_CC_RA;
+ *cc2 = TYPEC_CC_RA;
+ goto out;
+ case DFP_RD_RD:
+ *cc1 = TYPEC_CC_RD;
+ *cc2 = TYPEC_CC_RD;
+ goto out;
+ case DFP_RD_RA_VCONN:
+ active = TYPEC_CC_RD;
+ *cc1 = TYPEC_CC_RA;
+ *cc2 = TYPEC_CC_RA;
+ break;
+ case DFP_RD_OPEN:
+ active = TYPEC_CC_RD;
+ break;
+ default:
+ dev_dbg(port->dev, "unhandled GEN1 DFP status %#x\n",
+ status2);
+ goto out;
+ }
+ } else {
+ /* Local port is UFP/sink; decode the partner's advertised Rp. */
+ switch (status1 & UFP_TYPEC_MASK) {
+ case UFP_TYPEC_RDSTD:
+ active = TYPEC_CC_RP_DEF;
+ break;
+ case UFP_TYPEC_RD1P5:
+ active = TYPEC_CC_RP_1_5;
+ break;
+ case UFP_TYPEC_RD3P0:
+ active = TYPEC_CC_RP_3_0;
+ break;
+ default:
+ dev_dbg(port->dev, "unhandled GEN1 UFP status %#x\n",
+ status1);
+ goto out;
+ }
+ }
+
+ if (orientation_cc2)
+ *cc2 = active;
+ else
+ *cc1 = active;
+
+out:
+ mutex_unlock(&port->lock);
+ return ret;
+}
+
+static int gen1_typec_set_cc(struct tcpc_dev *tcpc,
+ enum typec_cc_status cc)
+{
+ struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+ struct gen1_typec_port *port = tcpm->pmic_typec_port;
+ unsigned int role;
+ unsigned int rp_current = 0;
+ int ret;
+
+ switch (cc) {
+ case TYPEC_CC_OPEN:
+ role = TYPEC_DISABLE_CMD;
+ break;
+ case TYPEC_CC_RD:
+ role = UFP_EN_CMD;
+ break;
+ case TYPEC_CC_RP_DEF:
+ role = DFP_EN_CMD;
+ rp_current = 0;
+ break;
+ case TYPEC_CC_RP_1_5:
+ case TYPEC_CC_RP_3_0:
+ /*
+ * GEN1 can only source 80 uA (default) or 180 uA (1.5 A).
+ * Advertise 1.5 A for 3.0 A requests, TCPM ignores set_cc()
+ * errors and would otherwise keep a stale Rp.
+ */
+ role = DFP_EN_CMD;
+ rp_current = EN_80UA_180UA_CUR_SOURCE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&port->lock);
+
+ if (role == DFP_EN_CMD) {
+ ret = regmap_update_bits(port->regmap,
+ port->base + TYPEC_CFG_2_REG,
+ EN_80UA_180UA_CUR_SOURCE,
+ rp_current);
+ if (ret)
+ goto out;
+ }
+
+ ret = gen1_typec_set_power_role(port, role);
+
+out:
+ mutex_unlock(&port->lock);
+ return ret;
+}
+
+static int gen1_typec_set_polarity(struct tcpc_dev *tcpc,
+ enum typec_cc_polarity polarity)
+{
+ /* USB PHY orientation is handled outside this PMIC Type-C block. */
+ return 0;
+}
+
+static int gen1_typec_set_vconn(struct tcpc_dev *tcpc, bool on)
+{
+ struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+ struct gen1_typec_port *port = tcpm->pmic_typec_port;
+ unsigned int status4, orientation, mask, val;
+ int ret;
+
+ mutex_lock(&port->lock);
+
+ ret = regmap_read(port->regmap, port->base +
+ TYPEC_STATUS_4_REG, &status4);
+ if (ret)
+ goto out;
+
+ /* VCONN is driven on the inactive CC pin. */
+ orientation = (status4 & CC_ORIENTATION) ?
+ 0 : VCONN_EN_ORIENTATION;
+
+ if (on) {
+ mask = VCONN_EN_ORIENTATION | VCONN_EN_VALUE;
+ val = orientation | VCONN_EN_VALUE;
+ } else {
+ mask = VCONN_EN_VALUE;
+ val = 0;
+ }
+
+ ret = regmap_update_bits(port->regmap,
+ port->base + TYPEC_SW_CTRL_REG,
+ mask, val);
+
+out:
+ mutex_unlock(&port->lock);
+ return ret;
+}
+
+static int gen1_typec_start_toggling(struct tcpc_dev *tcpc,
+ enum typec_port_type port_type,
+ enum typec_cc_status cc)
+{
+ struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+ struct gen1_typec_port *port = tcpm->pmic_typec_port;
+ unsigned int role;
+ unsigned int try_src = 0;
+ unsigned int try_snk = 0;
+ int ret;
+
+ switch (port_type) {
+ case TYPEC_PORT_SRC:
+ role = DFP_EN_CMD;
+ break;
+ case TYPEC_PORT_SNK:
+ role = UFP_EN_CMD;
+ break;
+ case TYPEC_PORT_DRP:
+ role = 0;
+ /*
+ * Like the PM8150B backend, keep hardware Try.SNK enabled
+ * while TCPM owns the policy state machine.
+ */
+ try_snk = EN_TRYSINK_MODE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&port->lock);
+
+ ret = regmap_update_bits(port->regmap,
+ port->base + TYPEC_CFG_2_REG,
+ EN_TRY_SOURCE_MODE, try_src);
+ if (ret)
+ goto out;
+
+ ret = regmap_update_bits(port->regmap,
+ port->base + TYPEC_CFG_3_REG,
+ EN_TRYSINK_MODE, try_snk);
+ if (ret)
+ goto out;
+
+ /* Disable first so the state machine restarts toggling. */
+ ret = gen1_typec_set_power_role(port, TYPEC_DISABLE_CMD);
+ if (ret)
+ goto out;
+
+ ret = gen1_typec_set_power_role(port, role);
+
+out:
+ mutex_unlock(&port->lock);
+ return ret;
+}
+
+static irqreturn_t gen1_typec_irq(int irq, void *data)
+{
+ struct gen1_typec_port *port = data;
+ unsigned int status4;
+ bool vbus;
+ bool vbus_changed = false;
+
+ /*
+ * GEN1 exposes a single aggregate Type-C change interrupt. Always
+ * notify TCPM of CC changes. Only generate a VBUS event when the
+ * hardware VBUS state changes, or on the first observation so TCPM
+ * can establish the initial vSafe0V state.
+ */
+ mutex_lock(&port->lock);
+
+ if (!regmap_read(port->regmap, port->base +
+ TYPEC_STATUS_4_REG, &status4)) {
+ if (status4 & TYPEC_VBUS_ERROR)
+ dev_warn_ratelimited(port->dev, "Type-C VBUS error\n");
+
+ vbus = !!(status4 & TYPEC_VBUS_STATUS);
+
+ if (!port->vbus_valid || vbus != port->vbus_present) {
+ port->vbus_present = vbus;
+ port->vbus_valid = true;
+ vbus_changed = true;
+ }
+ }
+
+ mutex_unlock(&port->lock);
+
+ if (port->tcpm_port) {
+ if (vbus_changed)
+ tcpm_vbus_change(port->tcpm_port);
+
+ tcpm_cc_change(port->tcpm_port);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int gen1_typec_port_start(struct pmic_typec *tcpm,
+ struct tcpm_port *tcpm_port)
+{
+ struct gen1_typec_port *port = tcpm->pmic_typec_port;
+ unsigned int irq_mask;
+ int ret;
+
+ /*
+ * TYPE_C_OR_U_USB == 0 selects the Type-C state machine on GEN1.
+ */
+ ret = regmap_update_bits(port->regmap,
+ port->base + TYPEC_CFG_REG,
+ TYPEC_OR_U_USB, 0);
+ if (ret)
+ return ret;
+
+ /*
+ * GEN1 exposes a single aggregate type-c-change interrupt, the
+ * handler re-reads TYPEC_STATUS_4 to find out what changed.
+ */
+ irq_mask = CCSTATE_CHANGE_INT_EN | DEBOUNCE_DONE_INT_EN |
+ VBUS_ASSERT_INT_EN | VBUS_DEASSERT_INT_EN |
+ VBUS_ERROR_INT_EN;
+
+ ret = regmap_write(port->regmap,
+ port->base + TYPEC_INTRPT_ENB_REG,
+ irq_mask);
+ if (ret)
+ return ret;
+
+ /* Select software control for VCONN, initially disabled. */
+ ret = regmap_update_bits(port->regmap,
+ port->base + TYPEC_SW_CTRL_REG,
+ VCONN_EN_SRC | VCONN_EN_VALUE,
+ VCONN_EN_SRC);
+ if (ret)
+ return ret;
+
+ port->tcpm_port = tcpm_port;
+ enable_irq(port->irq);
+
+ return 0;
+}
+
+static void gen1_typec_port_stop(struct pmic_typec *tcpm)
+{
+ struct gen1_typec_port *port = tcpm->pmic_typec_port;
+
+ disable_irq(port->irq);
+ port->tcpm_port = NULL;
+}
+
+int qcom_pmic_typec_gen1_port_probe(struct platform_device *pdev,
+ struct pmic_typec *tcpm,
+ const struct pmic_typec_port_resources *res,
+ struct regmap *regmap,
+ u32 base)
+{
+ struct device *dev = &pdev->dev;
+ struct gen1_typec_port *port;
+ struct fwnode_handle *connector;
+ int ret;
+
+ if (!res->nr_irqs || res->nr_irqs > PMIC_TYPEC_MAX_IRQS)
+ return -EINVAL;
+
+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ connector = device_get_named_child_node(dev, "connector");
+ if (!connector)
+ return -EINVAL;
+
+ port->vbus = devm_of_regulator_get_optional(dev,
+ to_of_node(connector),
+ "vbus");
+ fwnode_handle_put(connector);
+ if (IS_ERR(port->vbus)) {
+ if (PTR_ERR(port->vbus) != -ENODEV)
+ return PTR_ERR(port->vbus);
+ port->vbus = NULL;
+ }
+
+ port->irq = platform_get_irq_byname(pdev,
+ res->irq_params[0].irq_name);
+ if (port->irq < 0)
+ return port->irq;
+
+ port->dev = dev;
+ port->regmap = regmap;
+ port->base = base;
+ mutex_init(&port->lock);
+
+ ret = devm_request_threaded_irq(dev, port->irq, NULL,
+ gen1_typec_irq,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN,
+ res->irq_params[0].irq_name, port);
+ if (ret)
+ return ret;
+
+ tcpm->pmic_typec_port = port;
+
+ tcpm->tcpc.get_vbus = gen1_typec_get_vbus;
+ tcpm->tcpc.set_vbus = gen1_typec_set_vbus;
+ tcpm->tcpc.get_cc = gen1_typec_get_cc;
+ tcpm->tcpc.set_cc = gen1_typec_set_cc;
+ tcpm->tcpc.set_polarity = gen1_typec_set_polarity;
+ tcpm->tcpc.set_vconn = gen1_typec_set_vconn;
+ tcpm->tcpc.start_toggling = gen1_typec_start_toggling;
+
+ tcpm->port_start = gen1_typec_port_start;
+ tcpm->port_stop = gen1_typec_port_stop;
+
+ return 0;
+}
diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port_gen1.h b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port_gen1.h
new file mode 100644
index 0000000000000..45e373d22edca
--- /dev/null
+++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port_gen1.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __QCOM_PMIC_TYPEC_PORT_GEN1_H__
+#define __QCOM_PMIC_TYPEC_PORT_GEN1_H__
+
+#include "qcom_pmic_typec_port.h"
+
+extern const struct pmic_typec_port_resources gen1_port_res;
+
+int qcom_pmic_typec_gen1_port_probe(struct platform_device *pdev,
+ struct pmic_typec *tcpm,
+ const struct pmic_typec_port_resources *res,
+ struct regmap *regmap,
+ u32 base);
+
+#endif /* __QCOM_PMIC_TYPEC_PORT_GEN1_H__ */
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 07/12] arm64: dts: qcom: pm660: Add USB Type-C port controller node
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
` (5 preceding siblings ...)
2026-09-26 12:40 ` [PATCH RFC 06/12] usb: typec: qcom: Add gen1 Type-C port support David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 08/12] arm64: dts: qcom: pmi8998: " David Heidelberg via B4 Relay
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: Alexey Minnekhanov <alexeymin@minlexx.ru>
Add the PM660 Type-C port controller and PD PHY device node.
As on PMI8998, the Type-C CC logic is part of the charger's USBIN
peripheral at 0x1300, the PD PHY is at 0x1700. The node uses the
'type-c-change' interrupt from the USBIN peripheral for CC state
notifications, plus the 8 PD PHY interrupts, including fr-swap.
The node is disabled by default; individual boards enable it and provide
the USB-C connector description with PD capabilities and port graph.
Assisted-by: LLM
Signed-off-by: Alexey Minnekhanov <alexeymin@minlexx.ru>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
arch/arm64/boot/dts/qcom/pm660.dtsi | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 156b2ddff0dcb..37965a3607417 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -85,16 +85,43 @@ pm660_charger: charger@1000 {
io-channels = <&pm660_rradc 3>,
<&pm660_rradc 4>;
io-channel-names = "usbin_i", "usbin_v";
status = "disabled";
};
+ pm660_typec: typec@1300 {
+ compatible = "qcom,pm660-typec";
+ reg = <0x1300>,
+ <0x1700>;
+
+ interrupts = <0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x4 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x6 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x7 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "type-c-change",
+ "sig-tx",
+ "sig-rx",
+ "msg-tx",
+ "msg-rx",
+ "msg-tx-failed",
+ "msg-tx-discarded",
+ "msg-rx-discarded",
+ "fr-swap";
+
+ status = "disabled";
+ };
+
pm660_temp: temp-alarm@2400 {
compatible = "qcom,spmi-temp-alarm";
reg = <0x2400>;
interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
io-channels = <&pm660_adc ADC5_DIE_TEMP>;
io-channel-names = "thermal";
#thermal-sensor-cells = <0>;
};
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 08/12] arm64: dts: qcom: pmi8998: Add USB Type-C port controller node
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
` (6 preceding siblings ...)
2026-09-26 12:40 ` [PATCH RFC 07/12] arm64: dts: qcom: pm660: Add USB Type-C port controller node David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 09/12] arm64: dts: qcom: sdm670-google-common: Enable USB Type-C port controller David Heidelberg via B4 Relay
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: David Heidelberg <david@ixit.cz>
Add the pmi8998 Type-C port controller and PD PHY device node.
The Type-C CC logic is at USBIN base 0x1300 and the PD PHY is at 0x1700.
The node uses the 'type-c-change' interrupt from the USBIN peripheral
for CC state notifications, plus the 8 PD PHY interrupts, including
fr-swap.
The node is disabled by default; individual boards enable it and provide
the USB-C connector description with PD capabilities and port graph.
Assisted-by: LLM
Signed-off-by: David Heidelberg <david@ixit.cz>
---
arch/arm64/boot/dts/qcom/pmi8998.dtsi | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index cd3f0790fd420..878e577c667d0 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -24,16 +24,43 @@ pmi8998_charger: charger@1000 {
io-channels = <&pmi8998_rradc 3>,
<&pmi8998_rradc 4>;
io-channel-names = "usbin_i", "usbin_v";
status = "disabled";
};
+ pmi8998_typec: typec@1300 {
+ compatible = "qcom,pmi8998-typec";
+ reg = <0x1300>,
+ <0x1700>;
+
+ interrupts = <0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x4 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x6 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x17 0x7 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "type-c-change",
+ "sig-tx",
+ "sig-rx",
+ "msg-tx",
+ "msg-rx",
+ "msg-tx-failed",
+ "msg-tx-discarded",
+ "msg-rx-discarded",
+ "fr-swap";
+
+ status = "disabled";
+ };
+
pmi8998_gpios: gpio@c000 {
compatible = "qcom,pmi8998-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
gpio-ranges = <&pmi8998_gpios 0 0 14>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 09/12] arm64: dts: qcom: sdm670-google-common: Enable USB Type-C port controller
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
` (7 preceding siblings ...)
2026-09-26 12:40 ` [PATCH RFC 08/12] arm64: dts: qcom: pmi8998: " David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 10/12] arm64: dts: qcom: sdm845-google-common: " David Heidelberg via B4 Relay
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: David Heidelberg <david@ixit.cz>
Enable the PM660 Type-C port controller with a USB-C connector
description for the Google Pixel 3a (sargo) and Pixel 3a XL (bonito),
which share the same USB-C hardware via this common dtsi.
The connector is configured as:
- Sink-only power role with a 5V/3A sink PDO
- Dual-role data with USB role switching
The VBUS output of the charger is not supported yet, so the port can't
act as a power source. Describe it as sink-only until VBUS support lands,
USB host mode is still reachable through a PD data role swap. Higher
voltage PDOs are left out until the charger driver programs the allowed
USBIN adapter voltage.
The Pixel 3a USB-C port is USB 2.0 only, so only the HS endpoint is
wired to the DWC3 controller.
Switch the DWC3 controller from peripheral-only to OTG mode with
usb-role-switch to allow the TCPM framework to control USB host/device
role based on CC pin detection.
Assisted-by: LLM
Signed-off-by: David Heidelberg <david@ixit.cz>
---
arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi | 51 +++++++++++++++++++++-
1 file changed, 49 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi b/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi
index b4854801a5f5e..afecbef2e5bc2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi
@@ -6,16 +6,17 @@
* Copyright (c) 2022, Richard Acayan. All rights reserved.
*/
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/leds/common.h>
#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
#include <dt-bindings/power/qcom-rpmpd.h>
+#include <dt-bindings/usb/pd.h>
#include "sdm670.dtsi"
#include "pm660.dtsi"
#include "pm660l.dtsi"
/delete-node/ &mpss_region;
/delete-node/ &venus_mem;
/delete-node/ &wlan_msa_mem;
/delete-node/ &cdsp_mem;
@@ -580,16 +581,56 @@ cam_vio_pin: cam-vio-state {
power-source = <0>;
};
};
&pm660_rradc {
status = "okay";
};
+&pm660_typec {
+ vdd-pdphy-supply = <&vreg_l7b_3p125>;
+
+ status = "okay";
+
+ connector {
+ compatible = "usb-c-connector";
+
+ /*
+ * Sink only for now, as the PM660 charger doesn't provide
+ * the VBUS output yet. Switch to the dual power role with
+ * source PDOs, try-power-role and vbus-supply once it is
+ * supported.
+ *
+ * Higher voltage sink PDOs will be added once the charger
+ * driver programs the allowed USBIN adapter voltage.
+ */
+ power-role = "sink";
+ data-role = "dual";
+ self-powered;
+
+ sink-pdos = <PDO_FIXED(5000, 3000,
+ PDO_FIXED_USB_COMM |
+ PDO_FIXED_DATA_SWAP)>;
+ op-sink-microwatt = <15000000>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ pm660_hs_in: endpoint {
+ remote-endpoint = <&usb_1_dwc3_hs>;
+ };
+ };
+ };
+ };
+};
+
&pm660l_flash {
status = "okay";
led-0 {
function = LED_FUNCTION_FLASH;
color = <LED_COLOR_ID_WHITE>;
led-sources = <1>, <2>;
led-max-microamp = <500000>;
@@ -702,16 +743,22 @@ &usb_1_hsphy {
};
&usb_1 {
qcom,select-utmi-as-pipe-clk;
status = "okay";
};
&usb_1_dwc3 {
- /* Only peripheral works for now */
- dr_mode = "peripheral";
+ dr_mode = "otg";
+ usb-role-switch;
/* Do not assume that sdm670.dtsi will never support USB 3.0 */
phys = <&usb_1_hsphy>;
phy-names = "usb2-phy";
maximum-speed = "high-speed";
+
+ port {
+ usb_1_dwc3_hs: endpoint {
+ remote-endpoint = <&pm660_hs_in>;
+ };
+ };
};
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 10/12] arm64: dts: qcom: sdm845-google-common: Enable USB Type-C port controller
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
` (8 preceding siblings ...)
2026-09-26 12:40 ` [PATCH RFC 09/12] arm64: dts: qcom: sdm670-google-common: Enable USB Type-C port controller David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 11/12] arm64: dts: qcom: sdm845-oneplus-common: " David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 12/12] arm64: dts: qcom: sdm845-shift-axolotl: " David Heidelberg via B4 Relay
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: David Heidelberg <david@ixit.cz>
Enable the PMI8998 Type-C port controller with a USB-C connector
description for the Google Pixel 3 (blueline) and Pixel 3 XL
(crosshatch), which share the same USB-C hardware via this common dtsi.
The connector is configured as:
- Sink-only power role with a 5V/3A sink PDO
- Operating sink power 7.6W (matching downstream configuration)
- Dual-role data with USB role switching
The VBUS output of the charger is not supported yet, so the port can't
act as a power source. Describe it as sink-only until VBUS support lands,
USB host mode is still reachable through a PD data role swap. Higher
voltage PDOs are left out until the charger driver programs the allowed
USBIN adapter voltage.
DisplayPort Alt Mode is not advertised as Google disabled DP output in
the Pixel 3 hardware design (downstream explicitly sets sde_dp to
disabled and excludes it from the MDSS connector list).
Wire the USB-C connector port graph:
- port@0: DWC3 HS endpoint for USB role switching
- port@1: QMP combo PHY for USB SS orientation switching
Switch the DWC3 controller from peripheral-only to OTG mode with
usb-role-switch to allow the TCPM framework to control USB host/device
role based on CC pin detection.
Assisted-by: LLM
Signed-off-by: David Heidelberg <david@ixit.cz>
---
arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi | 59 +++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi
index 9e952f9862f24..99f40a13b5d7f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi
@@ -2,16 +2,17 @@
/dts-v1/;
#include <dt-bindings/arm/qcom,ids.h>
#include <dt-bindings/dma/qcom-gpi.h>
#include <dt-bindings/input/linux-event-codes.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <dt-bindings/usb/pd.h>
#include "sdm845.dtsi"
#include "pm8998.dtsi"
#include "pmi8998.dtsi"
/delete-node/ &mpss_region;
/delete-node/ &venus_mem;
/delete-node/ &cdsp_mem;
@@ -449,16 +450,63 @@ &pm8998_resin {
};
&pmi8998_charger {
monitored-battery = <&battery>;
status = "okay";
};
+&pmi8998_typec {
+ status = "okay";
+
+ vdd-pdphy-supply = <&vreg_l24a_3p075>;
+
+ connector {
+ compatible = "usb-c-connector";
+
+ /*
+ * Sink only for now, as the PMI8998 charger doesn't provide
+ * the VBUS output yet. Switch to the dual power role with
+ * source PDOs, try-power-role and vbus-supply once it is
+ * supported.
+ *
+ * Higher voltage sink PDOs will be added once the charger
+ * driver programs the allowed USBIN adapter voltage.
+ */
+ power-role = "sink";
+ data-role = "dual";
+ self-powered;
+
+ sink-pdos = <PDO_FIXED(5000, 3000,
+ PDO_FIXED_USB_COMM |
+ PDO_FIXED_DATA_SWAP)>;
+ op-sink-microwatt = <7600000>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ pmi8998_hs_in: endpoint {
+ remote-endpoint = <&usb_1_dwc3_hs>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ pmi8998_typec_mux_in: endpoint {
+ remote-endpoint = <&usb_1_qmpphy_out>;
+ };
+ };
+ };
+ };
+};
+
&qupv3_id_0 {
status = "okay";
};
&qupv3_id_1 {
status = "okay";
};
@@ -549,17 +597,22 @@ &ufs_mem_phy {
status = "okay";
};
&usb_1 {
status = "okay";
};
&usb_1_dwc3 {
- dr_mode = "peripheral";
+ dr_mode = "otg";
+ usb-role-switch;
+};
+
+&usb_1_dwc3_hs {
+ remote-endpoint = <&pmi8998_hs_in>;
};
&usb_1_hsphy {
vdd-supply = <&vreg_l1a_0p875>;
vdda-pll-supply = <&vreg_l12a_1p8>;
vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
qcom,imp-res-offset-value = <8>;
@@ -572,16 +625,20 @@ &usb_1_hsphy {
&usb_1_qmpphy {
vdda-phy-supply = <&vreg_l1a_0p875>;
vdda-pll-supply = <&vreg_l26a_1p2>;
status = "okay";
};
+&usb_1_qmpphy_out {
+ remote-endpoint = <&pmi8998_typec_mux_in>;
+};
+
&venus {
firmware-name = "qcom/sdm845/Google/blueline/venus.mbn";
status = "okay";
};
&wifi {
vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>;
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 11/12] arm64: dts: qcom: sdm845-oneplus-common: Enable USB Type-C port controller
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
` (9 preceding siblings ...)
2026-09-26 12:40 ` [PATCH RFC 10/12] arm64: dts: qcom: sdm845-google-common: " David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 12/12] arm64: dts: qcom: sdm845-shift-axolotl: " David Heidelberg via B4 Relay
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: David Heidelberg <david@ixit.cz>
Enable the PMI8998 Type-C port controller with a USB-C connector
description for the OnePlus 6 (enchilada) and OnePlus 6T (fajita),
which share the same USB-C hardware via this common dtsi.
The connector is configured as:
- Sink-only power role with a 5V/3A sink PDO
- Dual-role data with USB role switching
The VBUS output of the charger is not supported yet, so the port can't
act as a power source. Describe it as sink-only until VBUS support lands,
USB host mode is still reachable through a PD data role swap.
Only the HS endpoint (port@0) is wired to the DWC3 controller since
these devices use USB 2.0 only — the QMP USB3+DP combo PHY is not
connected in the OnePlus 6/6T hardware design. Consequently, no
DisplayPort Alt Mode is advertised and no SS orientation switching is
needed.
Switch the DWC3 controller from peripheral-only to OTG mode with
usb-role-switch to allow the TCPM framework to control USB host/device
role based on CC pin detection.
Assisted-by: LLM
Signed-off-by: David Heidelberg <david@ixit.cz>
---
.../arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 48 +++++++++++++++++++++-
1 file changed, 46 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi
index 439779f308e38..c71cbd1effe91 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi
@@ -6,16 +6,17 @@
*/
/dts-v1/;
#include <dt-bindings/arm/qcom,ids.h>
#include <dt-bindings/input/linux-event-codes.h>
#include <dt-bindings/leds/common.h>
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <dt-bindings/usb/pd.h>
#include <dt-bindings/sound/qcom,q6afe.h>
#include <dt-bindings/sound/qcom,q6asm.h>
#include "sdm845.dtsi"
#include "sdm845-wcd9340.dtsi"
#include "pm8998.dtsi"
#include "pmi8998.dtsi"
@@ -639,16 +640,53 @@ pinconf {
};
};
};
&pmi8998_charger {
status = "okay";
};
+&pmi8998_typec {
+ status = "okay";
+
+ vdd-pdphy-supply = <&vreg_l24a_3p075>;
+
+ connector {
+ compatible = "usb-c-connector";
+
+ /*
+ * Sink only for now, as the PMI8998 charger doesn't provide
+ * the VBUS output yet. Switch to the dual power role with
+ * source PDOs, try-power-role and vbus-supply once it is
+ * supported.
+ */
+ power-role = "sink";
+ data-role = "dual";
+ self-powered;
+
+ sink-pdos = <PDO_FIXED(5000, 3000,
+ PDO_FIXED_USB_COMM |
+ PDO_FIXED_DATA_SWAP)>;
+ op-sink-microwatt = <15000000>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ pmi8998_hs_in: endpoint {
+ remote-endpoint = <&usb_1_dwc3_hs>;
+ };
+ };
+ };
+ };
+};
+
&pmi8998_flash {
status = "okay";
led-0 {
function = LED_FUNCTION_FLASH;
color = <LED_COLOR_ID_WHITE>;
led-sources = <1>;
led-max-microamp = <500000>;
@@ -929,28 +967,34 @@ &usb_1 {
* disable USB3 clock requirement as the device only supports
* USB2.
*/
qcom,select-utmi-as-pipe-clk;
};
&usb_1_dwc3 {
/*
- * We don't have the capability to switch modes yet.
+ * The USB-C role is managed by the pmi8998 Type-C port controller
+ * via usb-role-switch.
*/
- dr_mode = "peripheral";
+ dr_mode = "otg";
+ usb-role-switch;
/* fastest mode for USB 2 */
maximum-speed = "high-speed";
/* Remove USB3 phy as it's unused on this device. */
phys = <&usb_1_hsphy>;
phy-names = "usb2-phy";
};
+&usb_1_dwc3_hs {
+ remote-endpoint = <&pmi8998_hs_in>;
+};
+
&usb_1_hsphy {
status = "okay";
vdd-supply = <&vdda_usb1_ss_core>;
vdda-pll-supply = <&vdda_qusb_hs0_1p8>;
vdda-phy-dpdm-supply = <&vdda_qusb_hs0_3p1>;
qcom,imp-res-offset-value = <8>;
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 12/12] arm64: dts: qcom: sdm845-shift-axolotl: Enable USB Type-C port controller
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
` (10 preceding siblings ...)
2026-09-26 12:40 ` [PATCH RFC 11/12] arm64: dts: qcom: sdm845-oneplus-common: " David Heidelberg via B4 Relay
@ 2026-09-26 12:40 ` David Heidelberg via B4 Relay
11 siblings, 0 replies; 13+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-09-26 12:40 UTC (permalink / raw)
To: Alexey Minnekhanov, Bryan O'Donoghue, Heikki Krogerus,
Greg Kroah-Hartman, Liam Girdwood, Mark Brown, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, Dmitry Baryshkov, Lee Jones, Stephen Boyd
Cc: linux-arm-msm, linux-usb, linux-kernel, devicetree, phone-devel,
mfd, David Heidelberg
From: David Heidelberg <david@ixit.cz>
Enable the PMI8998 Type-C port controller with a USB-C connector
description for the SHIFT6mq:
- Sink-only power role with a 5V/3A sink PDO
- Dual-role data with USB role switching
The VBUS output of the charger is not supported yet, so the port can't
act as a power source. Describe it as sink-only until VBUS support lands,
USB host mode is still reachable through a PD data role swap. Higher
voltage PDOs are left out until the charger driver programs the allowed
USBIN adapter voltage.
Wire the USB-C connector port graph:
- port@0: DWC3 HS endpoint for USB role switching
- port@1: QMP combo PHY for SS lane orientation
Switch the DWC3 controller from peripheral-only to OTG mode with
usb-role-switch to allow the TCPM framework to control USB host/device
role based on CC pin detection.
DisplayPort Alt Mode is not advertised yet, it will be added together
with enabling the DP controller (mdss_dp).
Assisted-by: LLM
Signed-off-by: David Heidelberg <david@ixit.cz>
---
arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts | 62 ++++++++++++++++++++++-
1 file changed, 61 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts b/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts
index 1b0eaeafbd517..2ddbe732961a2 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts
@@ -6,16 +6,17 @@
*/
/dts-v1/;
#include <dt-bindings/arm/qcom,ids.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <dt-bindings/usb/pd.h>
#include "sdm845.dtsi"
#include "pm8998.dtsi"
#include "pmi8998.dtsi"
/ {
model = "SHIFT SHIFT6mq";
compatible = "shift,axolotl", "qcom,sdm845";
chassis-type = "handset";
@@ -654,16 +655,66 @@ led-1 {
color = <LED_COLOR_ID_YELLOW>;
led-sources = <2>;
led-max-microamp = <100000>;
flash-max-microamp = <1100000>;
flash-max-timeout-us = <1280000>;
};
};
+&pmi8998_typec {
+ status = "okay";
+
+ vdd-pdphy-supply = <&vreg_l24a_3p075>;
+
+ connector {
+ compatible = "usb-c-connector";
+
+ /*
+ * Sink only for now, as the PMI8998 charger doesn't provide
+ * the VBUS output yet. Switch to the dual power role with
+ * source PDOs, try-power-role and vbus-supply once it is
+ * supported.
+ *
+ * Higher voltage sink PDOs will be added once the charger
+ * driver programs the allowed USBIN adapter voltage.
+ *
+ * DisplayPort Alt Mode will be added together with enabling
+ * the DP controller (mdss_dp).
+ */
+ power-role = "sink";
+ data-role = "dual";
+ self-powered;
+
+ sink-pdos = <PDO_FIXED(5000, 3000,
+ PDO_FIXED_USB_COMM |
+ PDO_FIXED_DATA_SWAP)>;
+ op-sink-microwatt = <15000000>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ pmi8998_hs_in: endpoint {
+ remote-endpoint = <&usb_1_dwc3_hs>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ pmi8998_typec_mux_in: endpoint {
+ remote-endpoint = <&usb_1_qmpphy_out>;
+ };
+ };
+ };
+ };
+};
+
&qup_uart9_rx {
drive-strength = <2>;
bias-pull-up;
};
&qup_uart9_tx {
drive-strength = <2>;
bias-disable;
@@ -855,17 +906,22 @@ &ufs_mem_phy {
vdda-pll-supply = <&vdda_ufs1_1p2>;
};
&usb_1 {
status = "okay";
};
&usb_1_dwc3 {
- dr_mode = "peripheral";
+ dr_mode = "otg";
+ usb-role-switch;
+};
+
+&usb_1_dwc3_hs {
+ remote-endpoint = <&pmi8998_hs_in>;
};
&usb_1_hsphy {
status = "okay";
vdd-supply = <&vreg_l1a_0p875>;
vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
vdda-pll-supply = <&vreg_l12a_1p8>;
@@ -873,16 +929,20 @@ &usb_1_hsphy {
&usb_1_qmpphy {
status = "okay";
vdda-phy-supply = <&vreg_l1a_0p875>;
vdda-pll-supply = <&vreg_l26a_1p2>;
};
+&usb_1_qmpphy_out {
+ remote-endpoint = <&pmi8998_typec_mux_in>;
+};
+
&venus {
firmware-name = "qcom/sdm845/SHIFT/axolotl/venus.mbn";
status = "okay";
};
&wifi {
vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>;
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-09-26 12:40 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-26 12:40 [PATCH RFC 00/12] Qualcomm Type-C support for 1st generation David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 01/12] usb: typec: tcpm: qcom: Release the connector fwnode reference David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 02/12] dt-bindings: usb: qcom,pmic-typec: Update example with vbus-supply David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 03/12] dt-bindings: usb: Add Qualcomm 1st-gen PMIC Type-C David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 04/12] usb: typec: qcom: Make PMIC port probe selectable David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 05/12] usb: typec: qcom: Make typec_port accept also different structure David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 06/12] usb: typec: qcom: Add gen1 Type-C port support David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 07/12] arm64: dts: qcom: pm660: Add USB Type-C port controller node David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 08/12] arm64: dts: qcom: pmi8998: " David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 09/12] arm64: dts: qcom: sdm670-google-common: Enable USB Type-C port controller David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 10/12] arm64: dts: qcom: sdm845-google-common: " David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 11/12] arm64: dts: qcom: sdm845-oneplus-common: " David Heidelberg via B4 Relay
2026-09-26 12:40 ` [PATCH RFC 12/12] arm64: dts: qcom: sdm845-shift-axolotl: " David Heidelberg via B4 Relay
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®