1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * USB Type-C Multiplexer/DeMultiplexer Switch support 4 * 5 * Copyright (C) 2018 Intel Corporation 6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> 7 * Hans de Goede <hdegoede@redhat.com> 8 */ 9 10 #include <linux/device.h> 11 #include <linux/list.h> 12 #include <linux/module.h> 13 #include <linux/mutex.h> 14 #include <linux/property.h> 15 #include <linux/slab.h> 16 17 #include "class.h" 18 #include "mux.h" 19 20 #define TYPEC_MUX_MAX_DEVS 3 21 22 struct typec_switch { 23 struct typec_switch_dev *sw_devs[TYPEC_MUX_MAX_DEVS]; 24 unsigned int num_sw_devs; 25 }; 26 27 static int switch_fwnode_match(struct device *dev, const void *fwnode) 28 { 29 if (!is_typec_switch_dev(dev)) 30 return 0; 31 32 return device_match_fwnode(dev, fwnode); 33 } 34 35 static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id, 36 void *data) 37 { 38 struct device *dev; 39 40 /* 41 * Device graph (OF graph) does not give any means to identify the 42 * device type or the device class of the remote port parent that @fwnode 43 * represents, so in order to identify the type or the class of @fwnode 44 * an additional device property is needed. With typec switches the 45 * property is named "orientation-switch" (@id). The value of the device 46 * property is ignored. 47 */ 48 if (id && !fwnode_property_present(fwnode, id)) 49 return NULL; 50 51 /* 52 * At this point we are sure that @fwnode is a typec switch in all 53 * cases. If the switch hasn't yet been registered for some reason, the 54 * function "defers probe" for now. 55 */ 56 dev = class_find_device(&typec_mux_class, NULL, fwnode, 57 switch_fwnode_match); 58 59 return dev ? to_typec_switch_dev(dev) : ERR_PTR(-EPROBE_DEFER); 60 } 61 62 /** 63 * fwnode_typec_switch_get - Find USB Type-C orientation switch 64 * @fwnode: The caller device node 65 * 66 * Finds a switch linked with @dev. Returns a reference to the switch on 67 * success, NULL if no matching connection was found, or 68 * ERR_PTR(-EPROBE_DEFER) when a connection was found but the switch 69 * has not been enumerated yet. 70 */ 71 struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode) 72 { 73 struct typec_switch_dev *sw_devs[TYPEC_MUX_MAX_DEVS]; 74 struct typec_switch *sw; 75 int count; 76 int err; 77 int i; 78 79 sw = kzalloc(sizeof(*sw), GFP_KERNEL); 80 if (!sw) 81 return ERR_PTR(-ENOMEM); 82 83 count = fwnode_connection_find_matches(fwnode, "orientation-switch", NULL, 84 typec_switch_match, 85 (void **)sw_devs, 86 ARRAY_SIZE(sw_devs)); 87 if (count <= 0) { 88 kfree(sw); 89 return NULL; 90 } 91 92 for (i = 0; i < count; i++) { 93 if (IS_ERR(sw_devs[i])) { 94 err = PTR_ERR(sw_devs[i]); 95 goto put_sw_devs; 96 } 97 } 98 99 for (i = 0; i < count; i++) { 100 WARN_ON(!try_module_get(sw_devs[i]->dev.parent->driver->owner)); 101 sw->sw_devs[i] = sw_devs[i]; 102 } 103 104 sw->num_sw_devs = count; 105 106 return sw; 107 108 put_sw_devs: 109 for (i = 0; i < count; i++) { 110 if (!IS_ERR(sw_devs[i])) 111 put_device(&sw_devs[i]->dev); 112 } 113 114 kfree(sw); 115 116 return ERR_PTR(err); 117 } 118 EXPORT_SYMBOL_GPL(fwnode_typec_switch_get); 119 120 /** 121 * typec_switch_put - Release USB Type-C orientation switch 122 * @sw: USB Type-C orientation switch 123 * 124 * Decrement reference count for @sw. 125 */ 126 void typec_switch_put(struct typec_switch *sw) 127 { 128 struct typec_switch_dev *sw_dev; 129 unsigned int i; 130 131 if (IS_ERR_OR_NULL(sw)) 132 return; 133 134 for (i = 0; i < sw->num_sw_devs; i++) { 135 sw_dev = sw->sw_devs[i]; 136 137 module_put(sw_dev->dev.parent->driver->owner); 138 put_device(&sw_dev->dev); 139 } 140 kfree(sw); 141 } 142 EXPORT_SYMBOL_GPL(typec_switch_put); 143 144 static void typec_switch_release(struct device *dev) 145 { 146 kfree(to_typec_switch_dev(dev)); 147 } 148 149 const struct device_type typec_switch_dev_type = { 150 .name = "orientation_switch", 151 .release = typec_switch_release, 152 }; 153 154 /** 155 * typec_switch_register - Register USB Type-C orientation switch 156 * @parent: Parent device 157 * @desc: Orientation switch description 158 * 159 * This function registers a switch that can be used for routing the correct 160 * data pairs depending on the cable plug orientation from the USB Type-C 161 * connector to the USB controllers. USB Type-C plugs can be inserted 162 * right-side-up or upside-down. 163 */ 164 struct typec_switch_dev * 165 typec_switch_register(struct device *parent, 166 const struct typec_switch_desc *desc) 167 { 168 struct typec_switch_dev *sw_dev; 169 int ret; 170 171 if (!desc || !desc->set) 172 return ERR_PTR(-EINVAL); 173 174 sw_dev = kzalloc(sizeof(*sw_dev), GFP_KERNEL); 175 if (!sw_dev) 176 return ERR_PTR(-ENOMEM); 177 178 sw_dev->set = desc->set; 179 180 device_initialize(&sw_dev->dev); 181 sw_dev->dev.parent = parent; 182 sw_dev->dev.fwnode = desc->fwnode; 183 sw_dev->dev.class = &typec_mux_class; 184 sw_dev->dev.type = &typec_switch_dev_type; 185 sw_dev->dev.driver_data = desc->drvdata; 186 ret = dev_set_name(&sw_dev->dev, "%s-switch", desc->name ? desc->name : dev_name(parent)); 187 if (ret) { 188 put_device(&sw_dev->dev); 189 return ERR_PTR(ret); 190 } 191 192 ret = device_add(&sw_dev->dev); 193 if (ret) { 194 dev_err(parent, "failed to register switch (%d)\n", ret); 195 put_device(&sw_dev->dev); 196 return ERR_PTR(ret); 197 } 198 199 return sw_dev; 200 } 201 EXPORT_SYMBOL_GPL(typec_switch_register); 202 203 int typec_switch_set(struct typec_switch *sw, 204 enum typec_orientation orientation) 205 { 206 struct typec_switch_dev *sw_dev; 207 unsigned int i; 208 int ret; 209 210 if (IS_ERR_OR_NULL(sw)) 211 return 0; 212 213 for (i = 0; i < sw->num_sw_devs; i++) { 214 sw_dev = sw->sw_devs[i]; 215 216 ret = sw_dev->set(sw_dev, orientation); 217 if (ret) 218 return ret; 219 } 220 221 return 0; 222 } 223 EXPORT_SYMBOL_GPL(typec_switch_set); 224 225 /** 226 * typec_switch_unregister - Unregister USB Type-C orientation switch 227 * @sw_dev: USB Type-C orientation switch 228 * 229 * Unregister switch that was registered with typec_switch_register(). 230 */ 231 void typec_switch_unregister(struct typec_switch_dev *sw_dev) 232 { 233 if (!IS_ERR_OR_NULL(sw_dev)) 234 device_unregister(&sw_dev->dev); 235 } 236 EXPORT_SYMBOL_GPL(typec_switch_unregister); 237 238 void typec_switch_set_drvdata(struct typec_switch_dev *sw_dev, void *data) 239 { 240 dev_set_drvdata(&sw_dev->dev, data); 241 } 242 EXPORT_SYMBOL_GPL(typec_switch_set_drvdata); 243 244 void *typec_switch_get_drvdata(struct typec_switch_dev *sw_dev) 245 { 246 return dev_get_drvdata(&sw_dev->dev); 247 } 248 EXPORT_SYMBOL_GPL(typec_switch_get_drvdata); 249 250 /* ------------------------------------------------------------------------- */ 251 252 struct typec_mux { 253 struct typec_mux_dev *mux_devs[TYPEC_MUX_MAX_DEVS]; 254 unsigned int num_mux_devs; 255 }; 256 257 static int mux_fwnode_match(struct device *dev, const void *fwnode) 258 { 259 if (!is_typec_mux_dev(dev)) 260 return 0; 261 262 return device_match_fwnode(dev, fwnode); 263 } 264 265 static void *typec_mux_match(struct fwnode_handle *fwnode, const char *id, 266 void *data) 267 { 268 const struct typec_altmode_desc *desc = data; 269 struct device *dev; 270 bool match; 271 int nval; 272 u16 *val; 273 int ret; 274 int i; 275 276 /* 277 * Check has the identifier already been "consumed". If it 278 * has, no need to do any extra connection identification. 279 */ 280 match = !id; 281 if (match) 282 goto find_mux; 283 284 if (!desc) { 285 /* 286 * Accessory Mode muxes & muxes which explicitly specify 287 * the required identifier can avoid SVID matching. 288 */ 289 match = fwnode_property_present(fwnode, "accessory") || 290 fwnode_property_present(fwnode, id); 291 if (match) 292 goto find_mux; 293 return NULL; 294 } 295 296 /* Alternate Mode muxes */ 297 nval = fwnode_property_count_u16(fwnode, "svid"); 298 if (nval <= 0) 299 return NULL; 300 301 val = kcalloc(nval, sizeof(*val), GFP_KERNEL); 302 if (!val) 303 return ERR_PTR(-ENOMEM); 304 305 ret = fwnode_property_read_u16_array(fwnode, "svid", val, nval); 306 if (ret < 0) { 307 kfree(val); 308 return ERR_PTR(ret); 309 } 310 311 for (i = 0; i < nval; i++) { 312 match = val[i] == desc->svid; 313 if (match) { 314 kfree(val); 315 goto find_mux; 316 } 317 } 318 kfree(val); 319 return NULL; 320 321 find_mux: 322 dev = class_find_device(&typec_mux_class, NULL, fwnode, 323 mux_fwnode_match); 324 325 return dev ? to_typec_mux_dev(dev) : ERR_PTR(-EPROBE_DEFER); 326 } 327 328 /** 329 * fwnode_typec_mux_get - Find USB Type-C Multiplexer 330 * @fwnode: The caller device node 331 * @desc: Alt Mode description 332 * 333 * Finds a mux linked to the caller. This function is primarily meant for the 334 * Type-C drivers. Returns a reference to the mux on success, NULL if no 335 * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection 336 * was found but the mux has not been enumerated yet. 337 */ 338 struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode, 339 const struct typec_altmode_desc *desc) 340 { 341 struct typec_mux_dev *mux_devs[TYPEC_MUX_MAX_DEVS]; 342 struct typec_mux *mux; 343 int count; 344 int err; 345 int i; 346 347 mux = kzalloc(sizeof(*mux), GFP_KERNEL); 348 if (!mux) 349 return ERR_PTR(-ENOMEM); 350 351 count = fwnode_connection_find_matches(fwnode, "mode-switch", 352 (void *)desc, typec_mux_match, 353 (void **)mux_devs, 354 ARRAY_SIZE(mux_devs)); 355 if (count <= 0) { 356 kfree(mux); 357 return NULL; 358 } 359 360 for (i = 0; i < count; i++) { 361 if (IS_ERR(mux_devs[i])) { 362 err = PTR_ERR(mux_devs[i]); 363 goto put_mux_devs; 364 } 365 } 366 367 for (i = 0; i < count; i++) { 368 WARN_ON(!try_module_get(mux_devs[i]->dev.parent->driver->owner)); 369 mux->mux_devs[i] = mux_devs[i]; 370 } 371 372 mux->num_mux_devs = count; 373 374 return mux; 375 376 put_mux_devs: 377 for (i = 0; i < count; i++) { 378 if (!IS_ERR(mux_devs[i])) 379 put_device(&mux_devs[i]->dev); 380 } 381 382 kfree(mux); 383 384 return ERR_PTR(err); 385 } 386 EXPORT_SYMBOL_GPL(fwnode_typec_mux_get); 387 388 /** 389 * typec_mux_put - Release handle to a Multiplexer 390 * @mux: USB Type-C Connector Multiplexer/DeMultiplexer 391 * 392 * Decrements reference count for @mux. 393 */ 394 void typec_mux_put(struct typec_mux *mux) 395 { 396 struct typec_mux_dev *mux_dev; 397 unsigned int i; 398 399 if (IS_ERR_OR_NULL(mux)) 400 return; 401 402 for (i = 0; i < mux->num_mux_devs; i++) { 403 mux_dev = mux->mux_devs[i]; 404 module_put(mux_dev->dev.parent->driver->owner); 405 put_device(&mux_dev->dev); 406 } 407 kfree(mux); 408 } 409 EXPORT_SYMBOL_GPL(typec_mux_put); 410 411 int typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state) 412 { 413 struct typec_mux_dev *mux_dev; 414 unsigned int i; 415 int ret; 416 417 if (IS_ERR_OR_NULL(mux)) 418 return 0; 419 420 for (i = 0; i < mux->num_mux_devs; i++) { 421 mux_dev = mux->mux_devs[i]; 422 423 ret = mux_dev->set(mux_dev, state); 424 if (ret) 425 return ret; 426 } 427 428 return 0; 429 } 430 EXPORT_SYMBOL_GPL(typec_mux_set); 431 432 static void typec_mux_release(struct device *dev) 433 { 434 kfree(to_typec_mux_dev(dev)); 435 } 436 437 const struct device_type typec_mux_dev_type = { 438 .name = "mode_switch", 439 .release = typec_mux_release, 440 }; 441 442 /** 443 * typec_mux_register - Register Multiplexer routing USB Type-C pins 444 * @parent: Parent device 445 * @desc: Multiplexer description 446 * 447 * USB Type-C connectors can be used for alternate modes of operation besides 448 * USB when Accessory/Alternate Modes are supported. With some of those modes, 449 * the pins on the connector need to be reconfigured. This function registers 450 * multiplexer switches routing the pins on the connector. 451 */ 452 struct typec_mux_dev * 453 typec_mux_register(struct device *parent, const struct typec_mux_desc *desc) 454 { 455 struct typec_mux_dev *mux_dev; 456 int ret; 457 458 if (!desc || !desc->set) 459 return ERR_PTR(-EINVAL); 460 461 mux_dev = kzalloc(sizeof(*mux_dev), GFP_KERNEL); 462 if (!mux_dev) 463 return ERR_PTR(-ENOMEM); 464 465 mux_dev->set = desc->set; 466 467 device_initialize(&mux_dev->dev); 468 mux_dev->dev.parent = parent; 469 mux_dev->dev.fwnode = desc->fwnode; 470 mux_dev->dev.class = &typec_mux_class; 471 mux_dev->dev.type = &typec_mux_dev_type; 472 mux_dev->dev.driver_data = desc->drvdata; 473 ret = dev_set_name(&mux_dev->dev, "%s-mux", desc->name ? desc->name : dev_name(parent)); 474 if (ret) { 475 put_device(&mux_dev->dev); 476 return ERR_PTR(ret); 477 } 478 479 ret = device_add(&mux_dev->dev); 480 if (ret) { 481 dev_err(parent, "failed to register mux (%d)\n", ret); 482 put_device(&mux_dev->dev); 483 return ERR_PTR(ret); 484 } 485 486 return mux_dev; 487 } 488 EXPORT_SYMBOL_GPL(typec_mux_register); 489 490 /** 491 * typec_mux_unregister - Unregister Multiplexer Switch 492 * @mux_dev: USB Type-C Connector Multiplexer/DeMultiplexer 493 * 494 * Unregister mux that was registered with typec_mux_register(). 495 */ 496 void typec_mux_unregister(struct typec_mux_dev *mux_dev) 497 { 498 if (!IS_ERR_OR_NULL(mux_dev)) 499 device_unregister(&mux_dev->dev); 500 } 501 EXPORT_SYMBOL_GPL(typec_mux_unregister); 502 503 void typec_mux_set_drvdata(struct typec_mux_dev *mux_dev, void *data) 504 { 505 dev_set_drvdata(&mux_dev->dev, data); 506 } 507 EXPORT_SYMBOL_GPL(typec_mux_set_drvdata); 508 509 void *typec_mux_get_drvdata(struct typec_mux_dev *mux_dev) 510 { 511 return dev_get_drvdata(&mux_dev->dev); 512 } 513 EXPORT_SYMBOL_GPL(typec_mux_get_drvdata); 514 515 struct class typec_mux_class = { 516 .name = "typec_mux", 517 .owner = THIS_MODULE, 518 }; 519