Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: typec: qcom: Add Qualcomm PMIC Type-C driver

This commit adds a QCOM PMIC TCPM driver with an initial pm8150b
block.

The driver is layered as follows:

qcom_pmic_typec.c : Responsible for registering with TCPM and arbitrates
access to the Type-C and PDPHY hardware blocks in one
place. This presents a single TCPM device to device to
the Linux TCPM layer.

qcom_pmic_typec_pdphy.c: Responsible for interfacing with the PDPHY hardware and
processing power-delivery related calls from TCPM.
This hardware binding can be extended to
facilitate similar hardware in different PMICs.

qcom_pmic_typec_port.c: Responsible for notifying and processing Type-C
related calls from TCPM. Similar to the pdphy this
layer can be extended to handle the specifics of
different Qualcomm PMIC Type-C port managers.

This code provides all of the same functionality as the existing
qcom typec driver plus power-delivery as well.

As a result commit 6c8cf3695176 ("usb: typec: Add QCOM PMIC typec detection
driver") can be deleted entirely.

References code from Jonathan Marek, Jack Pham, Wesley Cheng, Hemant Kumar,
Guru Das Srinagesh and Ashay Jaiswal.

Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Reviewed-by: Caleb Connolly <caleb.connolly@linaro.org>
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Link: https://lore.kernel.org/r/20230508142308.1656410-8-bryan.odonoghue@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Bryan O'Donoghue and committed by
Greg Kroah-Hartman
a4422ff2 00bb478b

+1772 -275
+10
MAINTAINERS
··· 17533 17533 F: Documentation/devicetree/bindings/thermal/qcom-tsens.yaml 17534 17534 F: drivers/thermal/qcom/ 17535 17535 17536 + QUALCOMM TYPEC PORT MANAGER DRIVER 17537 + M: Bryan O'Donoghue <bryan.odonoghue@linaro.org> 17538 + L: linux-arm-msm@vger.kernel.org 17539 + L: linux-usb@vger.kernel.org 17540 + S: Maintained 17541 + F: Documentation/devicetree/bindings/usb/qcom,pmic-*.yaml 17542 + F: drivers/usb/typec/tcpm/qcom/ 17543 + F: include/dt-bindings/usb/typec/qcom,pmic-pdphy.h 17544 + F: include/dt-bindings/usb/typec/qcom,pmic-typec.h 17545 + 17536 17546 QUALCOMM VENUS VIDEO ACCELERATOR DRIVER 17537 17547 M: Stanimir Varbanov <stanimir.k.varbanov@gmail.com> 17538 17548 M: Vikash Garodia <quic_vgarodia@quicinc.com>
-13
drivers/usb/typec/Kconfig
··· 100 100 If you choose to build this driver as a dynamically linked module, the 101 101 module will be called stusb160x.ko. 102 102 103 - config TYPEC_QCOM_PMIC 104 - tristate "Qualcomm PMIC USB Type-C driver" 105 - depends on ARCH_QCOM || COMPILE_TEST 106 - depends on USB_ROLE_SWITCH || !USB_ROLE_SWITCH 107 - help 108 - Driver for supporting role switch over the Qualcomm PMIC. This will 109 - handle the USB Type-C role and orientation detection reported by the 110 - QCOM PMIC if the PMIC has the capability to handle USB Type-C 111 - detection. 112 - 113 - It will also enable the VBUS output to connected devices when a 114 - DFP connection is made. 115 - 116 103 config TYPEC_WUSB3801 117 104 tristate "Willsemi WUSB3801 Type-C port controller driver" 118 105 depends on I2C
-1
drivers/usb/typec/Makefile
··· 8 8 obj-$(CONFIG_TYPEC_TPS6598X) += tipd/ 9 9 obj-$(CONFIG_TYPEC_ANX7411) += anx7411.o 10 10 obj-$(CONFIG_TYPEC_HD3SS3220) += hd3ss3220.o 11 - obj-$(CONFIG_TYPEC_QCOM_PMIC) += qcom-pmic-typec.o 12 11 obj-$(CONFIG_TYPEC_STUSB160X) += stusb160x.o 13 12 obj-$(CONFIG_TYPEC_RT1719) += rt1719.o 14 13 obj-$(CONFIG_TYPEC_WUSB3801) += wusb3801.o
-261
drivers/usb/typec/qcom-pmic-typec.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Copyright (c) 2020, The Linux Foundation. All rights reserved. 4 - */ 5 - 6 - #include <linux/err.h> 7 - #include <linux/interrupt.h> 8 - #include <linux/kernel.h> 9 - #include <linux/mod_devicetable.h> 10 - #include <linux/module.h> 11 - #include <linux/platform_device.h> 12 - #include <linux/regmap.h> 13 - #include <linux/regulator/consumer.h> 14 - #include <linux/slab.h> 15 - #include <linux/usb/role.h> 16 - #include <linux/usb/typec_mux.h> 17 - 18 - #define TYPEC_MISC_STATUS 0xb 19 - #define CC_ATTACHED BIT(0) 20 - #define CC_ORIENTATION BIT(1) 21 - #define SNK_SRC_MODE BIT(6) 22 - #define TYPEC_MODE_CFG 0x44 23 - #define TYPEC_DISABLE_CMD BIT(0) 24 - #define EN_SNK_ONLY BIT(1) 25 - #define EN_SRC_ONLY BIT(2) 26 - #define TYPEC_VCONN_CONTROL 0x46 27 - #define VCONN_EN_SRC BIT(0) 28 - #define VCONN_EN_VAL BIT(1) 29 - #define TYPEC_EXIT_STATE_CFG 0x50 30 - #define SEL_SRC_UPPER_REF BIT(2) 31 - #define TYPEC_INTR_EN_CFG_1 0x5e 32 - #define TYPEC_INTR_EN_CFG_1_MASK GENMASK(7, 0) 33 - 34 - struct qcom_pmic_typec { 35 - struct device *dev; 36 - struct regmap *regmap; 37 - u32 base; 38 - 39 - struct typec_port *port; 40 - struct usb_role_switch *role_sw; 41 - 42 - struct regulator *vbus_reg; 43 - bool vbus_enabled; 44 - }; 45 - 46 - static void qcom_pmic_typec_enable_vbus_regulator(struct qcom_pmic_typec 47 - *qcom_usb, bool enable) 48 - { 49 - int ret; 50 - 51 - if (enable == qcom_usb->vbus_enabled) 52 - return; 53 - 54 - if (enable) { 55 - ret = regulator_enable(qcom_usb->vbus_reg); 56 - if (ret) 57 - return; 58 - } else { 59 - ret = regulator_disable(qcom_usb->vbus_reg); 60 - if (ret) 61 - return; 62 - } 63 - qcom_usb->vbus_enabled = enable; 64 - } 65 - 66 - static void qcom_pmic_typec_check_connection(struct qcom_pmic_typec *qcom_usb) 67 - { 68 - enum typec_orientation orientation; 69 - enum usb_role role; 70 - unsigned int stat; 71 - bool enable_vbus; 72 - 73 - regmap_read(qcom_usb->regmap, qcom_usb->base + TYPEC_MISC_STATUS, 74 - &stat); 75 - 76 - if (stat & CC_ATTACHED) { 77 - orientation = (stat & CC_ORIENTATION) ? 78 - TYPEC_ORIENTATION_REVERSE : 79 - TYPEC_ORIENTATION_NORMAL; 80 - typec_set_orientation(qcom_usb->port, orientation); 81 - 82 - role = (stat & SNK_SRC_MODE) ? USB_ROLE_HOST : USB_ROLE_DEVICE; 83 - if (role == USB_ROLE_HOST) 84 - enable_vbus = true; 85 - else 86 - enable_vbus = false; 87 - } else { 88 - role = USB_ROLE_NONE; 89 - enable_vbus = false; 90 - } 91 - 92 - qcom_pmic_typec_enable_vbus_regulator(qcom_usb, enable_vbus); 93 - usb_role_switch_set_role(qcom_usb->role_sw, role); 94 - } 95 - 96 - static irqreturn_t qcom_pmic_typec_interrupt(int irq, void *_qcom_usb) 97 - { 98 - struct qcom_pmic_typec *qcom_usb = _qcom_usb; 99 - 100 - qcom_pmic_typec_check_connection(qcom_usb); 101 - return IRQ_HANDLED; 102 - } 103 - 104 - static void qcom_pmic_typec_typec_hw_init(struct qcom_pmic_typec *qcom_usb, 105 - enum typec_port_type type) 106 - { 107 - u8 mode = 0; 108 - 109 - regmap_update_bits(qcom_usb->regmap, 110 - qcom_usb->base + TYPEC_INTR_EN_CFG_1, 111 - TYPEC_INTR_EN_CFG_1_MASK, 0); 112 - 113 - if (type == TYPEC_PORT_SRC) 114 - mode = EN_SRC_ONLY; 115 - else if (type == TYPEC_PORT_SNK) 116 - mode = EN_SNK_ONLY; 117 - 118 - regmap_update_bits(qcom_usb->regmap, qcom_usb->base + TYPEC_MODE_CFG, 119 - EN_SNK_ONLY | EN_SRC_ONLY, mode); 120 - 121 - regmap_update_bits(qcom_usb->regmap, 122 - qcom_usb->base + TYPEC_VCONN_CONTROL, 123 - VCONN_EN_SRC | VCONN_EN_VAL, VCONN_EN_SRC); 124 - regmap_update_bits(qcom_usb->regmap, 125 - qcom_usb->base + TYPEC_EXIT_STATE_CFG, 126 - SEL_SRC_UPPER_REF, SEL_SRC_UPPER_REF); 127 - } 128 - 129 - static int qcom_pmic_typec_probe(struct platform_device *pdev) 130 - { 131 - struct qcom_pmic_typec *qcom_usb; 132 - struct device *dev = &pdev->dev; 133 - struct fwnode_handle *fwnode; 134 - struct typec_capability cap; 135 - const char *buf; 136 - int ret, irq, role; 137 - u32 reg; 138 - 139 - ret = device_property_read_u32(dev, "reg", &reg); 140 - if (ret < 0) { 141 - dev_err(dev, "missing base address\n"); 142 - return ret; 143 - } 144 - 145 - qcom_usb = devm_kzalloc(dev, sizeof(*qcom_usb), GFP_KERNEL); 146 - if (!qcom_usb) 147 - return -ENOMEM; 148 - 149 - qcom_usb->dev = dev; 150 - qcom_usb->base = reg; 151 - 152 - qcom_usb->regmap = dev_get_regmap(dev->parent, NULL); 153 - if (!qcom_usb->regmap) { 154 - dev_err(dev, "Failed to get regmap\n"); 155 - return -EINVAL; 156 - } 157 - 158 - qcom_usb->vbus_reg = devm_regulator_get(qcom_usb->dev, "usb_vbus"); 159 - if (IS_ERR(qcom_usb->vbus_reg)) 160 - return PTR_ERR(qcom_usb->vbus_reg); 161 - 162 - fwnode = device_get_named_child_node(dev, "connector"); 163 - if (!fwnode) 164 - return -EINVAL; 165 - 166 - ret = fwnode_property_read_string(fwnode, "power-role", &buf); 167 - if (!ret) { 168 - role = typec_find_port_power_role(buf); 169 - if (role < 0) 170 - role = TYPEC_PORT_SNK; 171 - } else { 172 - role = TYPEC_PORT_SNK; 173 - } 174 - cap.type = role; 175 - 176 - ret = fwnode_property_read_string(fwnode, "data-role", &buf); 177 - if (!ret) { 178 - role = typec_find_port_data_role(buf); 179 - if (role < 0) 180 - role = TYPEC_PORT_UFP; 181 - } else { 182 - role = TYPEC_PORT_UFP; 183 - } 184 - cap.data = role; 185 - 186 - cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; 187 - cap.fwnode = fwnode; 188 - qcom_usb->port = typec_register_port(dev, &cap); 189 - if (IS_ERR(qcom_usb->port)) { 190 - ret = PTR_ERR(qcom_usb->port); 191 - dev_err(dev, "Failed to register type c port %d\n", ret); 192 - goto err_put_node; 193 - } 194 - fwnode_handle_put(fwnode); 195 - 196 - qcom_usb->role_sw = fwnode_usb_role_switch_get(dev_fwnode(qcom_usb->dev)); 197 - if (IS_ERR(qcom_usb->role_sw)) { 198 - ret = dev_err_probe(dev, PTR_ERR(qcom_usb->role_sw), 199 - "failed to get role switch\n"); 200 - goto err_typec_port; 201 - } 202 - 203 - irq = platform_get_irq(pdev, 0); 204 - if (irq < 0) 205 - goto err_usb_role_sw; 206 - 207 - ret = devm_request_threaded_irq(qcom_usb->dev, irq, NULL, 208 - qcom_pmic_typec_interrupt, IRQF_ONESHOT, 209 - "qcom-pmic-typec", qcom_usb); 210 - if (ret) { 211 - dev_err(&pdev->dev, "Could not request IRQ\n"); 212 - goto err_usb_role_sw; 213 - } 214 - 215 - platform_set_drvdata(pdev, qcom_usb); 216 - qcom_pmic_typec_typec_hw_init(qcom_usb, cap.type); 217 - qcom_pmic_typec_check_connection(qcom_usb); 218 - 219 - return 0; 220 - 221 - err_usb_role_sw: 222 - usb_role_switch_put(qcom_usb->role_sw); 223 - err_typec_port: 224 - typec_unregister_port(qcom_usb->port); 225 - err_put_node: 226 - fwnode_handle_put(fwnode); 227 - 228 - return ret; 229 - } 230 - 231 - static int qcom_pmic_typec_remove(struct platform_device *pdev) 232 - { 233 - struct qcom_pmic_typec *qcom_usb = platform_get_drvdata(pdev); 234 - 235 - usb_role_switch_set_role(qcom_usb->role_sw, USB_ROLE_NONE); 236 - qcom_pmic_typec_enable_vbus_regulator(qcom_usb, 0); 237 - 238 - typec_unregister_port(qcom_usb->port); 239 - usb_role_switch_put(qcom_usb->role_sw); 240 - 241 - return 0; 242 - } 243 - 244 - static const struct of_device_id qcom_pmic_typec_table[] = { 245 - { .compatible = "qcom,pm8150b-usb-typec" }, 246 - { } 247 - }; 248 - MODULE_DEVICE_TABLE(of, qcom_pmic_typec_table); 249 - 250 - static struct platform_driver qcom_pmic_typec = { 251 - .driver = { 252 - .name = "qcom,pmic-typec", 253 - .of_match_table = qcom_pmic_typec_table, 254 - }, 255 - .probe = qcom_pmic_typec_probe, 256 - .remove = qcom_pmic_typec_remove, 257 - }; 258 - module_platform_driver(qcom_pmic_typec); 259 - 260 - MODULE_DESCRIPTION("QCOM PMIC USB type C driver"); 261 - MODULE_LICENSE("GPL v2");
+11
drivers/usb/typec/tcpm/Kconfig
··· 76 76 To compile this driver as module, choose M here: the module will be 77 77 called typec_wcove.ko 78 78 79 + config TYPEC_QCOM_PMIC 80 + tristate "Qualcomm PMIC USB Type-C Port Controller Manager driver" 81 + depends on ARCH_QCOM || COMPILE_TEST 82 + help 83 + A Type-C port and Power Delivery driver which aggregates two 84 + discrete pieces of silicon in the PM8150b PMIC block: the 85 + Type-C port controller and the Power Delivery PHY. 86 + 87 + This driver enables Type-C role switching, orientation, Alternate 88 + mode and Power Delivery support both for VBUS and VCONN. 89 + 79 90 endif # TYPEC_TCPM
+1
drivers/usb/typec/tcpm/Makefile
··· 9 9 obj-$(CONFIG_TYPEC_TCPCI_MT6370) += tcpci_mt6370.o 10 10 obj-$(CONFIG_TYPEC_TCPCI_MAXIM) += tcpci_maxim.o 11 11 tcpci_maxim-y += tcpci_maxim_core.o maxim_contaminant.o 12 + obj-$(CONFIG_TYPEC_QCOM_PMIC) += qcom/
+6
drivers/usb/typec/tcpm/qcom/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + obj-$(CONFIG_TYPEC_QCOM_PMIC) += qcom_pmic_tcpm.o 4 + qcom_pmic_tcpm-y += qcom_pmic_typec.o \ 5 + qcom_pmic_typec_port.o \ 6 + qcom_pmic_typec_pdphy.o
+346
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2023, Linaro Ltd. All rights reserved. 4 + */ 5 + 6 + #include <linux/err.h> 7 + #include <linux/interrupt.h> 8 + #include <linux/kernel.h> 9 + #include <linux/mod_devicetable.h> 10 + #include <linux/module.h> 11 + #include <linux/of_device.h> 12 + #include <linux/of_graph.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/regmap.h> 15 + #include <linux/regulator/consumer.h> 16 + #include <linux/slab.h> 17 + #include <linux/usb/role.h> 18 + #include <linux/usb/tcpm.h> 19 + #include <linux/usb/typec_mux.h> 20 + #include "qcom_pmic_typec_pdphy.h" 21 + #include "qcom_pmic_typec_port.h" 22 + 23 + struct pmic_typec_resources { 24 + struct pmic_typec_pdphy_resources *pdphy_res; 25 + struct pmic_typec_port_resources *port_res; 26 + }; 27 + 28 + struct pmic_typec { 29 + struct device *dev; 30 + struct tcpm_port *tcpm_port; 31 + struct tcpc_dev tcpc; 32 + struct pmic_typec_pdphy *pmic_typec_pdphy; 33 + struct pmic_typec_port *pmic_typec_port; 34 + bool vbus_enabled; 35 + struct mutex lock; /* VBUS state serialization */ 36 + }; 37 + 38 + #define tcpc_to_tcpm(_tcpc_) container_of(_tcpc_, struct pmic_typec, tcpc) 39 + 40 + static int qcom_pmic_typec_get_vbus(struct tcpc_dev *tcpc) 41 + { 42 + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 43 + int ret; 44 + 45 + mutex_lock(&tcpm->lock); 46 + ret = tcpm->vbus_enabled || qcom_pmic_typec_port_get_vbus(tcpm->pmic_typec_port); 47 + mutex_unlock(&tcpm->lock); 48 + 49 + return ret; 50 + } 51 + 52 + static int qcom_pmic_typec_set_vbus(struct tcpc_dev *tcpc, bool on, bool sink) 53 + { 54 + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 55 + int ret = 0; 56 + 57 + mutex_lock(&tcpm->lock); 58 + if (tcpm->vbus_enabled == on) 59 + goto done; 60 + 61 + ret = qcom_pmic_typec_port_set_vbus(tcpm->pmic_typec_port, on); 62 + if (ret) 63 + goto done; 64 + 65 + tcpm->vbus_enabled = on; 66 + tcpm_vbus_change(tcpm->tcpm_port); 67 + 68 + done: 69 + dev_dbg(tcpm->dev, "set_vbus set: %d result %d\n", on, ret); 70 + mutex_unlock(&tcpm->lock); 71 + 72 + return ret; 73 + } 74 + 75 + static int qcom_pmic_typec_set_vconn(struct tcpc_dev *tcpc, bool on) 76 + { 77 + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 78 + 79 + return qcom_pmic_typec_port_set_vconn(tcpm->pmic_typec_port, on); 80 + } 81 + 82 + static int qcom_pmic_typec_get_cc(struct tcpc_dev *tcpc, 83 + enum typec_cc_status *cc1, 84 + enum typec_cc_status *cc2) 85 + { 86 + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 87 + 88 + return qcom_pmic_typec_port_get_cc(tcpm->pmic_typec_port, cc1, cc2); 89 + } 90 + 91 + static int qcom_pmic_typec_set_cc(struct tcpc_dev *tcpc, 92 + enum typec_cc_status cc) 93 + { 94 + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 95 + 96 + return qcom_pmic_typec_port_set_cc(tcpm->pmic_typec_port, cc); 97 + } 98 + 99 + static int qcom_pmic_typec_set_polarity(struct tcpc_dev *tcpc, 100 + enum typec_cc_polarity pol) 101 + { 102 + /* Polarity is set separately by phy-qcom-qmp.c */ 103 + return 0; 104 + } 105 + 106 + static int qcom_pmic_typec_start_toggling(struct tcpc_dev *tcpc, 107 + enum typec_port_type port_type, 108 + enum typec_cc_status cc) 109 + { 110 + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 111 + 112 + return qcom_pmic_typec_port_start_toggling(tcpm->pmic_typec_port, 113 + port_type, cc); 114 + } 115 + 116 + static int qcom_pmic_typec_set_roles(struct tcpc_dev *tcpc, bool attached, 117 + enum typec_role power_role, 118 + enum typec_data_role data_role) 119 + { 120 + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 121 + 122 + return qcom_pmic_typec_pdphy_set_roles(tcpm->pmic_typec_pdphy, 123 + data_role, power_role); 124 + } 125 + 126 + static int qcom_pmic_typec_set_pd_rx(struct tcpc_dev *tcpc, bool on) 127 + { 128 + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 129 + 130 + return qcom_pmic_typec_pdphy_set_pd_rx(tcpm->pmic_typec_pdphy, on); 131 + } 132 + 133 + static int qcom_pmic_typec_pd_transmit(struct tcpc_dev *tcpc, 134 + enum tcpm_transmit_type type, 135 + const struct pd_message *msg, 136 + unsigned int negotiated_rev) 137 + { 138 + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 139 + 140 + return qcom_pmic_typec_pdphy_pd_transmit(tcpm->pmic_typec_pdphy, type, 141 + msg, negotiated_rev); 142 + } 143 + 144 + static int qcom_pmic_typec_init(struct tcpc_dev *tcpc) 145 + { 146 + return 0; 147 + } 148 + 149 + static int qcom_pmic_typec_probe(struct platform_device *pdev) 150 + { 151 + struct pmic_typec *tcpm; 152 + struct device *dev = &pdev->dev; 153 + struct device_node *np = dev->of_node; 154 + const struct pmic_typec_resources *res; 155 + struct regmap *regmap; 156 + u32 base[2]; 157 + int ret; 158 + 159 + res = of_device_get_match_data(dev); 160 + if (!res) 161 + return -ENODEV; 162 + 163 + tcpm = devm_kzalloc(dev, sizeof(*tcpm), GFP_KERNEL); 164 + if (!tcpm) 165 + return -ENOMEM; 166 + 167 + tcpm->dev = dev; 168 + tcpm->tcpc.init = qcom_pmic_typec_init; 169 + tcpm->tcpc.get_vbus = qcom_pmic_typec_get_vbus; 170 + tcpm->tcpc.set_vbus = qcom_pmic_typec_set_vbus; 171 + tcpm->tcpc.set_cc = qcom_pmic_typec_set_cc; 172 + tcpm->tcpc.get_cc = qcom_pmic_typec_get_cc; 173 + tcpm->tcpc.set_polarity = qcom_pmic_typec_set_polarity; 174 + tcpm->tcpc.set_vconn = qcom_pmic_typec_set_vconn; 175 + tcpm->tcpc.start_toggling = qcom_pmic_typec_start_toggling; 176 + tcpm->tcpc.set_pd_rx = qcom_pmic_typec_set_pd_rx; 177 + tcpm->tcpc.set_roles = qcom_pmic_typec_set_roles; 178 + tcpm->tcpc.pd_transmit = qcom_pmic_typec_pd_transmit; 179 + 180 + regmap = dev_get_regmap(dev->parent, NULL); 181 + if (!regmap) { 182 + dev_err(dev, "Failed to get regmap\n"); 183 + return -ENODEV; 184 + } 185 + 186 + ret = of_property_read_u32_array(np, "reg", base, 2); 187 + if (ret) 188 + return ret; 189 + 190 + tcpm->pmic_typec_port = qcom_pmic_typec_port_alloc(dev); 191 + if (IS_ERR(tcpm->pmic_typec_port)) 192 + return PTR_ERR(tcpm->pmic_typec_port); 193 + 194 + tcpm->pmic_typec_pdphy = qcom_pmic_typec_pdphy_alloc(dev); 195 + if (IS_ERR(tcpm->pmic_typec_pdphy)) 196 + return PTR_ERR(tcpm->pmic_typec_pdphy); 197 + 198 + ret = qcom_pmic_typec_port_probe(pdev, tcpm->pmic_typec_port, 199 + res->port_res, regmap, base[0]); 200 + if (ret) 201 + return ret; 202 + 203 + ret = qcom_pmic_typec_pdphy_probe(pdev, tcpm->pmic_typec_pdphy, 204 + res->pdphy_res, regmap, base[1]); 205 + if (ret) 206 + return ret; 207 + 208 + mutex_init(&tcpm->lock); 209 + platform_set_drvdata(pdev, tcpm); 210 + 211 + tcpm->tcpc.fwnode = device_get_named_child_node(tcpm->dev, "connector"); 212 + if (IS_ERR(tcpm->tcpc.fwnode)) 213 + return PTR_ERR(tcpm->tcpc.fwnode); 214 + 215 + tcpm->tcpm_port = tcpm_register_port(tcpm->dev, &tcpm->tcpc); 216 + if (IS_ERR(tcpm->tcpm_port)) { 217 + ret = PTR_ERR(tcpm->tcpm_port); 218 + goto fwnode_remove; 219 + } 220 + 221 + ret = qcom_pmic_typec_port_start(tcpm->pmic_typec_port, 222 + tcpm->tcpm_port); 223 + if (ret) 224 + goto fwnode_remove; 225 + 226 + ret = qcom_pmic_typec_pdphy_start(tcpm->pmic_typec_pdphy, 227 + tcpm->tcpm_port); 228 + if (ret) 229 + goto fwnode_remove; 230 + 231 + return 0; 232 + 233 + fwnode_remove: 234 + fwnode_remove_software_node(tcpm->tcpc.fwnode); 235 + 236 + return ret; 237 + } 238 + 239 + static int qcom_pmic_typec_remove(struct platform_device *pdev) 240 + { 241 + struct pmic_typec *tcpm = platform_get_drvdata(pdev); 242 + 243 + qcom_pmic_typec_pdphy_stop(tcpm->pmic_typec_pdphy); 244 + qcom_pmic_typec_port_stop(tcpm->pmic_typec_port); 245 + tcpm_unregister_port(tcpm->tcpm_port); 246 + fwnode_remove_software_node(tcpm->tcpc.fwnode); 247 + 248 + return 0; 249 + } 250 + 251 + static struct pmic_typec_pdphy_resources pm8150b_pdphy_res = { 252 + .irq_params = { 253 + { 254 + .virq = PMIC_PDPHY_SIG_TX_IRQ, 255 + .irq_name = "sig-tx", 256 + }, 257 + { 258 + .virq = PMIC_PDPHY_SIG_RX_IRQ, 259 + .irq_name = "sig-rx", 260 + }, 261 + { 262 + .virq = PMIC_PDPHY_MSG_TX_IRQ, 263 + .irq_name = "msg-tx", 264 + }, 265 + { 266 + .virq = PMIC_PDPHY_MSG_RX_IRQ, 267 + .irq_name = "msg-rx", 268 + }, 269 + { 270 + .virq = PMIC_PDPHY_MSG_TX_FAIL_IRQ, 271 + .irq_name = "msg-tx-failed", 272 + }, 273 + { 274 + .virq = PMIC_PDPHY_MSG_TX_DISCARD_IRQ, 275 + .irq_name = "msg-tx-discarded", 276 + }, 277 + { 278 + .virq = PMIC_PDPHY_MSG_RX_DISCARD_IRQ, 279 + .irq_name = "msg-rx-discarded", 280 + }, 281 + }, 282 + .nr_irqs = 7, 283 + }; 284 + 285 + static struct pmic_typec_port_resources pm8150b_port_res = { 286 + .irq_params = { 287 + { 288 + .irq_name = "vpd-detect", 289 + .virq = PMIC_TYPEC_VPD_IRQ, 290 + }, 291 + 292 + { 293 + .irq_name = "cc-state-change", 294 + .virq = PMIC_TYPEC_CC_STATE_IRQ, 295 + }, 296 + { 297 + .irq_name = "vconn-oc", 298 + .virq = PMIC_TYPEC_VCONN_OC_IRQ, 299 + }, 300 + 301 + { 302 + .irq_name = "vbus-change", 303 + .virq = PMIC_TYPEC_VBUS_IRQ, 304 + }, 305 + 306 + { 307 + .irq_name = "attach-detach", 308 + .virq = PMIC_TYPEC_ATTACH_DETACH_IRQ, 309 + }, 310 + { 311 + .irq_name = "legacy-cable-detect", 312 + .virq = PMIC_TYPEC_LEGACY_CABLE_IRQ, 313 + }, 314 + 315 + { 316 + .irq_name = "try-snk-src-detect", 317 + .virq = PMIC_TYPEC_TRY_SNK_SRC_IRQ, 318 + }, 319 + }, 320 + .nr_irqs = 7, 321 + }; 322 + 323 + struct pmic_typec_resources pm8150b_typec_res = { 324 + .pdphy_res = &pm8150b_pdphy_res, 325 + .port_res = &pm8150b_port_res, 326 + }; 327 + 328 + static const struct of_device_id qcom_pmic_typec_table[] = { 329 + { .compatible = "qcom,pm8150b-typec", .data = &pm8150b_typec_res }, 330 + { } 331 + }; 332 + MODULE_DEVICE_TABLE(of, qcom_pmic_typec_table); 333 + 334 + static struct platform_driver qcom_pmic_typec_driver = { 335 + .driver = { 336 + .name = "qcom,pmic-typec", 337 + .of_match_table = qcom_pmic_typec_table, 338 + }, 339 + .probe = qcom_pmic_typec_probe, 340 + .remove = qcom_pmic_typec_remove, 341 + }; 342 + 343 + module_platform_driver(qcom_pmic_typec_driver); 344 + 345 + MODULE_DESCRIPTION("QCOM PMIC USB Type-C Port Manager Driver"); 346 + MODULE_LICENSE("GPL");
+528
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2023, Linaro Ltd. All rights reserved. 4 + */ 5 + 6 + #include <linux/err.h> 7 + #include <linux/interrupt.h> 8 + #include <linux/kernel.h> 9 + #include <linux/mod_devicetable.h> 10 + #include <linux/module.h> 11 + #include <linux/of_device.h> 12 + #include <linux/of_irq.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/regmap.h> 15 + #include <linux/regulator/consumer.h> 16 + #include <linux/slab.h> 17 + #include <linux/usb/pd.h> 18 + #include <linux/usb/tcpm.h> 19 + #include "qcom_pmic_typec_pdphy.h" 20 + 21 + struct pmic_typec_pdphy_irq_data { 22 + int virq; 23 + int irq; 24 + struct pmic_typec_pdphy *pmic_typec_pdphy; 25 + }; 26 + 27 + struct pmic_typec_pdphy { 28 + struct device *dev; 29 + struct tcpm_port *tcpm_port; 30 + struct regmap *regmap; 31 + u32 base; 32 + 33 + unsigned int nr_irqs; 34 + struct pmic_typec_pdphy_irq_data *irq_data; 35 + 36 + struct work_struct reset_work; 37 + struct work_struct receive_work; 38 + struct regulator *vdd_pdphy; 39 + spinlock_t lock; /* Register atomicity */ 40 + }; 41 + 42 + static void qcom_pmic_typec_pdphy_reset_on(struct pmic_typec_pdphy *pmic_typec_pdphy) 43 + { 44 + struct device *dev = pmic_typec_pdphy->dev; 45 + int ret; 46 + 47 + /* Terminate TX */ 48 + ret = regmap_write(pmic_typec_pdphy->regmap, 49 + pmic_typec_pdphy->base + USB_PDPHY_TX_CONTROL_REG, 0); 50 + if (ret) 51 + goto err; 52 + 53 + ret = regmap_write(pmic_typec_pdphy->regmap, 54 + pmic_typec_pdphy->base + USB_PDPHY_FRAME_FILTER_REG, 0); 55 + if (ret) 56 + goto err; 57 + 58 + return; 59 + err: 60 + dev_err(dev, "pd_reset_on error\n"); 61 + } 62 + 63 + static void qcom_pmic_typec_pdphy_reset_off(struct pmic_typec_pdphy *pmic_typec_pdphy) 64 + { 65 + struct device *dev = pmic_typec_pdphy->dev; 66 + int ret; 67 + 68 + ret = regmap_write(pmic_typec_pdphy->regmap, 69 + pmic_typec_pdphy->base + USB_PDPHY_FRAME_FILTER_REG, 70 + FRAME_FILTER_EN_SOP | FRAME_FILTER_EN_HARD_RESET); 71 + if (ret) 72 + dev_err(dev, "pd_reset_off error\n"); 73 + } 74 + 75 + static void qcom_pmic_typec_pdphy_sig_reset_work(struct work_struct *work) 76 + { 77 + struct pmic_typec_pdphy *pmic_typec_pdphy = container_of(work, struct pmic_typec_pdphy, 78 + reset_work); 79 + unsigned long flags; 80 + 81 + spin_lock_irqsave(&pmic_typec_pdphy->lock, flags); 82 + 83 + qcom_pmic_typec_pdphy_reset_on(pmic_typec_pdphy); 84 + qcom_pmic_typec_pdphy_reset_off(pmic_typec_pdphy); 85 + 86 + spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags); 87 + 88 + tcpm_pd_hard_reset(pmic_typec_pdphy->tcpm_port); 89 + } 90 + 91 + static int 92 + qcom_pmic_typec_pdphy_clear_tx_control_reg(struct pmic_typec_pdphy *pmic_typec_pdphy) 93 + { 94 + struct device *dev = pmic_typec_pdphy->dev; 95 + unsigned int val; 96 + int ret; 97 + 98 + /* Clear TX control register */ 99 + ret = regmap_write(pmic_typec_pdphy->regmap, 100 + pmic_typec_pdphy->base + USB_PDPHY_TX_CONTROL_REG, 0); 101 + if (ret) 102 + goto done; 103 + 104 + /* Perform readback to ensure sufficient delay for command to latch */ 105 + ret = regmap_read(pmic_typec_pdphy->regmap, 106 + pmic_typec_pdphy->base + USB_PDPHY_TX_CONTROL_REG, &val); 107 + 108 + done: 109 + if (ret) 110 + dev_err(dev, "pd_clear_tx_control_reg: clear tx flag\n"); 111 + 112 + return ret; 113 + } 114 + 115 + static int 116 + qcom_pmic_typec_pdphy_pd_transmit_signal(struct pmic_typec_pdphy *pmic_typec_pdphy, 117 + enum tcpm_transmit_type type, 118 + unsigned int negotiated_rev) 119 + { 120 + struct device *dev = pmic_typec_pdphy->dev; 121 + unsigned int val; 122 + unsigned long flags; 123 + int ret; 124 + 125 + spin_lock_irqsave(&pmic_typec_pdphy->lock, flags); 126 + 127 + /* Clear TX control register */ 128 + ret = qcom_pmic_typec_pdphy_clear_tx_control_reg(pmic_typec_pdphy); 129 + if (ret) 130 + goto done; 131 + 132 + val = TX_CONTROL_SEND_SIGNAL; 133 + if (negotiated_rev == PD_REV30) 134 + val |= TX_CONTROL_RETRY_COUNT(2); 135 + else 136 + val |= TX_CONTROL_RETRY_COUNT(3); 137 + 138 + if (type == TCPC_TX_CABLE_RESET || type == TCPC_TX_HARD_RESET) 139 + val |= TX_CONTROL_FRAME_TYPE(1); 140 + 141 + ret = regmap_write(pmic_typec_pdphy->regmap, 142 + pmic_typec_pdphy->base + USB_PDPHY_TX_CONTROL_REG, val); 143 + 144 + done: 145 + spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags); 146 + 147 + dev_vdbg(dev, "pd_transmit_signal: type %d negotiate_rev %d send %d\n", 148 + type, negotiated_rev, ret); 149 + 150 + return ret; 151 + } 152 + 153 + static int 154 + qcom_pmic_typec_pdphy_pd_transmit_payload(struct pmic_typec_pdphy *pmic_typec_pdphy, 155 + enum tcpm_transmit_type type, 156 + const struct pd_message *msg, 157 + unsigned int negotiated_rev) 158 + { 159 + struct device *dev = pmic_typec_pdphy->dev; 160 + unsigned int val, hdr_len, txbuf_len, txsize_len; 161 + unsigned long flags; 162 + int ret; 163 + 164 + spin_lock_irqsave(&pmic_typec_pdphy->lock, flags); 165 + 166 + ret = regmap_read(pmic_typec_pdphy->regmap, 167 + pmic_typec_pdphy->base + USB_PDPHY_RX_ACKNOWLEDGE_REG, 168 + &val); 169 + if (ret) 170 + goto done; 171 + 172 + if (val) { 173 + dev_err(dev, "pd_transmit_payload: RX message pending\n"); 174 + ret = -EBUSY; 175 + goto done; 176 + } 177 + 178 + /* Clear TX control register */ 179 + ret = qcom_pmic_typec_pdphy_clear_tx_control_reg(pmic_typec_pdphy); 180 + if (ret) 181 + goto done; 182 + 183 + hdr_len = sizeof(msg->header); 184 + txbuf_len = pd_header_cnt_le(msg->header) * 4; 185 + txsize_len = hdr_len + txbuf_len - 1; 186 + 187 + /* Write message header sizeof(u16) to USB_PDPHY_TX_BUFFER_HDR_REG */ 188 + ret = regmap_bulk_write(pmic_typec_pdphy->regmap, 189 + pmic_typec_pdphy->base + USB_PDPHY_TX_BUFFER_HDR_REG, 190 + &msg->header, hdr_len); 191 + if (ret) 192 + goto done; 193 + 194 + /* Write payload to USB_PDPHY_TX_BUFFER_DATA_REG for txbuf_len */ 195 + if (txbuf_len) { 196 + ret = regmap_bulk_write(pmic_typec_pdphy->regmap, 197 + pmic_typec_pdphy->base + USB_PDPHY_TX_BUFFER_DATA_REG, 198 + &msg->payload, txbuf_len); 199 + if (ret) 200 + goto done; 201 + } 202 + 203 + /* Write total length ((header + data) - 1) to USB_PDPHY_TX_SIZE_REG */ 204 + ret = regmap_write(pmic_typec_pdphy->regmap, 205 + pmic_typec_pdphy->base + USB_PDPHY_TX_SIZE_REG, 206 + txsize_len); 207 + if (ret) 208 + goto done; 209 + 210 + /* Clear TX control register */ 211 + ret = qcom_pmic_typec_pdphy_clear_tx_control_reg(pmic_typec_pdphy); 212 + if (ret) 213 + goto done; 214 + 215 + /* Initiate transmit with retry count as indicated by PD revision */ 216 + val = TX_CONTROL_FRAME_TYPE(type) | TX_CONTROL_SEND_MSG; 217 + if (pd_header_rev(msg->header) == PD_REV30) 218 + val |= TX_CONTROL_RETRY_COUNT(2); 219 + else 220 + val |= TX_CONTROL_RETRY_COUNT(3); 221 + 222 + ret = regmap_write(pmic_typec_pdphy->regmap, 223 + pmic_typec_pdphy->base + USB_PDPHY_TX_CONTROL_REG, val); 224 + 225 + done: 226 + spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags); 227 + 228 + if (ret) { 229 + dev_err(dev, "pd_transmit_payload: hdr %*ph data %*ph ret %d\n", 230 + hdr_len, &msg->header, txbuf_len, &msg->payload, ret); 231 + } 232 + 233 + return ret; 234 + } 235 + 236 + int qcom_pmic_typec_pdphy_pd_transmit(struct pmic_typec_pdphy *pmic_typec_pdphy, 237 + enum tcpm_transmit_type type, 238 + const struct pd_message *msg, 239 + unsigned int negotiated_rev) 240 + { 241 + struct device *dev = pmic_typec_pdphy->dev; 242 + int ret; 243 + 244 + if (msg) { 245 + ret = qcom_pmic_typec_pdphy_pd_transmit_payload(pmic_typec_pdphy, 246 + type, msg, 247 + negotiated_rev); 248 + } else { 249 + ret = qcom_pmic_typec_pdphy_pd_transmit_signal(pmic_typec_pdphy, 250 + type, 251 + negotiated_rev); 252 + } 253 + 254 + if (ret) 255 + dev_dbg(dev, "pd_transmit: type %x result %d\n", type, ret); 256 + 257 + return ret; 258 + } 259 + 260 + static void qcom_pmic_typec_pdphy_pd_receive(struct pmic_typec_pdphy *pmic_typec_pdphy) 261 + { 262 + struct device *dev = pmic_typec_pdphy->dev; 263 + struct pd_message msg; 264 + unsigned int size, rx_status; 265 + unsigned long flags; 266 + int ret; 267 + 268 + spin_lock_irqsave(&pmic_typec_pdphy->lock, flags); 269 + 270 + ret = regmap_read(pmic_typec_pdphy->regmap, 271 + pmic_typec_pdphy->base + USB_PDPHY_RX_SIZE_REG, &size); 272 + if (ret) 273 + goto done; 274 + 275 + /* Hardware requires +1 of the real read value to be passed */ 276 + if (size < 1 || size > sizeof(msg.payload) + 1) { 277 + dev_dbg(dev, "pd_receive: invalid size %d\n", size); 278 + goto done; 279 + } 280 + 281 + size += 1; 282 + ret = regmap_read(pmic_typec_pdphy->regmap, 283 + pmic_typec_pdphy->base + USB_PDPHY_RX_STATUS_REG, 284 + &rx_status); 285 + 286 + if (ret) 287 + goto done; 288 + 289 + ret = regmap_bulk_read(pmic_typec_pdphy->regmap, 290 + pmic_typec_pdphy->base + USB_PDPHY_RX_BUFFER_REG, 291 + (u8 *)&msg, size); 292 + if (ret) 293 + goto done; 294 + 295 + /* Return ownership of RX buffer to hardware */ 296 + ret = regmap_write(pmic_typec_pdphy->regmap, 297 + pmic_typec_pdphy->base + USB_PDPHY_RX_ACKNOWLEDGE_REG, 0); 298 + 299 + done: 300 + spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags); 301 + 302 + if (!ret) { 303 + dev_vdbg(dev, "pd_receive: handing %d bytes to tcpm\n", size); 304 + tcpm_pd_receive(pmic_typec_pdphy->tcpm_port, &msg); 305 + } 306 + } 307 + 308 + static irqreturn_t qcom_pmic_typec_pdphy_isr(int irq, void *dev_id) 309 + { 310 + struct pmic_typec_pdphy_irq_data *irq_data = dev_id; 311 + struct pmic_typec_pdphy *pmic_typec_pdphy = irq_data->pmic_typec_pdphy; 312 + struct device *dev = pmic_typec_pdphy->dev; 313 + 314 + switch (irq_data->virq) { 315 + case PMIC_PDPHY_SIG_TX_IRQ: 316 + dev_err(dev, "isr: tx_sig\n"); 317 + break; 318 + case PMIC_PDPHY_SIG_RX_IRQ: 319 + schedule_work(&pmic_typec_pdphy->reset_work); 320 + break; 321 + case PMIC_PDPHY_MSG_TX_IRQ: 322 + tcpm_pd_transmit_complete(pmic_typec_pdphy->tcpm_port, 323 + TCPC_TX_SUCCESS); 324 + break; 325 + case PMIC_PDPHY_MSG_RX_IRQ: 326 + qcom_pmic_typec_pdphy_pd_receive(pmic_typec_pdphy); 327 + break; 328 + case PMIC_PDPHY_MSG_TX_FAIL_IRQ: 329 + tcpm_pd_transmit_complete(pmic_typec_pdphy->tcpm_port, 330 + TCPC_TX_FAILED); 331 + break; 332 + case PMIC_PDPHY_MSG_TX_DISCARD_IRQ: 333 + tcpm_pd_transmit_complete(pmic_typec_pdphy->tcpm_port, 334 + TCPC_TX_DISCARDED); 335 + break; 336 + } 337 + 338 + return IRQ_HANDLED; 339 + } 340 + 341 + int qcom_pmic_typec_pdphy_set_pd_rx(struct pmic_typec_pdphy *pmic_typec_pdphy, bool on) 342 + { 343 + unsigned long flags; 344 + int ret; 345 + 346 + spin_lock_irqsave(&pmic_typec_pdphy->lock, flags); 347 + 348 + ret = regmap_write(pmic_typec_pdphy->regmap, 349 + pmic_typec_pdphy->base + USB_PDPHY_RX_ACKNOWLEDGE_REG, !on); 350 + 351 + spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags); 352 + 353 + dev_dbg(pmic_typec_pdphy->dev, "set_pd_rx: %s\n", on ? "on" : "off"); 354 + 355 + return ret; 356 + } 357 + 358 + int qcom_pmic_typec_pdphy_set_roles(struct pmic_typec_pdphy *pmic_typec_pdphy, 359 + bool data_role_host, bool power_role_src) 360 + { 361 + struct device *dev = pmic_typec_pdphy->dev; 362 + unsigned long flags; 363 + int ret; 364 + 365 + spin_lock_irqsave(&pmic_typec_pdphy->lock, flags); 366 + 367 + ret = regmap_update_bits(pmic_typec_pdphy->regmap, 368 + pmic_typec_pdphy->base + USB_PDPHY_MSG_CONFIG_REG, 369 + MSG_CONFIG_PORT_DATA_ROLE | 370 + MSG_CONFIG_PORT_POWER_ROLE, 371 + data_role_host << 3 | power_role_src << 2); 372 + 373 + spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags); 374 + 375 + dev_dbg(dev, "pdphy_set_roles: data_role_host=%d power_role_src=%d\n", 376 + data_role_host, power_role_src); 377 + 378 + return ret; 379 + } 380 + 381 + static int qcom_pmic_typec_pdphy_enable(struct pmic_typec_pdphy *pmic_typec_pdphy) 382 + { 383 + struct device *dev = pmic_typec_pdphy->dev; 384 + int ret; 385 + 386 + ret = regulator_enable(pmic_typec_pdphy->vdd_pdphy); 387 + if (ret) 388 + return ret; 389 + 390 + /* PD 2.0, DR=TYPEC_DEVICE, PR=TYPEC_SINK */ 391 + ret = regmap_update_bits(pmic_typec_pdphy->regmap, 392 + pmic_typec_pdphy->base + USB_PDPHY_MSG_CONFIG_REG, 393 + MSG_CONFIG_SPEC_REV_MASK, PD_REV20); 394 + if (ret) 395 + goto done; 396 + 397 + ret = regmap_write(pmic_typec_pdphy->regmap, 398 + pmic_typec_pdphy->base + USB_PDPHY_EN_CONTROL_REG, 0); 399 + if (ret) 400 + goto done; 401 + 402 + ret = regmap_write(pmic_typec_pdphy->regmap, 403 + pmic_typec_pdphy->base + USB_PDPHY_EN_CONTROL_REG, 404 + CONTROL_ENABLE); 405 + if (ret) 406 + goto done; 407 + 408 + qcom_pmic_typec_pdphy_reset_off(pmic_typec_pdphy); 409 + done: 410 + if (ret) { 411 + regulator_disable(pmic_typec_pdphy->vdd_pdphy); 412 + dev_err(dev, "pdphy_enable fail %d\n", ret); 413 + } 414 + 415 + return ret; 416 + } 417 + 418 + static int qcom_pmic_typec_pdphy_disable(struct pmic_typec_pdphy *pmic_typec_pdphy) 419 + { 420 + int ret; 421 + 422 + qcom_pmic_typec_pdphy_reset_on(pmic_typec_pdphy); 423 + 424 + ret = regmap_write(pmic_typec_pdphy->regmap, 425 + pmic_typec_pdphy->base + USB_PDPHY_EN_CONTROL_REG, 0); 426 + 427 + regulator_disable(pmic_typec_pdphy->vdd_pdphy); 428 + 429 + return ret; 430 + } 431 + 432 + static int pmic_typec_pdphy_reset(struct pmic_typec_pdphy *pmic_typec_pdphy) 433 + { 434 + int ret; 435 + 436 + ret = qcom_pmic_typec_pdphy_disable(pmic_typec_pdphy); 437 + if (ret) 438 + goto done; 439 + 440 + usleep_range(400, 500); 441 + ret = qcom_pmic_typec_pdphy_enable(pmic_typec_pdphy); 442 + done: 443 + return ret; 444 + } 445 + 446 + int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy, 447 + struct tcpm_port *tcpm_port) 448 + { 449 + int i; 450 + int ret; 451 + 452 + pmic_typec_pdphy->tcpm_port = tcpm_port; 453 + 454 + ret = pmic_typec_pdphy_reset(pmic_typec_pdphy); 455 + if (ret) 456 + return ret; 457 + 458 + for (i = 0; i < pmic_typec_pdphy->nr_irqs; i++) 459 + enable_irq(pmic_typec_pdphy->irq_data[i].irq); 460 + 461 + return 0; 462 + } 463 + 464 + void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy) 465 + { 466 + int i; 467 + 468 + for (i = 0; i < pmic_typec_pdphy->nr_irqs; i++) 469 + disable_irq(pmic_typec_pdphy->irq_data[i].irq); 470 + 471 + qcom_pmic_typec_pdphy_reset_on(pmic_typec_pdphy); 472 + } 473 + 474 + struct pmic_typec_pdphy *qcom_pmic_typec_pdphy_alloc(struct device *dev) 475 + { 476 + return devm_kzalloc(dev, sizeof(struct pmic_typec_pdphy), GFP_KERNEL); 477 + } 478 + 479 + int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev, 480 + struct pmic_typec_pdphy *pmic_typec_pdphy, 481 + struct pmic_typec_pdphy_resources *res, 482 + struct regmap *regmap, 483 + u32 base) 484 + { 485 + struct device *dev = &pdev->dev; 486 + struct pmic_typec_pdphy_irq_data *irq_data; 487 + int i, ret, irq; 488 + 489 + if (!res->nr_irqs || res->nr_irqs > PMIC_PDPHY_MAX_IRQS) 490 + return -EINVAL; 491 + 492 + irq_data = devm_kzalloc(dev, sizeof(*irq_data) * res->nr_irqs, 493 + GFP_KERNEL); 494 + if (!irq_data) 495 + return -ENOMEM; 496 + 497 + pmic_typec_pdphy->vdd_pdphy = devm_regulator_get(dev, "vdd-pdphy"); 498 + if (IS_ERR(pmic_typec_pdphy->vdd_pdphy)) 499 + return PTR_ERR(pmic_typec_pdphy->vdd_pdphy); 500 + 501 + pmic_typec_pdphy->dev = dev; 502 + pmic_typec_pdphy->base = base; 503 + pmic_typec_pdphy->regmap = regmap; 504 + pmic_typec_pdphy->nr_irqs = res->nr_irqs; 505 + pmic_typec_pdphy->irq_data = irq_data; 506 + spin_lock_init(&pmic_typec_pdphy->lock); 507 + INIT_WORK(&pmic_typec_pdphy->reset_work, qcom_pmic_typec_pdphy_sig_reset_work); 508 + 509 + for (i = 0; i < res->nr_irqs; i++, irq_data++) { 510 + irq = platform_get_irq_byname(pdev, res->irq_params[i].irq_name); 511 + if (irq < 0) 512 + return irq; 513 + 514 + irq_data->pmic_typec_pdphy = pmic_typec_pdphy; 515 + irq_data->irq = irq; 516 + irq_data->virq = res->irq_params[i].virq; 517 + 518 + ret = devm_request_threaded_irq(dev, irq, NULL, 519 + qcom_pmic_typec_pdphy_isr, 520 + IRQF_ONESHOT | IRQF_NO_AUTOEN, 521 + res->irq_params[i].irq_name, 522 + irq_data); 523 + if (ret) 524 + return ret; 525 + } 526 + 527 + return 0; 528 + }
+119
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. 4 + * Copyright (c) 2023, Linaro Ltd. All rights reserved. 5 + */ 6 + #ifndef __QCOM_PMIC_PDPHY_H__ 7 + #define __QCOM_PMIC_PDPHY_H__ 8 + 9 + #include <linux/platform_device.h> 10 + #include <linux/regmap.h> 11 + #include <linux/usb/tcpm.h> 12 + 13 + #define USB_PDPHY_MAX_DATA_OBJ_LEN 28 14 + #define USB_PDPHY_MSG_HDR_LEN 2 15 + 16 + /* PD PHY register offsets and bit fields */ 17 + #define USB_PDPHY_MSG_CONFIG_REG 0x40 18 + #define MSG_CONFIG_PORT_DATA_ROLE BIT(3) 19 + #define MSG_CONFIG_PORT_POWER_ROLE BIT(2) 20 + #define MSG_CONFIG_SPEC_REV_MASK (BIT(1) | BIT(0)) 21 + 22 + #define USB_PDPHY_EN_CONTROL_REG 0x46 23 + #define CONTROL_ENABLE BIT(0) 24 + 25 + #define USB_PDPHY_RX_STATUS_REG 0x4A 26 + #define RX_FRAME_TYPE (BIT(0) | BIT(1) | BIT(2)) 27 + 28 + #define USB_PDPHY_FRAME_FILTER_REG 0x4C 29 + #define FRAME_FILTER_EN_HARD_RESET BIT(5) 30 + #define FRAME_FILTER_EN_SOP BIT(0) 31 + 32 + #define USB_PDPHY_TX_SIZE_REG 0x42 33 + #define TX_SIZE_MASK 0xF 34 + 35 + #define USB_PDPHY_TX_CONTROL_REG 0x44 36 + #define TX_CONTROL_RETRY_COUNT(n) (((n) & 0x3) << 5) 37 + #define TX_CONTROL_FRAME_TYPE(n) (((n) & 0x7) << 2) 38 + #define TX_CONTROL_FRAME_TYPE_CABLE_RESET (0x1 << 2) 39 + #define TX_CONTROL_SEND_SIGNAL BIT(1) 40 + #define TX_CONTROL_SEND_MSG BIT(0) 41 + 42 + #define USB_PDPHY_RX_SIZE_REG 0x48 43 + 44 + #define USB_PDPHY_RX_ACKNOWLEDGE_REG 0x4B 45 + #define RX_BUFFER_TOKEN BIT(0) 46 + 47 + #define USB_PDPHY_BIST_MODE_REG 0x4E 48 + #define BIST_MODE_MASK 0xF 49 + #define BIST_ENABLE BIT(7) 50 + #define PD_MSG_BIST 0x3 51 + #define PD_BIST_TEST_DATA_MODE 0x8 52 + 53 + #define USB_PDPHY_TX_BUFFER_HDR_REG 0x60 54 + #define USB_PDPHY_TX_BUFFER_DATA_REG 0x62 55 + 56 + #define USB_PDPHY_RX_BUFFER_REG 0x80 57 + 58 + /* VDD regulator */ 59 + #define VDD_PDPHY_VOL_MIN 2800000 /* uV */ 60 + #define VDD_PDPHY_VOL_MAX 3300000 /* uV */ 61 + #define VDD_PDPHY_HPM_LOAD 3000 /* uA */ 62 + 63 + /* Message Spec Rev field */ 64 + #define PD_MSG_HDR_REV(hdr) (((hdr) >> 6) & 3) 65 + 66 + /* timers */ 67 + #define RECEIVER_RESPONSE_TIME 15 /* tReceiverResponse */ 68 + #define HARD_RESET_COMPLETE_TIME 5 /* tHardResetComplete */ 69 + 70 + /* Interrupt numbers */ 71 + #define PMIC_PDPHY_SIG_TX_IRQ 0x0 72 + #define PMIC_PDPHY_SIG_RX_IRQ 0x1 73 + #define PMIC_PDPHY_MSG_TX_IRQ 0x2 74 + #define PMIC_PDPHY_MSG_RX_IRQ 0x3 75 + #define PMIC_PDPHY_MSG_TX_FAIL_IRQ 0x4 76 + #define PMIC_PDPHY_MSG_TX_DISCARD_IRQ 0x5 77 + #define PMIC_PDPHY_MSG_RX_DISCARD_IRQ 0x6 78 + #define PMIC_PDPHY_FR_SWAP_IRQ 0x7 79 + 80 + /* Resources */ 81 + #define PMIC_PDPHY_MAX_IRQS 0x08 82 + 83 + struct pmic_typec_pdphy_irq_params { 84 + int virq; 85 + char *irq_name; 86 + }; 87 + 88 + struct pmic_typec_pdphy_resources { 89 + unsigned int nr_irqs; 90 + struct pmic_typec_pdphy_irq_params irq_params[PMIC_PDPHY_MAX_IRQS]; 91 + }; 92 + 93 + /* API */ 94 + struct pmic_typec_pdphy; 95 + 96 + struct pmic_typec_pdphy *qcom_pmic_typec_pdphy_alloc(struct device *dev); 97 + 98 + int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev, 99 + struct pmic_typec_pdphy *pmic_typec_pdphy, 100 + struct pmic_typec_pdphy_resources *res, 101 + struct regmap *regmap, 102 + u32 base); 103 + 104 + int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy, 105 + struct tcpm_port *tcpm_port); 106 + 107 + void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy); 108 + 109 + int qcom_pmic_typec_pdphy_set_roles(struct pmic_typec_pdphy *pmic_typec_pdphy, 110 + bool power_role_src, bool data_role_host); 111 + 112 + int qcom_pmic_typec_pdphy_set_pd_rx(struct pmic_typec_pdphy *pmic_typec_pdphy, bool on); 113 + 114 + int qcom_pmic_typec_pdphy_pd_transmit(struct pmic_typec_pdphy *pmic_typec_pdphy, 115 + enum tcpm_transmit_type type, 116 + const struct pd_message *msg, 117 + unsigned int negotiated_rev); 118 + 119 + #endif /* __QCOM_PMIC_TYPEC_PDPHY_H__ */
+556
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2023, Linaro Ltd. All rights reserved. 4 + */ 5 + 6 + #include <linux/delay.h> 7 + #include <linux/err.h> 8 + #include <linux/interrupt.h> 9 + #include <linux/kernel.h> 10 + #include <linux/mod_devicetable.h> 11 + #include <linux/module.h> 12 + #include <linux/of_device.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/regmap.h> 15 + #include <linux/regulator/consumer.h> 16 + #include <linux/slab.h> 17 + #include <linux/usb/tcpm.h> 18 + #include <linux/usb/typec_mux.h> 19 + #include <linux/workqueue.h> 20 + #include "qcom_pmic_typec_port.h" 21 + 22 + struct pmic_typec_port_irq_data { 23 + int virq; 24 + int irq; 25 + struct pmic_typec_port *pmic_typec_port; 26 + }; 27 + 28 + struct pmic_typec_port { 29 + struct device *dev; 30 + struct tcpm_port *tcpm_port; 31 + struct regmap *regmap; 32 + u32 base; 33 + unsigned int nr_irqs; 34 + struct pmic_typec_port_irq_data *irq_data; 35 + 36 + struct regulator *vdd_vbus; 37 + 38 + int cc; 39 + bool debouncing_cc; 40 + struct delayed_work cc_debounce_dwork; 41 + 42 + spinlock_t lock; /* Register atomicity */ 43 + }; 44 + 45 + static const char * const typec_cc_status_name[] = { 46 + [TYPEC_CC_OPEN] = "Open", 47 + [TYPEC_CC_RA] = "Ra", 48 + [TYPEC_CC_RD] = "Rd", 49 + [TYPEC_CC_RP_DEF] = "Rp-def", 50 + [TYPEC_CC_RP_1_5] = "Rp-1.5", 51 + [TYPEC_CC_RP_3_0] = "Rp-3.0", 52 + }; 53 + 54 + static const char *rp_unknown = "unknown"; 55 + 56 + static const char *cc_to_name(enum typec_cc_status cc) 57 + { 58 + if (cc > TYPEC_CC_RP_3_0) 59 + return rp_unknown; 60 + 61 + return typec_cc_status_name[cc]; 62 + } 63 + 64 + static const char * const rp_sel_name[] = { 65 + [TYPEC_SRC_RP_SEL_80UA] = "Rp-def-80uA", 66 + [TYPEC_SRC_RP_SEL_180UA] = "Rp-1.5-180uA", 67 + [TYPEC_SRC_RP_SEL_330UA] = "Rp-3.0-330uA", 68 + }; 69 + 70 + static const char *rp_sel_to_name(int rp_sel) 71 + { 72 + if (rp_sel > TYPEC_SRC_RP_SEL_330UA) 73 + return rp_unknown; 74 + 75 + return rp_sel_name[rp_sel]; 76 + } 77 + 78 + #define misc_to_cc(msic) !!(misc & CC_ORIENTATION) ? "cc1" : "cc2" 79 + #define misc_to_vconn(msic) !!(misc & CC_ORIENTATION) ? "cc2" : "cc1" 80 + 81 + static void qcom_pmic_typec_port_cc_debounce(struct work_struct *work) 82 + { 83 + struct pmic_typec_port *pmic_typec_port = 84 + container_of(work, struct pmic_typec_port, cc_debounce_dwork.work); 85 + unsigned long flags; 86 + 87 + spin_lock_irqsave(&pmic_typec_port->lock, flags); 88 + pmic_typec_port->debouncing_cc = false; 89 + spin_unlock_irqrestore(&pmic_typec_port->lock, flags); 90 + 91 + dev_dbg(pmic_typec_port->dev, "Debounce cc complete\n"); 92 + } 93 + 94 + static irqreturn_t pmic_typec_port_isr(int irq, void *dev_id) 95 + { 96 + struct pmic_typec_port_irq_data *irq_data = dev_id; 97 + struct pmic_typec_port *pmic_typec_port = irq_data->pmic_typec_port; 98 + u32 misc_stat; 99 + bool vbus_change = false; 100 + bool cc_change = false; 101 + unsigned long flags; 102 + int ret; 103 + 104 + spin_lock_irqsave(&pmic_typec_port->lock, flags); 105 + 106 + ret = regmap_read(pmic_typec_port->regmap, 107 + pmic_typec_port->base + TYPEC_MISC_STATUS_REG, 108 + &misc_stat); 109 + if (ret) 110 + goto done; 111 + 112 + switch (irq_data->virq) { 113 + case PMIC_TYPEC_VBUS_IRQ: 114 + vbus_change = true; 115 + break; 116 + case PMIC_TYPEC_CC_STATE_IRQ: 117 + case PMIC_TYPEC_ATTACH_DETACH_IRQ: 118 + if (!pmic_typec_port->debouncing_cc) 119 + cc_change = true; 120 + break; 121 + } 122 + 123 + done: 124 + spin_unlock_irqrestore(&pmic_typec_port->lock, flags); 125 + 126 + if (vbus_change) 127 + tcpm_vbus_change(pmic_typec_port->tcpm_port); 128 + 129 + if (cc_change) 130 + tcpm_cc_change(pmic_typec_port->tcpm_port); 131 + 132 + return IRQ_HANDLED; 133 + } 134 + 135 + int qcom_pmic_typec_port_get_vbus(struct pmic_typec_port *pmic_typec_port) 136 + { 137 + struct device *dev = pmic_typec_port->dev; 138 + unsigned int misc; 139 + int ret; 140 + 141 + ret = regmap_read(pmic_typec_port->regmap, 142 + pmic_typec_port->base + TYPEC_MISC_STATUS_REG, 143 + &misc); 144 + if (ret) 145 + misc = 0; 146 + 147 + dev_dbg(dev, "get_vbus: 0x%08x detect %d\n", misc, !!(misc & TYPEC_VBUS_DETECT)); 148 + 149 + return !!(misc & TYPEC_VBUS_DETECT); 150 + } 151 + 152 + int qcom_pmic_typec_port_set_vbus(struct pmic_typec_port *pmic_typec_port, bool on) 153 + { 154 + u32 sm_stat; 155 + u32 val; 156 + int ret; 157 + 158 + if (on) { 159 + ret = regulator_enable(pmic_typec_port->vdd_vbus); 160 + if (ret) 161 + return ret; 162 + 163 + val = TYPEC_SM_VBUS_VSAFE5V; 164 + } else { 165 + ret = regulator_disable(pmic_typec_port->vdd_vbus); 166 + if (ret) 167 + return ret; 168 + 169 + val = TYPEC_SM_VBUS_VSAFE0V; 170 + } 171 + 172 + /* Poll waiting for transition to required vSafe5V or vSafe0V */ 173 + ret = regmap_read_poll_timeout(pmic_typec_port->regmap, 174 + pmic_typec_port->base + TYPEC_SM_STATUS_REG, 175 + sm_stat, sm_stat & val, 176 + 100, 250000); 177 + if (ret) 178 + dev_warn(pmic_typec_port->dev, "vbus vsafe%dv fail\n", on ? 5 : 0); 179 + 180 + return 0; 181 + } 182 + 183 + int qcom_pmic_typec_port_get_cc(struct pmic_typec_port *pmic_typec_port, 184 + enum typec_cc_status *cc1, 185 + enum typec_cc_status *cc2) 186 + { 187 + struct device *dev = pmic_typec_port->dev; 188 + unsigned int misc, val; 189 + bool attached; 190 + int ret = 0; 191 + 192 + ret = regmap_read(pmic_typec_port->regmap, 193 + pmic_typec_port->base + TYPEC_MISC_STATUS_REG, &misc); 194 + if (ret) 195 + goto done; 196 + 197 + attached = !!(misc & CC_ATTACHED); 198 + 199 + if (pmic_typec_port->debouncing_cc) { 200 + ret = -EBUSY; 201 + goto done; 202 + } 203 + 204 + *cc1 = TYPEC_CC_OPEN; 205 + *cc2 = TYPEC_CC_OPEN; 206 + 207 + if (!attached) 208 + goto done; 209 + 210 + if (misc & SNK_SRC_MODE) { 211 + ret = regmap_read(pmic_typec_port->regmap, 212 + pmic_typec_port->base + TYPEC_SRC_STATUS_REG, 213 + &val); 214 + if (ret) 215 + goto done; 216 + switch (val & DETECTED_SRC_TYPE_MASK) { 217 + case SRC_RD_OPEN: 218 + val = TYPEC_CC_RD; 219 + break; 220 + case SRC_RD_RA_VCONN: 221 + val = TYPEC_CC_RD; 222 + *cc1 = TYPEC_CC_RA; 223 + *cc2 = TYPEC_CC_RA; 224 + break; 225 + default: 226 + dev_warn(dev, "unexpected src status %.2x\n", val); 227 + val = TYPEC_CC_RD; 228 + break; 229 + } 230 + } else { 231 + ret = regmap_read(pmic_typec_port->regmap, 232 + pmic_typec_port->base + TYPEC_SNK_STATUS_REG, 233 + &val); 234 + if (ret) 235 + goto done; 236 + switch (val & DETECTED_SNK_TYPE_MASK) { 237 + case SNK_RP_STD: 238 + val = TYPEC_CC_RP_DEF; 239 + break; 240 + case SNK_RP_1P5: 241 + val = TYPEC_CC_RP_1_5; 242 + break; 243 + case SNK_RP_3P0: 244 + val = TYPEC_CC_RP_3_0; 245 + break; 246 + default: 247 + dev_warn(dev, "unexpected snk status %.2x\n", val); 248 + val = TYPEC_CC_RP_DEF; 249 + break; 250 + } 251 + val = TYPEC_CC_RP_DEF; 252 + } 253 + 254 + if (misc & CC_ORIENTATION) 255 + *cc2 = val; 256 + else 257 + *cc1 = val; 258 + 259 + done: 260 + dev_dbg(dev, "get_cc: misc 0x%08x cc1 0x%08x %s cc2 0x%08x %s attached %d cc=%s\n", 261 + misc, *cc1, cc_to_name(*cc1), *cc2, cc_to_name(*cc2), attached, 262 + misc_to_cc(misc)); 263 + 264 + return ret; 265 + } 266 + 267 + static void qcom_pmic_set_cc_debounce(struct pmic_typec_port *pmic_typec_port) 268 + { 269 + pmic_typec_port->debouncing_cc = true; 270 + schedule_delayed_work(&pmic_typec_port->cc_debounce_dwork, 271 + msecs_to_jiffies(2)); 272 + } 273 + 274 + int qcom_pmic_typec_port_set_cc(struct pmic_typec_port *pmic_typec_port, 275 + enum typec_cc_status cc) 276 + { 277 + struct device *dev = pmic_typec_port->dev; 278 + unsigned int mode, currsrc; 279 + unsigned int misc; 280 + unsigned long flags; 281 + int ret; 282 + 283 + spin_lock_irqsave(&pmic_typec_port->lock, flags); 284 + 285 + ret = regmap_read(pmic_typec_port->regmap, 286 + pmic_typec_port->base + TYPEC_MISC_STATUS_REG, 287 + &misc); 288 + if (ret) 289 + goto done; 290 + 291 + mode = EN_SRC_ONLY; 292 + 293 + switch (cc) { 294 + case TYPEC_CC_OPEN: 295 + currsrc = TYPEC_SRC_RP_SEL_80UA; 296 + break; 297 + case TYPEC_CC_RP_DEF: 298 + currsrc = TYPEC_SRC_RP_SEL_80UA; 299 + break; 300 + case TYPEC_CC_RP_1_5: 301 + currsrc = TYPEC_SRC_RP_SEL_180UA; 302 + break; 303 + case TYPEC_CC_RP_3_0: 304 + currsrc = TYPEC_SRC_RP_SEL_330UA; 305 + break; 306 + case TYPEC_CC_RD: 307 + currsrc = TYPEC_SRC_RP_SEL_80UA; 308 + mode = EN_SNK_ONLY; 309 + break; 310 + default: 311 + dev_warn(dev, "unexpected set_cc %d\n", cc); 312 + ret = -EINVAL; 313 + goto done; 314 + } 315 + 316 + if (mode == EN_SRC_ONLY) { 317 + ret = regmap_write(pmic_typec_port->regmap, 318 + pmic_typec_port->base + TYPEC_CURRSRC_CFG_REG, 319 + currsrc); 320 + if (ret) 321 + goto done; 322 + } 323 + 324 + pmic_typec_port->cc = cc; 325 + qcom_pmic_set_cc_debounce(pmic_typec_port); 326 + ret = 0; 327 + 328 + done: 329 + spin_unlock_irqrestore(&pmic_typec_port->lock, flags); 330 + 331 + dev_dbg(dev, "set_cc: currsrc=%x %s mode %s debounce %d attached %d cc=%s\n", 332 + currsrc, rp_sel_to_name(currsrc), 333 + mode == EN_SRC_ONLY ? "EN_SRC_ONLY" : "EN_SNK_ONLY", 334 + pmic_typec_port->debouncing_cc, !!(misc & CC_ATTACHED), 335 + misc_to_cc(misc)); 336 + 337 + return ret; 338 + } 339 + 340 + int qcom_pmic_typec_port_set_vconn(struct pmic_typec_port *pmic_typec_port, bool on) 341 + { 342 + struct device *dev = pmic_typec_port->dev; 343 + unsigned int orientation, misc, mask, value; 344 + unsigned long flags; 345 + int ret; 346 + 347 + spin_lock_irqsave(&pmic_typec_port->lock, flags); 348 + 349 + ret = regmap_read(pmic_typec_port->regmap, 350 + pmic_typec_port->base + TYPEC_MISC_STATUS_REG, &misc); 351 + if (ret) 352 + goto done; 353 + 354 + /* Set VCONN on the inversion of the active CC channel */ 355 + orientation = (misc & CC_ORIENTATION) ? 0 : VCONN_EN_ORIENTATION; 356 + if (on) { 357 + mask = VCONN_EN_ORIENTATION | VCONN_EN_VALUE; 358 + value = orientation | VCONN_EN_VALUE | VCONN_EN_SRC; 359 + } else { 360 + mask = VCONN_EN_VALUE; 361 + value = 0; 362 + } 363 + 364 + ret = regmap_update_bits(pmic_typec_port->regmap, 365 + pmic_typec_port->base + TYPEC_VCONN_CONTROL_REG, 366 + mask, value); 367 + done: 368 + spin_unlock_irqrestore(&pmic_typec_port->lock, flags); 369 + 370 + dev_dbg(dev, "set_vconn: orientation %d control 0x%08x state %s cc %s vconn %s\n", 371 + orientation, value, on ? "on" : "off", misc_to_vconn(misc), misc_to_cc(misc)); 372 + 373 + return ret; 374 + } 375 + 376 + int qcom_pmic_typec_port_start_toggling(struct pmic_typec_port *pmic_typec_port, 377 + enum typec_port_type port_type, 378 + enum typec_cc_status cc) 379 + { 380 + struct device *dev = pmic_typec_port->dev; 381 + unsigned int misc; 382 + u8 mode = 0; 383 + unsigned long flags; 384 + int ret; 385 + 386 + switch (port_type) { 387 + case TYPEC_PORT_SRC: 388 + mode = EN_SRC_ONLY; 389 + break; 390 + case TYPEC_PORT_SNK: 391 + mode = EN_SNK_ONLY; 392 + break; 393 + case TYPEC_PORT_DRP: 394 + mode = EN_TRY_SNK; 395 + break; 396 + } 397 + 398 + spin_lock_irqsave(&pmic_typec_port->lock, flags); 399 + 400 + ret = regmap_read(pmic_typec_port->regmap, 401 + pmic_typec_port->base + TYPEC_MISC_STATUS_REG, &misc); 402 + if (ret) 403 + goto done; 404 + 405 + dev_dbg(dev, "start_toggling: misc 0x%08x attached %d port_type %d current cc %d new %d\n", 406 + misc, !!(misc & CC_ATTACHED), port_type, pmic_typec_port->cc, cc); 407 + 408 + qcom_pmic_set_cc_debounce(pmic_typec_port); 409 + 410 + /* force it to toggle at least once */ 411 + ret = regmap_write(pmic_typec_port->regmap, 412 + pmic_typec_port->base + TYPEC_MODE_CFG_REG, 413 + TYPEC_DISABLE_CMD); 414 + if (ret) 415 + goto done; 416 + 417 + ret = regmap_write(pmic_typec_port->regmap, 418 + pmic_typec_port->base + TYPEC_MODE_CFG_REG, 419 + mode); 420 + done: 421 + spin_unlock_irqrestore(&pmic_typec_port->lock, flags); 422 + 423 + return ret; 424 + } 425 + 426 + #define TYPEC_INTR_EN_CFG_1_MASK \ 427 + (TYPEC_LEGACY_CABLE_INT_EN | \ 428 + TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN | \ 429 + TYPEC_TRYSOURCE_DETECT_INT_EN | \ 430 + TYPEC_TRYSINK_DETECT_INT_EN | \ 431 + TYPEC_CCOUT_DETACH_INT_EN | \ 432 + TYPEC_CCOUT_ATTACH_INT_EN | \ 433 + TYPEC_VBUS_DEASSERT_INT_EN | \ 434 + TYPEC_VBUS_ASSERT_INT_EN) 435 + 436 + #define TYPEC_INTR_EN_CFG_2_MASK \ 437 + (TYPEC_STATE_MACHINE_CHANGE_INT_EN | TYPEC_VBUS_ERROR_INT_EN | \ 438 + TYPEC_DEBOUNCE_DONE_INT_EN) 439 + 440 + int qcom_pmic_typec_port_start(struct pmic_typec_port *pmic_typec_port, 441 + struct tcpm_port *tcpm_port) 442 + { 443 + int i; 444 + int mask; 445 + int ret; 446 + 447 + /* Configure interrupt sources */ 448 + ret = regmap_write(pmic_typec_port->regmap, 449 + pmic_typec_port->base + TYPEC_INTERRUPT_EN_CFG_1_REG, 450 + TYPEC_INTR_EN_CFG_1_MASK); 451 + if (ret) 452 + goto done; 453 + 454 + ret = regmap_write(pmic_typec_port->regmap, 455 + pmic_typec_port->base + TYPEC_INTERRUPT_EN_CFG_2_REG, 456 + TYPEC_INTR_EN_CFG_2_MASK); 457 + if (ret) 458 + goto done; 459 + 460 + /* start in TRY_SNK mode */ 461 + ret = regmap_write(pmic_typec_port->regmap, 462 + pmic_typec_port->base + TYPEC_MODE_CFG_REG, EN_TRY_SNK); 463 + if (ret) 464 + goto done; 465 + 466 + /* Configure VCONN for software control */ 467 + ret = regmap_update_bits(pmic_typec_port->regmap, 468 + pmic_typec_port->base + TYPEC_VCONN_CONTROL_REG, 469 + VCONN_EN_SRC | VCONN_EN_VALUE, VCONN_EN_SRC); 470 + if (ret) 471 + goto done; 472 + 473 + /* Set CC threshold to 1.6 Volts | tPDdebounce = 10-20ms */ 474 + mask = SEL_SRC_UPPER_REF | USE_TPD_FOR_EXITING_ATTACHSRC; 475 + ret = regmap_update_bits(pmic_typec_port->regmap, 476 + pmic_typec_port->base + TYPEC_EXIT_STATE_CFG_REG, 477 + mask, mask); 478 + if (ret) 479 + goto done; 480 + 481 + pmic_typec_port->tcpm_port = tcpm_port; 482 + 483 + for (i = 0; i < pmic_typec_port->nr_irqs; i++) 484 + enable_irq(pmic_typec_port->irq_data[i].irq); 485 + 486 + done: 487 + return ret; 488 + } 489 + 490 + void qcom_pmic_typec_port_stop(struct pmic_typec_port *pmic_typec_port) 491 + { 492 + int i; 493 + 494 + for (i = 0; i < pmic_typec_port->nr_irqs; i++) 495 + disable_irq(pmic_typec_port->irq_data[i].irq); 496 + } 497 + 498 + struct pmic_typec_port *qcom_pmic_typec_port_alloc(struct device *dev) 499 + { 500 + return devm_kzalloc(dev, sizeof(struct pmic_typec_port), GFP_KERNEL); 501 + } 502 + 503 + int qcom_pmic_typec_port_probe(struct platform_device *pdev, 504 + struct pmic_typec_port *pmic_typec_port, 505 + struct pmic_typec_port_resources *res, 506 + struct regmap *regmap, 507 + u32 base) 508 + { 509 + struct device *dev = &pdev->dev; 510 + struct pmic_typec_port_irq_data *irq_data; 511 + int i, ret, irq; 512 + 513 + if (!res->nr_irqs || res->nr_irqs > PMIC_TYPEC_MAX_IRQS) 514 + return -EINVAL; 515 + 516 + irq_data = devm_kzalloc(dev, sizeof(*irq_data) * res->nr_irqs, 517 + GFP_KERNEL); 518 + if (!irq_data) 519 + return -ENOMEM; 520 + 521 + pmic_typec_port->vdd_vbus = devm_regulator_get(dev, "vdd-vbus"); 522 + if (IS_ERR(pmic_typec_port->vdd_vbus)) 523 + return PTR_ERR(pmic_typec_port->vdd_vbus); 524 + 525 + pmic_typec_port->dev = dev; 526 + pmic_typec_port->base = base; 527 + pmic_typec_port->regmap = regmap; 528 + pmic_typec_port->nr_irqs = res->nr_irqs; 529 + pmic_typec_port->irq_data = irq_data; 530 + spin_lock_init(&pmic_typec_port->lock); 531 + INIT_DELAYED_WORK(&pmic_typec_port->cc_debounce_dwork, 532 + qcom_pmic_typec_port_cc_debounce); 533 + 534 + irq = platform_get_irq(pdev, 0); 535 + if (irq < 0) 536 + return irq; 537 + 538 + for (i = 0; i < res->nr_irqs; i++, irq_data++) { 539 + irq = platform_get_irq_byname(pdev, 540 + res->irq_params[i].irq_name); 541 + if (irq < 0) 542 + return irq; 543 + 544 + irq_data->pmic_typec_port = pmic_typec_port; 545 + irq_data->irq = irq; 546 + irq_data->virq = res->irq_params[i].virq; 547 + ret = devm_request_threaded_irq(dev, irq, NULL, pmic_typec_port_isr, 548 + IRQF_ONESHOT | IRQF_NO_AUTOEN, 549 + res->irq_params[i].irq_name, 550 + irq_data); 551 + if (ret) 552 + return ret; 553 + } 554 + 555 + return 0; 556 + }
+195
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. 4 + * Copyright (c) 2023, Linaro Ltd. All rights reserved. 5 + */ 6 + #ifndef __QCOM_PMIC_TYPEC_H__ 7 + #define __QCOM_PMIC_TYPEC_H__ 8 + 9 + #include <linux/platform_device.h> 10 + #include <linux/usb/tcpm.h> 11 + 12 + #define TYPEC_SNK_STATUS_REG 0x06 13 + #define DETECTED_SNK_TYPE_MASK GENMASK(6, 0) 14 + #define SNK_DAM_MASK GENMASK(6, 4) 15 + #define SNK_DAM_500MA BIT(6) 16 + #define SNK_DAM_1500MA BIT(5) 17 + #define SNK_DAM_3000MA BIT(4) 18 + #define SNK_RP_STD BIT(3) 19 + #define SNK_RP_1P5 BIT(2) 20 + #define SNK_RP_3P0 BIT(1) 21 + #define SNK_RP_SHORT BIT(0) 22 + 23 + #define TYPEC_SRC_STATUS_REG 0x08 24 + #define DETECTED_SRC_TYPE_MASK GENMASK(4, 0) 25 + #define SRC_HIGH_BATT BIT(5) 26 + #define SRC_DEBUG_ACCESS BIT(4) 27 + #define SRC_RD_OPEN BIT(3) 28 + #define SRC_RD_RA_VCONN BIT(2) 29 + #define SRC_RA_OPEN BIT(1) 30 + #define AUDIO_ACCESS_RA_RA BIT(0) 31 + 32 + #define TYPEC_STATE_MACHINE_STATUS_REG 0x09 33 + #define TYPEC_ATTACH_DETACH_STATE BIT(5) 34 + 35 + #define TYPEC_SM_STATUS_REG 0x0A 36 + #define TYPEC_SM_VBUS_VSAFE5V BIT(5) 37 + #define TYPEC_SM_VBUS_VSAFE0V BIT(6) 38 + #define TYPEC_SM_USBIN_LT_LV BIT(7) 39 + 40 + #define TYPEC_MISC_STATUS_REG 0x0B 41 + #define TYPEC_WATER_DETECTION_STATUS BIT(7) 42 + #define SNK_SRC_MODE BIT(6) 43 + #define TYPEC_VBUS_DETECT BIT(5) 44 + #define TYPEC_VBUS_ERROR_STATUS BIT(4) 45 + #define TYPEC_DEBOUNCE_DONE BIT(3) 46 + #define CC_ORIENTATION BIT(1) 47 + #define CC_ATTACHED BIT(0) 48 + 49 + #define LEGACY_CABLE_STATUS_REG 0x0D 50 + #define TYPEC_LEGACY_CABLE_STATUS BIT(1) 51 + #define TYPEC_NONCOMP_LEGACY_CABLE_STATUS BIT(0) 52 + 53 + #define TYPEC_U_USB_STATUS_REG 0x0F 54 + #define U_USB_GROUND_NOVBUS BIT(6) 55 + #define U_USB_GROUND BIT(4) 56 + #define U_USB_FMB1 BIT(3) 57 + #define U_USB_FLOAT1 BIT(2) 58 + #define U_USB_FMB2 BIT(1) 59 + #define U_USB_FLOAT2 BIT(0) 60 + 61 + #define TYPEC_MODE_CFG_REG 0x44 62 + #define TYPEC_TRY_MODE_MASK GENMASK(4, 3) 63 + #define EN_TRY_SNK BIT(4) 64 + #define EN_TRY_SRC BIT(3) 65 + #define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 0) 66 + #define EN_SRC_ONLY BIT(2) 67 + #define EN_SNK_ONLY BIT(1) 68 + #define TYPEC_DISABLE_CMD BIT(0) 69 + 70 + #define TYPEC_VCONN_CONTROL_REG 0x46 71 + #define VCONN_EN_ORIENTATION BIT(2) 72 + #define VCONN_EN_VALUE BIT(1) 73 + #define VCONN_EN_SRC BIT(0) 74 + 75 + #define TYPEC_CCOUT_CONTROL_REG 0x48 76 + #define TYPEC_CCOUT_BUFFER_EN BIT(2) 77 + #define TYPEC_CCOUT_VALUE BIT(1) 78 + #define TYPEC_CCOUT_SRC BIT(0) 79 + 80 + #define DEBUG_ACCESS_SRC_CFG_REG 0x4C 81 + #define EN_UNORIENTED_DEBUG_ACCESS_SRC BIT(0) 82 + 83 + #define TYPE_C_CRUDE_SENSOR_CFG_REG 0x4e 84 + #define EN_SRC_CRUDE_SENSOR BIT(1) 85 + #define EN_SNK_CRUDE_SENSOR BIT(0) 86 + 87 + #define TYPEC_EXIT_STATE_CFG_REG 0x50 88 + #define BYPASS_VSAFE0V_DURING_ROLE_SWAP BIT(3) 89 + #define SEL_SRC_UPPER_REF BIT(2) 90 + #define USE_TPD_FOR_EXITING_ATTACHSRC BIT(1) 91 + #define EXIT_SNK_BASED_ON_CC BIT(0) 92 + 93 + #define TYPEC_CURRSRC_CFG_REG 0x52 94 + #define TYPEC_SRC_RP_SEL_330UA BIT(1) 95 + #define TYPEC_SRC_RP_SEL_180UA BIT(0) 96 + #define TYPEC_SRC_RP_SEL_80UA 0 97 + #define TYPEC_SRC_RP_SEL_MASK GENMASK(1, 0) 98 + 99 + #define TYPEC_INTERRUPT_EN_CFG_1_REG 0x5E 100 + #define TYPEC_LEGACY_CABLE_INT_EN BIT(7) 101 + #define TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN BIT(6) 102 + #define TYPEC_TRYSOURCE_DETECT_INT_EN BIT(5) 103 + #define TYPEC_TRYSINK_DETECT_INT_EN BIT(4) 104 + #define TYPEC_CCOUT_DETACH_INT_EN BIT(3) 105 + #define TYPEC_CCOUT_ATTACH_INT_EN BIT(2) 106 + #define TYPEC_VBUS_DEASSERT_INT_EN BIT(1) 107 + #define TYPEC_VBUS_ASSERT_INT_EN BIT(0) 108 + 109 + #define TYPEC_INTERRUPT_EN_CFG_2_REG 0x60 110 + #define TYPEC_SRC_BATT_HPWR_INT_EN BIT(6) 111 + #define MICRO_USB_STATE_CHANGE_INT_EN BIT(5) 112 + #define TYPEC_STATE_MACHINE_CHANGE_INT_EN BIT(4) 113 + #define TYPEC_DEBUG_ACCESS_DETECT_INT_EN BIT(3) 114 + #define TYPEC_WATER_DETECTION_INT_EN BIT(2) 115 + #define TYPEC_VBUS_ERROR_INT_EN BIT(1) 116 + #define TYPEC_DEBOUNCE_DONE_INT_EN BIT(0) 117 + 118 + #define TYPEC_DEBOUNCE_OPTION_REG 0x62 119 + #define REDUCE_TCCDEBOUNCE_TO_2MS BIT(2) 120 + 121 + #define TYPE_C_SBU_CFG_REG 0x6A 122 + #define SEL_SBU1_ISRC_VAL 0x04 123 + #define SEL_SBU2_ISRC_VAL 0x01 124 + 125 + #define TYPEC_U_USB_CFG_REG 0x70 126 + #define EN_MICRO_USB_FACTORY_MODE BIT(1) 127 + #define EN_MICRO_USB_MODE BIT(0) 128 + 129 + #define TYPEC_PMI632_U_USB_WATER_PROTECTION_CFG_REG 0x72 130 + 131 + #define TYPEC_U_USB_WATER_PROTECTION_CFG_REG 0x73 132 + #define EN_MICRO_USB_WATER_PROTECTION BIT(4) 133 + #define MICRO_USB_DETECTION_ON_TIME_CFG_MASK GENMASK(3, 2) 134 + #define MICRO_USB_DETECTION_PERIOD_CFG_MASK GENMASK(1, 0) 135 + 136 + #define TYPEC_PMI632_MICRO_USB_MODE_REG 0x73 137 + #define MICRO_USB_MODE_ONLY BIT(0) 138 + 139 + /* Interrupt numbers */ 140 + #define PMIC_TYPEC_OR_RID_IRQ 0x0 141 + #define PMIC_TYPEC_VPD_IRQ 0x1 142 + #define PMIC_TYPEC_CC_STATE_IRQ 0x2 143 + #define PMIC_TYPEC_VCONN_OC_IRQ 0x3 144 + #define PMIC_TYPEC_VBUS_IRQ 0x4 145 + #define PMIC_TYPEC_ATTACH_DETACH_IRQ 0x5 146 + #define PMIC_TYPEC_LEGACY_CABLE_IRQ 0x6 147 + #define PMIC_TYPEC_TRY_SNK_SRC_IRQ 0x7 148 + 149 + /* Resources */ 150 + #define PMIC_TYPEC_MAX_IRQS 0x08 151 + 152 + struct pmic_typec_port_irq_params { 153 + int virq; 154 + char *irq_name; 155 + }; 156 + 157 + struct pmic_typec_port_resources { 158 + unsigned int nr_irqs; 159 + struct pmic_typec_port_irq_params irq_params[PMIC_TYPEC_MAX_IRQS]; 160 + }; 161 + 162 + /* API */ 163 + struct pmic_typec; 164 + 165 + struct pmic_typec_port *qcom_pmic_typec_port_alloc(struct device *dev); 166 + 167 + int qcom_pmic_typec_port_probe(struct platform_device *pdev, 168 + struct pmic_typec_port *pmic_typec_port, 169 + struct pmic_typec_port_resources *res, 170 + struct regmap *regmap, 171 + u32 base); 172 + 173 + int qcom_pmic_typec_port_start(struct pmic_typec_port *pmic_typec_port, 174 + struct tcpm_port *tcpm_port); 175 + 176 + void qcom_pmic_typec_port_stop(struct pmic_typec_port *pmic_typec_port); 177 + 178 + int qcom_pmic_typec_port_get_cc(struct pmic_typec_port *pmic_typec_port, 179 + enum typec_cc_status *cc1, 180 + enum typec_cc_status *cc2); 181 + 182 + int qcom_pmic_typec_port_set_cc(struct pmic_typec_port *pmic_typec_port, 183 + enum typec_cc_status cc); 184 + 185 + int qcom_pmic_typec_port_get_vbus(struct pmic_typec_port *pmic_typec_port); 186 + 187 + int qcom_pmic_typec_port_set_vconn(struct pmic_typec_port *pmic_typec_port, bool on); 188 + 189 + int qcom_pmic_typec_port_start_toggling(struct pmic_typec_port *pmic_typec_port, 190 + enum typec_port_type port_type, 191 + enum typec_cc_status cc); 192 + 193 + int qcom_pmic_typec_port_set_vbus(struct pmic_typec_port *pmic_typec_port, bool on); 194 + 195 + #endif /* __QCOM_PMIC_TYPE_C_PORT_H__ */