FILE
ucsi_glink.c
File preview with syntax highlighting.
linux-6.19.14/drivers/usb/typec/ucsi/ucsi_glink.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. 4 * Copyright (c) 2023, Linaro Ltd 5 */ 6#include <linux/auxiliary_bus.h> 7#include <linux/module.h> 8#include <linux/mutex.h> 9#include <linux/of_device.h> 10#include <linux/property.h> 11#include <linux/soc/qcom/pdr.h> 12#include <linux/usb/typec_mux.h> 13#include <linux/gpio/consumer.h> 14#include <linux/soc/qcom/pmic_glink.h> 15#include "ucsi.h" 16 17#define PMIC_GLINK_MAX_PORTS 3 18 19#define UCSI_BUF_V1_SIZE (UCSI_MESSAGE_OUT + (UCSI_MESSAGE_OUT - UCSI_MESSAGE_IN)) 20#define UCSI_BUF_V2_SIZE (UCSIv2_MESSAGE_OUT + (UCSIv2_MESSAGE_OUT - UCSI_MESSAGE_IN)) 21 22#define MSG_TYPE_REQ_RESP 1 23 24#define UC_NOTIFY_RECEIVER_UCSI 0x0 25#define UC_UCSI_READ_BUF_REQ 0x11 26#define UC_UCSI_WRITE_BUF_REQ 0x12 27#define UC_UCSI_USBC_NOTIFY_IND 0x13 28 29struct ucsi_read_buf_req_msg { 30 struct pmic_glink_hdr hdr; 31}; 32 33struct __packed ucsi_read_buf_resp_msg { 34 struct pmic_glink_hdr hdr; 35 union { 36 u8 v2_buf[UCSI_BUF_V2_SIZE]; 37 u8 v1_buf[UCSI_BUF_V1_SIZE]; 38 } buf; 39 u32 ret_code; 40}; 41 42struct __packed ucsi_write_buf_req_msg { 43 struct pmic_glink_hdr hdr; 44 union { 45 u8 v2_buf[UCSI_BUF_V2_SIZE]; 46 u8 v1_buf[UCSI_BUF_V1_SIZE]; 47 } buf; 48 u32 reserved; 49}; 50 51struct __packed ucsi_write_buf_resp_msg { 52 struct pmic_glink_hdr hdr; 53 u32 ret_code; 54}; 55 56struct __packed ucsi_notify_ind_msg { 57 struct pmic_glink_hdr hdr; 58 u32 notification; 59 u32 receiver; 60 u32 reserved; 61}; 62 63struct pmic_glink_ucsi { 64 struct device *dev; 65 66 struct gpio_desc *port_orientation[PMIC_GLINK_MAX_PORTS]; 67 68 struct pmic_glink_client *client; 69 70 struct ucsi *ucsi; 71 struct completion read_ack; 72 struct completion write_ack; 73 struct mutex lock; /* protects concurrent access to PMIC Glink interface */ 74 75 struct work_struct notify_work; 76 struct work_struct register_work; 77 spinlock_t state_lock; 78 bool ucsi_registered; 79 bool pd_running; 80 81 u8 read_buf[UCSI_BUF_V2_SIZE]; 82}; 83 84static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, 85 void *val, size_t val_len) 86{ 87 struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); 88 struct ucsi_read_buf_req_msg req = {}; 89 unsigned long left; 90 int ret; 91 92 req.hdr.owner = PMIC_GLINK_OWNER_USBC; 93 req.hdr.type = MSG_TYPE_REQ_RESP; 94 req.hdr.opcode = UC_UCSI_READ_BUF_REQ; 95 96 mutex_lock(&ucsi->lock); 97 memset(ucsi->read_buf, 0, sizeof(ucsi->read_buf)); 98 reinit_completion(&ucsi->read_ack); 99 100 ret = pmic_glink_send(ucsi->client, &req, sizeof(req)); 101 if (ret < 0) { 102 dev_err(ucsi->dev, "failed to send UCSI read request: %d\n", ret); 103 goto out_unlock; 104 } 105 106 left = wait_for_completion_timeout(&ucsi->read_ack, 5 * HZ); 107 if (!left) { 108 dev_err(ucsi->dev, "timeout waiting for UCSI read response\n"); 109 ret = -ETIMEDOUT; 110 goto out_unlock; 111 } 112 113 memcpy(val, &ucsi->read_buf[offset], val_len); 114 ret = 0; 115 116out_unlock: 117 mutex_unlock(&ucsi->lock); 118 119 return ret; 120} 121 122static int pmic_glink_ucsi_read_version(struct ucsi *ucsi, u16 *version) 123{ 124 return pmic_glink_ucsi_read(ucsi, UCSI_VERSION, version, sizeof(*version)); 125} 126 127static int pmic_glink_ucsi_read_cci(struct ucsi *ucsi, u32 *cci) 128{ 129 return pmic_glink_ucsi_read(ucsi, UCSI_CCI, cci, sizeof(*cci)); 130} 131 132static int pmic_glink_ucsi_read_message_in(struct ucsi *ucsi, void *val, size_t val_len) 133{ 134 return pmic_glink_ucsi_read(ucsi, UCSI_MESSAGE_IN, val, val_len); 135} 136 137static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned int offset, 138 const void *val, size_t val_len) 139{ 140 struct ucsi_write_buf_req_msg req = {}; 141 size_t req_len, buf_len; 142 unsigned long left; 143 int ret; 144 u8 *buf; 145 146 req.hdr.owner = PMIC_GLINK_OWNER_USBC; 147 req.hdr.type = MSG_TYPE_REQ_RESP; 148 req.hdr.opcode = UC_UCSI_WRITE_BUF_REQ; 149 150 if (ucsi->ucsi->version >= UCSI_VERSION_2_0) { 151 buf_len = UCSI_BUF_V2_SIZE; 152 buf = req.buf.v2_buf; 153 } else if (ucsi->ucsi->version) { 154 buf_len = UCSI_BUF_V1_SIZE; 155 buf = req.buf.v1_buf; 156 } else { 157 dev_err(ucsi->dev, "UCSI version unknown\n"); 158 return -EINVAL; 159 } 160 req_len = sizeof(struct pmic_glink_hdr) + buf_len + sizeof(u32); 161 162 if (offset + val_len > buf_len) 163 return -EINVAL; 164 165 memcpy(&buf[offset], val, val_len); 166 167 reinit_completion(&ucsi->write_ack); 168 169 ret = pmic_glink_send(ucsi->client, &req, req_len); 170 if (ret < 0) { 171 dev_err(ucsi->dev, "failed to send UCSI write request: %d\n", ret); 172 return ret; 173 } 174 175 left = wait_for_completion_timeout(&ucsi->write_ack, 5 * HZ); 176 if (!left) { 177 dev_err(ucsi->dev, "timeout waiting for UCSI write response\n"); 178 return -ETIMEDOUT; 179 } 180 181 return 0; 182} 183 184static int pmic_glink_ucsi_async_control(struct ucsi *__ucsi, u64 command) 185{ 186 struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); 187 int ret; 188 189 mutex_lock(&ucsi->lock); 190 ret = pmic_glink_ucsi_locked_write(ucsi, UCSI_CONTROL, &command, sizeof(command)); 191 mutex_unlock(&ucsi->lock); 192 193 return ret; 194} 195 196static void pmic_glink_ucsi_update_connector(struct ucsi_connector *con) 197{ 198 struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(con->ucsi); 199 200 if (con->num > PMIC_GLINK_MAX_PORTS || 201 !ucsi->port_orientation[con->num - 1]) 202 return; 203 204 con->typec_cap.orientation_aware = true; 205} 206 207static void pmic_glink_ucsi_connector_status(struct ucsi_connector *con) 208{ 209 struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(con->ucsi); 210 int orientation; 211 212 if (!UCSI_CONSTAT(con, CONNECTED)) { 213 typec_set_orientation(con->port, TYPEC_ORIENTATION_NONE); 214 return; 215 } 216 217 if (con->num > PMIC_GLINK_MAX_PORTS || 218 !ucsi->port_orientation[con->num - 1]) 219 return; 220 221 orientation = gpiod_get_value(ucsi->port_orientation[con->num - 1]); 222 if (orientation >= 0) { 223 typec_set_orientation(con->port, 224 orientation ? 225 TYPEC_ORIENTATION_REVERSE : 226 TYPEC_ORIENTATION_NORMAL); 227 } 228} 229 230static const struct ucsi_operations pmic_glink_ucsi_ops = { 231 .read_version = pmic_glink_ucsi_read_version, 232 .read_cci = pmic_glink_ucsi_read_cci, 233 .poll_cci = pmic_glink_ucsi_read_cci, 234 .read_message_in = pmic_glink_ucsi_read_message_in, 235 .sync_control = ucsi_sync_control_common, 236 .async_control = pmic_glink_ucsi_async_control, 237 .update_connector = pmic_glink_ucsi_update_connector, 238 .connector_status = pmic_glink_ucsi_connector_status, 239}; 240 241static void pmic_glink_ucsi_read_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) 242{ 243 u32 ret_code, resp_len, buf_len = 0; 244 u8 *buf; 245 246 if (ucsi->ucsi->version) { 247 if (ucsi->ucsi->version >= UCSI_VERSION_2_0) { 248 buf = ((struct ucsi_read_buf_resp_msg *)data)->buf.v2_buf; 249 buf_len = UCSI_BUF_V2_SIZE; 250 } else { 251 buf = ((struct ucsi_read_buf_resp_msg *)data)->buf.v1_buf; 252 buf_len = UCSI_BUF_V1_SIZE; 253 } 254 } else if (!ucsi->ucsi_registered) { 255 /* 256 * If UCSI version is not known yet because device is not registered, choose buffer 257 * size which best fits incoming data 258 */ 259 if (len > sizeof(struct pmic_glink_hdr) + UCSI_BUF_V2_SIZE) { 260 buf = ((struct ucsi_read_buf_resp_msg *)data)->buf.v2_buf; 261 buf_len = UCSI_BUF_V2_SIZE; 262 } else { 263 buf = ((struct ucsi_read_buf_resp_msg *)data)->buf.v1_buf; 264 buf_len = UCSI_BUF_V1_SIZE; 265 } 266 } else { 267 dev_err(ucsi->dev, "Device has been registered but UCSI version is still unknown\n"); 268 return; 269 } 270 271 resp_len = sizeof(struct pmic_glink_hdr) + buf_len + sizeof(u32); 272 273 if (len > resp_len) 274 return; 275 276 /* Ensure that buffer_len leaves space for ret_code to be read back from memory */ 277 if (buf_len > len - sizeof(struct pmic_glink_hdr) - sizeof(u32)) 278 buf_len = len - sizeof(struct pmic_glink_hdr) - sizeof(u32); 279 280 memcpy(&ret_code, buf + buf_len, sizeof(u32)); 281 if (ret_code) 282 return; 283 284 memcpy(ucsi->read_buf, buf, buf_len); 285 complete(&ucsi->read_ack); 286} 287 288static void pmic_glink_ucsi_write_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) 289{ 290 const struct ucsi_write_buf_resp_msg *resp = data; 291 292 if (resp->ret_code) 293 return; 294 295 complete(&ucsi->write_ack); 296} 297 298static void pmic_glink_ucsi_notify(struct work_struct *work) 299{ 300 struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, notify_work); 301 u32 cci; 302 int ret; 303 304 ret = pmic_glink_ucsi_read(ucsi->ucsi, UCSI_CCI, &cci, sizeof(cci)); 305 if (ret) { 306 dev_err(ucsi->dev, "failed to read CCI on notification\n"); 307 return; 308 } 309 310 ucsi_notify_common(ucsi->ucsi, cci); 311} 312 313static void pmic_glink_ucsi_register(struct work_struct *work) 314{ 315 struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); 316 unsigned long flags; 317 bool pd_running; 318 319 spin_lock_irqsave(&ucsi->state_lock, flags); 320 pd_running = ucsi->pd_running; 321 spin_unlock_irqrestore(&ucsi->state_lock, flags); 322 323 if (!ucsi->ucsi_registered && pd_running) { 324 ucsi_register(ucsi->ucsi); 325 ucsi->ucsi_registered = true; 326 } else if (ucsi->ucsi_registered && !pd_running) { 327 ucsi_unregister(ucsi->ucsi); 328 ucsi->ucsi_registered = false; 329 } 330} 331 332static void pmic_glink_ucsi_callback(const void *data, size_t len, void *priv) 333{ 334 struct pmic_glink_ucsi *ucsi = priv; 335 const struct pmic_glink_hdr *hdr = data; 336 337 switch (le32_to_cpu(hdr->opcode)) { 338 case UC_UCSI_READ_BUF_REQ: 339 pmic_glink_ucsi_read_ack(ucsi, data, len); 340 break; 341 case UC_UCSI_WRITE_BUF_REQ: 342 pmic_glink_ucsi_write_ack(ucsi, data, len); 343 break; 344 case UC_UCSI_USBC_NOTIFY_IND: 345 schedule_work(&ucsi->notify_work); 346 break; 347 } 348} 349 350static void pmic_glink_ucsi_pdr_notify(void *priv, int state) 351{ 352 struct pmic_glink_ucsi *ucsi = priv; 353 unsigned long flags; 354 355 spin_lock_irqsave(&ucsi->state_lock, flags); 356 ucsi->pd_running = (state == SERVREG_SERVICE_STATE_UP); 357 spin_unlock_irqrestore(&ucsi->state_lock, flags); 358 schedule_work(&ucsi->register_work); 359} 360 361static void pmic_glink_ucsi_destroy(void *data) 362{ 363 struct pmic_glink_ucsi *ucsi = data; 364 365 /* Protect to make sure we're not in a middle of a transaction from a glink callback */ 366 mutex_lock(&ucsi->lock); 367 ucsi_destroy(ucsi->ucsi); 368 mutex_unlock(&ucsi->lock); 369} 370 371static unsigned long quirk_sc8180x = UCSI_NO_PARTNER_PDOS; 372static unsigned long quirk_sc8280xp = UCSI_NO_PARTNER_PDOS | UCSI_DELAY_DEVICE_PDOS; 373static unsigned long quirk_sm8450 = UCSI_DELAY_DEVICE_PDOS; 374 375static const struct of_device_id pmic_glink_ucsi_of_quirks[] = { 376 { .compatible = "qcom,qcm6490-pmic-glink", .data = &quirk_sc8280xp, }, 377 { .compatible = "qcom,sc8180x-pmic-glink", .data = &quirk_sc8180x, }, 378 { .compatible = "qcom,sc8280xp-pmic-glink", .data = &quirk_sc8280xp, }, 379 { .compatible = "qcom,sm8350-pmic-glink", .data = &quirk_sc8180x, }, 380 { .compatible = "qcom,sm8450-pmic-glink", .data = &quirk_sm8450, }, 381 { .compatible = "qcom,sm8550-pmic-glink", .data = &quirk_sm8450, }, 382 {} 383}; 384 385static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, 386 const struct auxiliary_device_id *id) 387{ 388 struct pmic_glink_ucsi *ucsi; 389 struct device *dev = &adev->dev; 390 const struct of_device_id *match; 391 int ret; 392 393 ucsi = devm_kzalloc(dev, sizeof(*ucsi), GFP_KERNEL); 394 if (!ucsi) 395 return -ENOMEM; 396 397 ucsi->dev = dev; 398 dev_set_drvdata(dev, ucsi); 399 400 INIT_WORK(&ucsi->notify_work, pmic_glink_ucsi_notify); 401 INIT_WORK(&ucsi->register_work, pmic_glink_ucsi_register); 402 init_completion(&ucsi->read_ack); 403 init_completion(&ucsi->write_ack); 404 spin_lock_init(&ucsi->state_lock); 405 mutex_init(&ucsi->lock); 406 407 ucsi->ucsi = ucsi_create(dev, &pmic_glink_ucsi_ops); 408 if (IS_ERR(ucsi->ucsi)) 409 return PTR_ERR(ucsi->ucsi); 410 411 /* Make sure we destroy *after* pmic_glink unregister */ 412 ret = devm_add_action_or_reset(dev, pmic_glink_ucsi_destroy, ucsi); 413 if (ret) 414 return ret; 415 416 match = of_match_device(pmic_glink_ucsi_of_quirks, dev->parent); 417 if (match) 418 ucsi->ucsi->quirks = *(unsigned long *)match->data; 419 420 ucsi_set_drvdata(ucsi->ucsi, ucsi); 421 422 device_for_each_child_node_scoped(dev, fwnode) { 423 struct gpio_desc *desc; 424 u32 port; 425 426 ret = fwnode_property_read_u32(fwnode, "reg", &port); 427 if (ret < 0) { 428 dev_err(dev, "missing reg property of %pOFn\n", fwnode); 429 return ret; 430 } 431 432 if (port >= PMIC_GLINK_MAX_PORTS) { 433 dev_warn(dev, "invalid connector number, ignoring\n"); 434 continue; 435 } 436 437 desc = devm_gpiod_get_index_optional(&adev->dev, "orientation", port, GPIOD_IN); 438 439 /* If GPIO isn't found, continue */ 440 if (!desc) 441 continue; 442 443 if (IS_ERR(desc)) 444 return dev_err_probe(dev, PTR_ERR(desc), 445 "unable to acquire orientation gpio\n"); 446 447 ucsi->port_orientation[port] = desc; 448 } 449 450 ucsi->client = devm_pmic_glink_client_alloc(dev, PMIC_GLINK_OWNER_USBC, 451 pmic_glink_ucsi_callback, 452 pmic_glink_ucsi_pdr_notify, 453 ucsi); 454 if (IS_ERR(ucsi->client)) 455 return PTR_ERR(ucsi->client); 456 457 pmic_glink_client_register(ucsi->client); 458 459 return 0; 460} 461 462static void pmic_glink_ucsi_remove(struct auxiliary_device *adev) 463{ 464 struct pmic_glink_ucsi *ucsi = dev_get_drvdata(&adev->dev); 465 466 /* Unregister first to stop having read & writes */ 467 ucsi_unregister(ucsi->ucsi); 468} 469 470static const struct auxiliary_device_id pmic_glink_ucsi_id_table[] = { 471 { .name = "pmic_glink.ucsi", }, 472 {}, 473}; 474MODULE_DEVICE_TABLE(auxiliary, pmic_glink_ucsi_id_table); 475 476static struct auxiliary_driver pmic_glink_ucsi_driver = { 477 .name = "pmic_glink_ucsi", 478 .probe = pmic_glink_ucsi_probe, 479 .remove = pmic_glink_ucsi_remove, 480 .id_table = pmic_glink_ucsi_id_table, 481}; 482 483module_auxiliary_driver(pmic_glink_ucsi_driver); 484 485MODULE_DESCRIPTION("Qualcomm PMIC GLINK UCSI driver"); 486MODULE_LICENSE("GPL");
~/
Read-only file preview.