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.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 21 #include <drm/drm_bridge.h> 22 23 #include "qcom_pmic_typec_pdphy.h" 24 #include "qcom_pmic_typec_port.h" 25 26 struct pmic_typec_resources { 27 struct pmic_typec_pdphy_resources *pdphy_res; 28 struct pmic_typec_port_resources *port_res; 29 }; 30 31 struct pmic_typec { 32 struct device *dev; 33 struct tcpm_port *tcpm_port; 34 struct tcpc_dev tcpc; 35 struct pmic_typec_pdphy *pmic_typec_pdphy; 36 struct pmic_typec_port *pmic_typec_port; 37 bool vbus_enabled; 38 struct mutex lock; /* VBUS state serialization */ 39 struct drm_bridge bridge; 40 }; 41 42 #define tcpc_to_tcpm(_tcpc_) container_of(_tcpc_, struct pmic_typec, tcpc) 43 44 static int qcom_pmic_typec_get_vbus(struct tcpc_dev *tcpc) 45 { 46 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 47 int ret; 48 49 mutex_lock(&tcpm->lock); 50 ret = tcpm->vbus_enabled || qcom_pmic_typec_port_get_vbus(tcpm->pmic_typec_port); 51 mutex_unlock(&tcpm->lock); 52 53 return ret; 54 } 55 56 static int qcom_pmic_typec_set_vbus(struct tcpc_dev *tcpc, bool on, bool sink) 57 { 58 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 59 int ret = 0; 60 61 mutex_lock(&tcpm->lock); 62 if (tcpm->vbus_enabled == on) 63 goto done; 64 65 ret = qcom_pmic_typec_port_set_vbus(tcpm->pmic_typec_port, on); 66 if (ret) 67 goto done; 68 69 tcpm->vbus_enabled = on; 70 tcpm_vbus_change(tcpm->tcpm_port); 71 72 done: 73 dev_dbg(tcpm->dev, "set_vbus set: %d result %d\n", on, ret); 74 mutex_unlock(&tcpm->lock); 75 76 return ret; 77 } 78 79 static int qcom_pmic_typec_set_vconn(struct tcpc_dev *tcpc, bool on) 80 { 81 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 82 83 return qcom_pmic_typec_port_set_vconn(tcpm->pmic_typec_port, on); 84 } 85 86 static int qcom_pmic_typec_get_cc(struct tcpc_dev *tcpc, 87 enum typec_cc_status *cc1, 88 enum typec_cc_status *cc2) 89 { 90 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 91 92 return qcom_pmic_typec_port_get_cc(tcpm->pmic_typec_port, cc1, cc2); 93 } 94 95 static int qcom_pmic_typec_set_cc(struct tcpc_dev *tcpc, 96 enum typec_cc_status cc) 97 { 98 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 99 100 return qcom_pmic_typec_port_set_cc(tcpm->pmic_typec_port, cc); 101 } 102 103 static int qcom_pmic_typec_set_polarity(struct tcpc_dev *tcpc, 104 enum typec_cc_polarity pol) 105 { 106 /* Polarity is set separately by phy-qcom-qmp.c */ 107 return 0; 108 } 109 110 static int qcom_pmic_typec_start_toggling(struct tcpc_dev *tcpc, 111 enum typec_port_type port_type, 112 enum typec_cc_status cc) 113 { 114 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 115 116 return qcom_pmic_typec_port_start_toggling(tcpm->pmic_typec_port, 117 port_type, cc); 118 } 119 120 static int qcom_pmic_typec_set_roles(struct tcpc_dev *tcpc, bool attached, 121 enum typec_role power_role, 122 enum typec_data_role data_role) 123 { 124 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 125 126 return qcom_pmic_typec_pdphy_set_roles(tcpm->pmic_typec_pdphy, 127 data_role, power_role); 128 } 129 130 static int qcom_pmic_typec_set_pd_rx(struct tcpc_dev *tcpc, bool on) 131 { 132 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 133 134 return qcom_pmic_typec_pdphy_set_pd_rx(tcpm->pmic_typec_pdphy, on); 135 } 136 137 static int qcom_pmic_typec_pd_transmit(struct tcpc_dev *tcpc, 138 enum tcpm_transmit_type type, 139 const struct pd_message *msg, 140 unsigned int negotiated_rev) 141 { 142 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); 143 144 return qcom_pmic_typec_pdphy_pd_transmit(tcpm->pmic_typec_pdphy, type, 145 msg, negotiated_rev); 146 } 147 148 static int qcom_pmic_typec_init(struct tcpc_dev *tcpc) 149 { 150 return 0; 151 } 152 153 #if IS_ENABLED(CONFIG_DRM) 154 static int qcom_pmic_typec_attach(struct drm_bridge *bridge, 155 enum drm_bridge_attach_flags flags) 156 { 157 return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL; 158 } 159 160 static const struct drm_bridge_funcs qcom_pmic_typec_bridge_funcs = { 161 .attach = qcom_pmic_typec_attach, 162 }; 163 164 static int qcom_pmic_typec_init_drm(struct pmic_typec *tcpm) 165 { 166 tcpm->bridge.funcs = &qcom_pmic_typec_bridge_funcs; 167 #ifdef CONFIG_OF 168 tcpm->bridge.of_node = of_get_child_by_name(tcpm->dev->of_node, "connector"); 169 #endif 170 tcpm->bridge.ops = DRM_BRIDGE_OP_HPD; 171 tcpm->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; 172 173 return devm_drm_bridge_add(tcpm->dev, &tcpm->bridge); 174 } 175 #else 176 static int qcom_pmic_typec_init_drm(struct pmic_typec *tcpm) 177 { 178 return 0; 179 } 180 #endif 181 182 static int qcom_pmic_typec_probe(struct platform_device *pdev) 183 { 184 struct pmic_typec *tcpm; 185 struct device *dev = &pdev->dev; 186 struct device_node *np = dev->of_node; 187 const struct pmic_typec_resources *res; 188 struct regmap *regmap; 189 u32 base[2]; 190 int ret; 191 192 res = of_device_get_match_data(dev); 193 if (!res) 194 return -ENODEV; 195 196 tcpm = devm_kzalloc(dev, sizeof(*tcpm), GFP_KERNEL); 197 if (!tcpm) 198 return -ENOMEM; 199 200 tcpm->dev = dev; 201 tcpm->tcpc.init = qcom_pmic_typec_init; 202 tcpm->tcpc.get_vbus = qcom_pmic_typec_get_vbus; 203 tcpm->tcpc.set_vbus = qcom_pmic_typec_set_vbus; 204 tcpm->tcpc.set_cc = qcom_pmic_typec_set_cc; 205 tcpm->tcpc.get_cc = qcom_pmic_typec_get_cc; 206 tcpm->tcpc.set_polarity = qcom_pmic_typec_set_polarity; 207 tcpm->tcpc.set_vconn = qcom_pmic_typec_set_vconn; 208 tcpm->tcpc.start_toggling = qcom_pmic_typec_start_toggling; 209 tcpm->tcpc.set_pd_rx = qcom_pmic_typec_set_pd_rx; 210 tcpm->tcpc.set_roles = qcom_pmic_typec_set_roles; 211 tcpm->tcpc.pd_transmit = qcom_pmic_typec_pd_transmit; 212 213 regmap = dev_get_regmap(dev->parent, NULL); 214 if (!regmap) { 215 dev_err(dev, "Failed to get regmap\n"); 216 return -ENODEV; 217 } 218 219 ret = of_property_read_u32_array(np, "reg", base, 2); 220 if (ret) 221 return ret; 222 223 tcpm->pmic_typec_port = qcom_pmic_typec_port_alloc(dev); 224 if (IS_ERR(tcpm->pmic_typec_port)) 225 return PTR_ERR(tcpm->pmic_typec_port); 226 227 tcpm->pmic_typec_pdphy = qcom_pmic_typec_pdphy_alloc(dev); 228 if (IS_ERR(tcpm->pmic_typec_pdphy)) 229 return PTR_ERR(tcpm->pmic_typec_pdphy); 230 231 ret = qcom_pmic_typec_port_probe(pdev, tcpm->pmic_typec_port, 232 res->port_res, regmap, base[0]); 233 if (ret) 234 return ret; 235 236 ret = qcom_pmic_typec_pdphy_probe(pdev, tcpm->pmic_typec_pdphy, 237 res->pdphy_res, regmap, base[1]); 238 if (ret) 239 return ret; 240 241 mutex_init(&tcpm->lock); 242 platform_set_drvdata(pdev, tcpm); 243 244 ret = qcom_pmic_typec_init_drm(tcpm); 245 if (ret) 246 return ret; 247 248 tcpm->tcpc.fwnode = device_get_named_child_node(tcpm->dev, "connector"); 249 if (!tcpm->tcpc.fwnode) 250 return -EINVAL; 251 252 tcpm->tcpm_port = tcpm_register_port(tcpm->dev, &tcpm->tcpc); 253 if (IS_ERR(tcpm->tcpm_port)) { 254 ret = PTR_ERR(tcpm->tcpm_port); 255 goto fwnode_remove; 256 } 257 258 ret = qcom_pmic_typec_port_start(tcpm->pmic_typec_port, 259 tcpm->tcpm_port); 260 if (ret) 261 goto fwnode_remove; 262 263 ret = qcom_pmic_typec_pdphy_start(tcpm->pmic_typec_pdphy, 264 tcpm->tcpm_port); 265 if (ret) 266 goto fwnode_remove; 267 268 return 0; 269 270 fwnode_remove: 271 fwnode_remove_software_node(tcpm->tcpc.fwnode); 272 273 return ret; 274 } 275 276 static void qcom_pmic_typec_remove(struct platform_device *pdev) 277 { 278 struct pmic_typec *tcpm = platform_get_drvdata(pdev); 279 280 qcom_pmic_typec_pdphy_stop(tcpm->pmic_typec_pdphy); 281 qcom_pmic_typec_port_stop(tcpm->pmic_typec_port); 282 tcpm_unregister_port(tcpm->tcpm_port); 283 fwnode_remove_software_node(tcpm->tcpc.fwnode); 284 } 285 286 static struct pmic_typec_pdphy_resources pm8150b_pdphy_res = { 287 .irq_params = { 288 { 289 .virq = PMIC_PDPHY_SIG_TX_IRQ, 290 .irq_name = "sig-tx", 291 }, 292 { 293 .virq = PMIC_PDPHY_SIG_RX_IRQ, 294 .irq_name = "sig-rx", 295 }, 296 { 297 .virq = PMIC_PDPHY_MSG_TX_IRQ, 298 .irq_name = "msg-tx", 299 }, 300 { 301 .virq = PMIC_PDPHY_MSG_RX_IRQ, 302 .irq_name = "msg-rx", 303 }, 304 { 305 .virq = PMIC_PDPHY_MSG_TX_FAIL_IRQ, 306 .irq_name = "msg-tx-failed", 307 }, 308 { 309 .virq = PMIC_PDPHY_MSG_TX_DISCARD_IRQ, 310 .irq_name = "msg-tx-discarded", 311 }, 312 { 313 .virq = PMIC_PDPHY_MSG_RX_DISCARD_IRQ, 314 .irq_name = "msg-rx-discarded", 315 }, 316 }, 317 .nr_irqs = 7, 318 }; 319 320 static struct pmic_typec_port_resources pm8150b_port_res = { 321 .irq_params = { 322 { 323 .irq_name = "vpd-detect", 324 .virq = PMIC_TYPEC_VPD_IRQ, 325 }, 326 327 { 328 .irq_name = "cc-state-change", 329 .virq = PMIC_TYPEC_CC_STATE_IRQ, 330 }, 331 { 332 .irq_name = "vconn-oc", 333 .virq = PMIC_TYPEC_VCONN_OC_IRQ, 334 }, 335 336 { 337 .irq_name = "vbus-change", 338 .virq = PMIC_TYPEC_VBUS_IRQ, 339 }, 340 341 { 342 .irq_name = "attach-detach", 343 .virq = PMIC_TYPEC_ATTACH_DETACH_IRQ, 344 }, 345 { 346 .irq_name = "legacy-cable-detect", 347 .virq = PMIC_TYPEC_LEGACY_CABLE_IRQ, 348 }, 349 350 { 351 .irq_name = "try-snk-src-detect", 352 .virq = PMIC_TYPEC_TRY_SNK_SRC_IRQ, 353 }, 354 }, 355 .nr_irqs = 7, 356 }; 357 358 static struct pmic_typec_resources pm8150b_typec_res = { 359 .pdphy_res = &pm8150b_pdphy_res, 360 .port_res = &pm8150b_port_res, 361 }; 362 363 static const struct of_device_id qcom_pmic_typec_table[] = { 364 { .compatible = "qcom,pm8150b-typec", .data = &pm8150b_typec_res }, 365 { } 366 }; 367 MODULE_DEVICE_TABLE(of, qcom_pmic_typec_table); 368 369 static struct platform_driver qcom_pmic_typec_driver = { 370 .driver = { 371 .name = "qcom,pmic-typec", 372 .of_match_table = qcom_pmic_typec_table, 373 }, 374 .probe = qcom_pmic_typec_probe, 375 .remove_new = qcom_pmic_typec_remove, 376 }; 377 378 module_platform_driver(qcom_pmic_typec_driver); 379 380 MODULE_DESCRIPTION("QCOM PMIC USB Type-C Port Manager Driver"); 381 MODULE_LICENSE("GPL"); 382