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(const struct fwnode_handle *fwnode, 36 const char *id, 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(const struct fwnode_handle *fwnode, 266 const char *id, void *data) 267 { 268 struct device *dev; 269 270 /* 271 * Device graph (OF graph) does not give any means to identify the 272 * device type or the device class of the remote port parent that @fwnode 273 * represents, so in order to identify the type or the class of @fwnode 274 * an additional device property is needed. With typec muxes the 275 * property is named "mode-switch" (@id). The value of the device 276 * property is ignored. 277 */ 278 if (id && !fwnode_property_present(fwnode, id)) 279 return NULL; 280 281 dev = class_find_device(&typec_mux_class, NULL, fwnode, 282 mux_fwnode_match); 283 284 return dev ? to_typec_mux_dev(dev) : ERR_PTR(-EPROBE_DEFER); 285 } 286 287 /** 288 * fwnode_typec_mux_get - Find USB Type-C Multiplexer 289 * @fwnode: The caller device node 290 * 291 * Finds a mux linked to the caller. This function is primarily meant for the 292 * Type-C drivers. Returns a reference to the mux on success, NULL if no 293 * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection 294 * was found but the mux has not been enumerated yet. 295 */ 296 struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode) 297 { 298 struct typec_mux_dev *mux_devs[TYPEC_MUX_MAX_DEVS]; 299 struct typec_mux *mux; 300 int count; 301 int err; 302 int i; 303 304 mux = kzalloc(sizeof(*mux), GFP_KERNEL); 305 if (!mux) 306 return ERR_PTR(-ENOMEM); 307 308 count = fwnode_connection_find_matches(fwnode, "mode-switch", 309 NULL, typec_mux_match, 310 (void **)mux_devs, 311 ARRAY_SIZE(mux_devs)); 312 if (count <= 0) { 313 kfree(mux); 314 return NULL; 315 } 316 317 for (i = 0; i < count; i++) { 318 if (IS_ERR(mux_devs[i])) { 319 err = PTR_ERR(mux_devs[i]); 320 goto put_mux_devs; 321 } 322 } 323 324 for (i = 0; i < count; i++) { 325 WARN_ON(!try_module_get(mux_devs[i]->dev.parent->driver->owner)); 326 mux->mux_devs[i] = mux_devs[i]; 327 } 328 329 mux->num_mux_devs = count; 330 331 return mux; 332 333 put_mux_devs: 334 for (i = 0; i < count; i++) { 335 if (!IS_ERR(mux_devs[i])) 336 put_device(&mux_devs[i]->dev); 337 } 338 339 kfree(mux); 340 341 return ERR_PTR(err); 342 } 343 EXPORT_SYMBOL_GPL(fwnode_typec_mux_get); 344 345 /** 346 * typec_mux_put - Release handle to a Multiplexer 347 * @mux: USB Type-C Connector Multiplexer/DeMultiplexer 348 * 349 * Decrements reference count for @mux. 350 */ 351 void typec_mux_put(struct typec_mux *mux) 352 { 353 struct typec_mux_dev *mux_dev; 354 unsigned int i; 355 356 if (IS_ERR_OR_NULL(mux)) 357 return; 358 359 for (i = 0; i < mux->num_mux_devs; i++) { 360 mux_dev = mux->mux_devs[i]; 361 module_put(mux_dev->dev.parent->driver->owner); 362 put_device(&mux_dev->dev); 363 } 364 kfree(mux); 365 } 366 EXPORT_SYMBOL_GPL(typec_mux_put); 367 368 int typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state) 369 { 370 struct typec_mux_dev *mux_dev; 371 unsigned int i; 372 int ret; 373 374 if (IS_ERR_OR_NULL(mux)) 375 return 0; 376 377 for (i = 0; i < mux->num_mux_devs; i++) { 378 mux_dev = mux->mux_devs[i]; 379 380 ret = mux_dev->set(mux_dev, state); 381 if (ret) 382 return ret; 383 } 384 385 return 0; 386 } 387 EXPORT_SYMBOL_GPL(typec_mux_set); 388 389 static void typec_mux_release(struct device *dev) 390 { 391 kfree(to_typec_mux_dev(dev)); 392 } 393 394 const struct device_type typec_mux_dev_type = { 395 .name = "mode_switch", 396 .release = typec_mux_release, 397 }; 398 399 /** 400 * typec_mux_register - Register Multiplexer routing USB Type-C pins 401 * @parent: Parent device 402 * @desc: Multiplexer description 403 * 404 * USB Type-C connectors can be used for alternate modes of operation besides 405 * USB when Accessory/Alternate Modes are supported. With some of those modes, 406 * the pins on the connector need to be reconfigured. This function registers 407 * multiplexer switches routing the pins on the connector. 408 */ 409 struct typec_mux_dev * 410 typec_mux_register(struct device *parent, const struct typec_mux_desc *desc) 411 { 412 struct typec_mux_dev *mux_dev; 413 int ret; 414 415 if (!desc || !desc->set) 416 return ERR_PTR(-EINVAL); 417 418 mux_dev = kzalloc(sizeof(*mux_dev), GFP_KERNEL); 419 if (!mux_dev) 420 return ERR_PTR(-ENOMEM); 421 422 mux_dev->set = desc->set; 423 424 device_initialize(&mux_dev->dev); 425 mux_dev->dev.parent = parent; 426 mux_dev->dev.fwnode = desc->fwnode; 427 mux_dev->dev.class = &typec_mux_class; 428 mux_dev->dev.type = &typec_mux_dev_type; 429 mux_dev->dev.driver_data = desc->drvdata; 430 ret = dev_set_name(&mux_dev->dev, "%s-mux", desc->name ? desc->name : dev_name(parent)); 431 if (ret) { 432 put_device(&mux_dev->dev); 433 return ERR_PTR(ret); 434 } 435 436 ret = device_add(&mux_dev->dev); 437 if (ret) { 438 dev_err(parent, "failed to register mux (%d)\n", ret); 439 put_device(&mux_dev->dev); 440 return ERR_PTR(ret); 441 } 442 443 return mux_dev; 444 } 445 EXPORT_SYMBOL_GPL(typec_mux_register); 446 447 /** 448 * typec_mux_unregister - Unregister Multiplexer Switch 449 * @mux_dev: USB Type-C Connector Multiplexer/DeMultiplexer 450 * 451 * Unregister mux that was registered with typec_mux_register(). 452 */ 453 void typec_mux_unregister(struct typec_mux_dev *mux_dev) 454 { 455 if (!IS_ERR_OR_NULL(mux_dev)) 456 device_unregister(&mux_dev->dev); 457 } 458 EXPORT_SYMBOL_GPL(typec_mux_unregister); 459 460 void typec_mux_set_drvdata(struct typec_mux_dev *mux_dev, void *data) 461 { 462 dev_set_drvdata(&mux_dev->dev, data); 463 } 464 EXPORT_SYMBOL_GPL(typec_mux_set_drvdata); 465 466 void *typec_mux_get_drvdata(struct typec_mux_dev *mux_dev) 467 { 468 return dev_get_drvdata(&mux_dev->dev); 469 } 470 EXPORT_SYMBOL_GPL(typec_mux_get_drvdata); 471 472 struct class typec_mux_class = { 473 .name = "typec_mux", 474 }; 475