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 void 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 249 static struct pmic_typec_pdphy_resources pm8150b_pdphy_res = { 250 .irq_params = { 251 { 252 .virq = PMIC_PDPHY_SIG_TX_IRQ, 253 .irq_name = "sig-tx", 254 }, 255 { 256 .virq = PMIC_PDPHY_SIG_RX_IRQ, 257 .irq_name = "sig-rx", 258 }, 259 { 260 .virq = PMIC_PDPHY_MSG_TX_IRQ, 261 .irq_name = "msg-tx", 262 }, 263 { 264 .virq = PMIC_PDPHY_MSG_RX_IRQ, 265 .irq_name = "msg-rx", 266 }, 267 { 268 .virq = PMIC_PDPHY_MSG_TX_FAIL_IRQ, 269 .irq_name = "msg-tx-failed", 270 }, 271 { 272 .virq = PMIC_PDPHY_MSG_TX_DISCARD_IRQ, 273 .irq_name = "msg-tx-discarded", 274 }, 275 { 276 .virq = PMIC_PDPHY_MSG_RX_DISCARD_IRQ, 277 .irq_name = "msg-rx-discarded", 278 }, 279 }, 280 .nr_irqs = 7, 281 }; 282 283 static struct pmic_typec_port_resources pm8150b_port_res = { 284 .irq_params = { 285 { 286 .irq_name = "vpd-detect", 287 .virq = PMIC_TYPEC_VPD_IRQ, 288 }, 289 290 { 291 .irq_name = "cc-state-change", 292 .virq = PMIC_TYPEC_CC_STATE_IRQ, 293 }, 294 { 295 .irq_name = "vconn-oc", 296 .virq = PMIC_TYPEC_VCONN_OC_IRQ, 297 }, 298 299 { 300 .irq_name = "vbus-change", 301 .virq = PMIC_TYPEC_VBUS_IRQ, 302 }, 303 304 { 305 .irq_name = "attach-detach", 306 .virq = PMIC_TYPEC_ATTACH_DETACH_IRQ, 307 }, 308 { 309 .irq_name = "legacy-cable-detect", 310 .virq = PMIC_TYPEC_LEGACY_CABLE_IRQ, 311 }, 312 313 { 314 .irq_name = "try-snk-src-detect", 315 .virq = PMIC_TYPEC_TRY_SNK_SRC_IRQ, 316 }, 317 }, 318 .nr_irqs = 7, 319 }; 320 321 static struct pmic_typec_resources pm8150b_typec_res = { 322 .pdphy_res = &pm8150b_pdphy_res, 323 .port_res = &pm8150b_port_res, 324 }; 325 326 static const struct of_device_id qcom_pmic_typec_table[] = { 327 { .compatible = "qcom,pm8150b-typec", .data = &pm8150b_typec_res }, 328 { } 329 }; 330 MODULE_DEVICE_TABLE(of, qcom_pmic_typec_table); 331 332 static struct platform_driver qcom_pmic_typec_driver = { 333 .driver = { 334 .name = "qcom,pmic-typec", 335 .of_match_table = qcom_pmic_typec_table, 336 }, 337 .probe = qcom_pmic_typec_probe, 338 .remove_new = qcom_pmic_typec_remove, 339 }; 340 341 module_platform_driver(qcom_pmic_typec_driver); 342 343 MODULE_DESCRIPTION("QCOM PMIC USB Type-C Port Manager Driver"); 344 MODULE_LICENSE("GPL"); 345