1bdecb33aSHeikki Krogerus // SPDX-License-Identifier: GPL-2.0 22d686c73SRandy Dunlap /* 3bdecb33aSHeikki Krogerus * USB Type-C Multiplexer/DeMultiplexer Switch support 4bdecb33aSHeikki Krogerus * 5bdecb33aSHeikki Krogerus * Copyright (C) 2018 Intel Corporation 6bdecb33aSHeikki Krogerus * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> 7bdecb33aSHeikki Krogerus * Hans de Goede <hdegoede@redhat.com> 8bdecb33aSHeikki Krogerus */ 9bdecb33aSHeikki Krogerus 10bdecb33aSHeikki Krogerus #include <linux/device.h> 11bdecb33aSHeikki Krogerus #include <linux/list.h> 123e3b8196SHeikki Krogerus #include <linux/module.h> 13bdecb33aSHeikki Krogerus #include <linux/mutex.h> 1496a6d031SHeikki Krogerus #include <linux/property.h> 1596a6d031SHeikki Krogerus #include <linux/slab.h> 16bdecb33aSHeikki Krogerus #include <linux/usb/typec_mux.h> 17bdecb33aSHeikki Krogerus 183370db35SHeikki Krogerus #include "bus.h" 193370db35SHeikki Krogerus 203370db35SHeikki Krogerus static bool dev_name_ends_with(struct device *dev, const char *suffix) 213370db35SHeikki Krogerus { 223370db35SHeikki Krogerus const char *name = dev_name(dev); 233370db35SHeikki Krogerus const int name_len = strlen(name); 243370db35SHeikki Krogerus const int suffix_len = strlen(suffix); 253370db35SHeikki Krogerus 263370db35SHeikki Krogerus if (suffix_len > name_len) 273370db35SHeikki Krogerus return false; 283370db35SHeikki Krogerus 293370db35SHeikki Krogerus return strcmp(name + (name_len - suffix_len), suffix) == 0; 303370db35SHeikki Krogerus } 313370db35SHeikki Krogerus 323370db35SHeikki Krogerus static int switch_fwnode_match(struct device *dev, const void *fwnode) 333370db35SHeikki Krogerus { 343370db35SHeikki Krogerus return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-switch"); 353370db35SHeikki Krogerus } 36bdecb33aSHeikki Krogerus 37f5514c91SHeikki Krogerus static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id, 38bdecb33aSHeikki Krogerus void *data) 39bdecb33aSHeikki Krogerus { 403370db35SHeikki Krogerus struct device *dev; 41bdecb33aSHeikki Krogerus 42f5514c91SHeikki Krogerus if (id && !fwnode_property_present(fwnode, id)) 4396a6d031SHeikki Krogerus return NULL; 4496a6d031SHeikki Krogerus 45f5514c91SHeikki Krogerus dev = class_find_device(&typec_mux_class, NULL, fwnode, 463370db35SHeikki Krogerus switch_fwnode_match); 4796a6d031SHeikki Krogerus 483370db35SHeikki Krogerus return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER); 49bdecb33aSHeikki Krogerus } 50bdecb33aSHeikki Krogerus 51bdecb33aSHeikki Krogerus /** 52d1c6a769SHeikki Krogerus * fwnode_typec_switch_get - Find USB Type-C orientation switch 53d1c6a769SHeikki Krogerus * @fwnode: The caller device node 54bdecb33aSHeikki Krogerus * 55bdecb33aSHeikki Krogerus * Finds a switch linked with @dev. Returns a reference to the switch on 56bdecb33aSHeikki Krogerus * success, NULL if no matching connection was found, or 57bdecb33aSHeikki Krogerus * ERR_PTR(-EPROBE_DEFER) when a connection was found but the switch 58bdecb33aSHeikki Krogerus * has not been enumerated yet. 59bdecb33aSHeikki Krogerus */ 60d1c6a769SHeikki Krogerus struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode) 61bdecb33aSHeikki Krogerus { 62bdecb33aSHeikki Krogerus struct typec_switch *sw; 63bdecb33aSHeikki Krogerus 64d1c6a769SHeikki Krogerus sw = fwnode_connection_find_match(fwnode, "orientation-switch", NULL, 65bdecb33aSHeikki Krogerus typec_switch_match); 663370db35SHeikki Krogerus if (!IS_ERR_OR_NULL(sw)) 673370db35SHeikki Krogerus WARN_ON(!try_module_get(sw->dev.parent->driver->owner)); 68bdecb33aSHeikki Krogerus 69bdecb33aSHeikki Krogerus return sw; 70bdecb33aSHeikki Krogerus } 71d1c6a769SHeikki Krogerus EXPORT_SYMBOL_GPL(fwnode_typec_switch_get); 72bdecb33aSHeikki Krogerus 73bdecb33aSHeikki Krogerus /** 74cbdc0f54SMauro Carvalho Chehab * typec_switch_put - Release USB Type-C orientation switch 75bdecb33aSHeikki Krogerus * @sw: USB Type-C orientation switch 76bdecb33aSHeikki Krogerus * 77bdecb33aSHeikki Krogerus * Decrement reference count for @sw. 78bdecb33aSHeikki Krogerus */ 79bdecb33aSHeikki Krogerus void typec_switch_put(struct typec_switch *sw) 80bdecb33aSHeikki Krogerus { 813e3b8196SHeikki Krogerus if (!IS_ERR_OR_NULL(sw)) { 823370db35SHeikki Krogerus module_put(sw->dev.parent->driver->owner); 833370db35SHeikki Krogerus put_device(&sw->dev); 84bdecb33aSHeikki Krogerus } 853e3b8196SHeikki Krogerus } 86bdecb33aSHeikki Krogerus EXPORT_SYMBOL_GPL(typec_switch_put); 87bdecb33aSHeikki Krogerus 883370db35SHeikki Krogerus static void typec_switch_release(struct device *dev) 893370db35SHeikki Krogerus { 903370db35SHeikki Krogerus kfree(to_typec_switch(dev)); 913370db35SHeikki Krogerus } 923370db35SHeikki Krogerus 933370db35SHeikki Krogerus static const struct device_type typec_switch_dev_type = { 943370db35SHeikki Krogerus .name = "orientation_switch", 953370db35SHeikki Krogerus .release = typec_switch_release, 963370db35SHeikki Krogerus }; 973370db35SHeikki Krogerus 98bdecb33aSHeikki Krogerus /** 99bdecb33aSHeikki Krogerus * typec_switch_register - Register USB Type-C orientation switch 1003370db35SHeikki Krogerus * @parent: Parent device 1013370db35SHeikki Krogerus * @desc: Orientation switch description 102bdecb33aSHeikki Krogerus * 103bdecb33aSHeikki Krogerus * This function registers a switch that can be used for routing the correct 104bdecb33aSHeikki Krogerus * data pairs depending on the cable plug orientation from the USB Type-C 105bdecb33aSHeikki Krogerus * connector to the USB controllers. USB Type-C plugs can be inserted 106bdecb33aSHeikki Krogerus * right-side-up or upside-down. 107bdecb33aSHeikki Krogerus */ 1083370db35SHeikki Krogerus struct typec_switch * 1093370db35SHeikki Krogerus typec_switch_register(struct device *parent, 1103370db35SHeikki Krogerus const struct typec_switch_desc *desc) 111bdecb33aSHeikki Krogerus { 1123370db35SHeikki Krogerus struct typec_switch *sw; 1133370db35SHeikki Krogerus int ret; 114bdecb33aSHeikki Krogerus 1153370db35SHeikki Krogerus if (!desc || !desc->set) 1163370db35SHeikki Krogerus return ERR_PTR(-EINVAL); 1173370db35SHeikki Krogerus 1183370db35SHeikki Krogerus sw = kzalloc(sizeof(*sw), GFP_KERNEL); 1193370db35SHeikki Krogerus if (!sw) 1203370db35SHeikki Krogerus return ERR_PTR(-ENOMEM); 1213370db35SHeikki Krogerus 1223370db35SHeikki Krogerus sw->set = desc->set; 1233370db35SHeikki Krogerus 1243370db35SHeikki Krogerus device_initialize(&sw->dev); 1253370db35SHeikki Krogerus sw->dev.parent = parent; 1263370db35SHeikki Krogerus sw->dev.fwnode = desc->fwnode; 1273370db35SHeikki Krogerus sw->dev.class = &typec_mux_class; 1283370db35SHeikki Krogerus sw->dev.type = &typec_switch_dev_type; 1293370db35SHeikki Krogerus sw->dev.driver_data = desc->drvdata; 130ef441dd6SHeikki Krogerus dev_set_name(&sw->dev, "%s-switch", 131ef441dd6SHeikki Krogerus desc->name ? desc->name : dev_name(parent)); 1323370db35SHeikki Krogerus 1333370db35SHeikki Krogerus ret = device_add(&sw->dev); 1343370db35SHeikki Krogerus if (ret) { 1353370db35SHeikki Krogerus dev_err(parent, "failed to register switch (%d)\n", ret); 1363370db35SHeikki Krogerus put_device(&sw->dev); 1373370db35SHeikki Krogerus return ERR_PTR(ret); 1383370db35SHeikki Krogerus } 1393370db35SHeikki Krogerus 1403370db35SHeikki Krogerus return sw; 141bdecb33aSHeikki Krogerus } 142bdecb33aSHeikki Krogerus EXPORT_SYMBOL_GPL(typec_switch_register); 143bdecb33aSHeikki Krogerus 144774a9df6SHeikki Krogerus int typec_switch_set(struct typec_switch *sw, 145774a9df6SHeikki Krogerus enum typec_orientation orientation) 146774a9df6SHeikki Krogerus { 147774a9df6SHeikki Krogerus if (IS_ERR_OR_NULL(sw)) 148774a9df6SHeikki Krogerus return 0; 149774a9df6SHeikki Krogerus 150774a9df6SHeikki Krogerus return sw->set(sw, orientation); 151774a9df6SHeikki Krogerus } 152774a9df6SHeikki Krogerus EXPORT_SYMBOL_GPL(typec_switch_set); 153774a9df6SHeikki Krogerus 154bdecb33aSHeikki Krogerus /** 155bdecb33aSHeikki Krogerus * typec_switch_unregister - Unregister USB Type-C orientation switch 156bdecb33aSHeikki Krogerus * @sw: USB Type-C orientation switch 157bdecb33aSHeikki Krogerus * 158bdecb33aSHeikki Krogerus * Unregister switch that was registered with typec_switch_register(). 159bdecb33aSHeikki Krogerus */ 160bdecb33aSHeikki Krogerus void typec_switch_unregister(struct typec_switch *sw) 161bdecb33aSHeikki Krogerus { 1623370db35SHeikki Krogerus if (!IS_ERR_OR_NULL(sw)) 1633370db35SHeikki Krogerus device_unregister(&sw->dev); 164bdecb33aSHeikki Krogerus } 165bdecb33aSHeikki Krogerus EXPORT_SYMBOL_GPL(typec_switch_unregister); 166bdecb33aSHeikki Krogerus 1673370db35SHeikki Krogerus void typec_switch_set_drvdata(struct typec_switch *sw, void *data) 1683370db35SHeikki Krogerus { 1693370db35SHeikki Krogerus dev_set_drvdata(&sw->dev, data); 1703370db35SHeikki Krogerus } 1713370db35SHeikki Krogerus EXPORT_SYMBOL_GPL(typec_switch_set_drvdata); 1723370db35SHeikki Krogerus 1733370db35SHeikki Krogerus void *typec_switch_get_drvdata(struct typec_switch *sw) 1743370db35SHeikki Krogerus { 1753370db35SHeikki Krogerus return dev_get_drvdata(&sw->dev); 1763370db35SHeikki Krogerus } 1773370db35SHeikki Krogerus EXPORT_SYMBOL_GPL(typec_switch_get_drvdata); 1783370db35SHeikki Krogerus 179bdecb33aSHeikki Krogerus /* ------------------------------------------------------------------------- */ 180bdecb33aSHeikki Krogerus 1813370db35SHeikki Krogerus static int mux_fwnode_match(struct device *dev, const void *fwnode) 1823370db35SHeikki Krogerus { 1833370db35SHeikki Krogerus return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-mux"); 1843370db35SHeikki Krogerus } 1853370db35SHeikki Krogerus 186f5514c91SHeikki Krogerus static void *typec_mux_match(struct fwnode_handle *fwnode, const char *id, 187f5514c91SHeikki Krogerus void *data) 188bdecb33aSHeikki Krogerus { 18996a6d031SHeikki Krogerus const struct typec_altmode_desc *desc = data; 1903370db35SHeikki Krogerus struct device *dev; 19196a6d031SHeikki Krogerus bool match; 1923370db35SHeikki Krogerus int nval; 19396a6d031SHeikki Krogerus u16 *val; 19496a6d031SHeikki Krogerus int i; 195bdecb33aSHeikki Krogerus 196bdecb33aSHeikki Krogerus /* 19796a6d031SHeikki Krogerus * Check has the identifier already been "consumed". If it 19896a6d031SHeikki Krogerus * has, no need to do any extra connection identification. 199bdecb33aSHeikki Krogerus */ 200f5514c91SHeikki Krogerus match = !id; 20196a6d031SHeikki Krogerus if (match) 20296a6d031SHeikki Krogerus goto find_mux; 20396a6d031SHeikki Krogerus 20496a6d031SHeikki Krogerus /* Accessory Mode muxes */ 20596a6d031SHeikki Krogerus if (!desc) { 206f5514c91SHeikki Krogerus match = fwnode_property_present(fwnode, "accessory"); 20796a6d031SHeikki Krogerus if (match) 20896a6d031SHeikki Krogerus goto find_mux; 20996a6d031SHeikki Krogerus return NULL; 21096a6d031SHeikki Krogerus } 21196a6d031SHeikki Krogerus 21296a6d031SHeikki Krogerus /* Alternate Mode muxes */ 213f5514c91SHeikki Krogerus nval = fwnode_property_count_u16(fwnode, "svid"); 21496a6d031SHeikki Krogerus if (nval <= 0) 21596a6d031SHeikki Krogerus return NULL; 21696a6d031SHeikki Krogerus 21796a6d031SHeikki Krogerus val = kcalloc(nval, sizeof(*val), GFP_KERNEL); 21896a6d031SHeikki Krogerus if (!val) 21996a6d031SHeikki Krogerus return ERR_PTR(-ENOMEM); 22096a6d031SHeikki Krogerus 221f5514c91SHeikki Krogerus nval = fwnode_property_read_u16_array(fwnode, "svid", val, nval); 22296a6d031SHeikki Krogerus if (nval < 0) { 22396a6d031SHeikki Krogerus kfree(val); 22496a6d031SHeikki Krogerus return ERR_PTR(nval); 22596a6d031SHeikki Krogerus } 22696a6d031SHeikki Krogerus 22796a6d031SHeikki Krogerus for (i = 0; i < nval; i++) { 22896a6d031SHeikki Krogerus match = val[i] == desc->svid; 22996a6d031SHeikki Krogerus if (match) { 23096a6d031SHeikki Krogerus kfree(val); 23196a6d031SHeikki Krogerus goto find_mux; 23296a6d031SHeikki Krogerus } 23396a6d031SHeikki Krogerus } 23496a6d031SHeikki Krogerus kfree(val); 23596a6d031SHeikki Krogerus return NULL; 23696a6d031SHeikki Krogerus 23796a6d031SHeikki Krogerus find_mux: 238f5514c91SHeikki Krogerus dev = class_find_device(&typec_mux_class, NULL, fwnode, 2393370db35SHeikki Krogerus mux_fwnode_match); 24096a6d031SHeikki Krogerus 2413370db35SHeikki Krogerus return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER); 242bdecb33aSHeikki Krogerus } 243bdecb33aSHeikki Krogerus 244bdecb33aSHeikki Krogerus /** 245d1c6a769SHeikki Krogerus * fwnode_typec_mux_get - Find USB Type-C Multiplexer 246d1c6a769SHeikki Krogerus * @fwnode: The caller device node 247540bfab7SHeikki Krogerus * @desc: Alt Mode description 248bdecb33aSHeikki Krogerus * 249bdecb33aSHeikki Krogerus * Finds a mux linked to the caller. This function is primarily meant for the 250bdecb33aSHeikki Krogerus * Type-C drivers. Returns a reference to the mux on success, NULL if no 251bdecb33aSHeikki Krogerus * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection 252bdecb33aSHeikki Krogerus * was found but the mux has not been enumerated yet. 253bdecb33aSHeikki Krogerus */ 254d1c6a769SHeikki Krogerus struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode, 255540bfab7SHeikki Krogerus const struct typec_altmode_desc *desc) 256bdecb33aSHeikki Krogerus { 257bdecb33aSHeikki Krogerus struct typec_mux *mux; 258bdecb33aSHeikki Krogerus 259d1c6a769SHeikki Krogerus mux = fwnode_connection_find_match(fwnode, "mode-switch", (void *)desc, 260540bfab7SHeikki Krogerus typec_mux_match); 2613370db35SHeikki Krogerus if (!IS_ERR_OR_NULL(mux)) 2623370db35SHeikki Krogerus WARN_ON(!try_module_get(mux->dev.parent->driver->owner)); 263bdecb33aSHeikki Krogerus 264bdecb33aSHeikki Krogerus return mux; 265bdecb33aSHeikki Krogerus } 266d1c6a769SHeikki Krogerus EXPORT_SYMBOL_GPL(fwnode_typec_mux_get); 267bdecb33aSHeikki Krogerus 268bdecb33aSHeikki Krogerus /** 269bdecb33aSHeikki Krogerus * typec_mux_put - Release handle to a Multiplexer 270bdecb33aSHeikki Krogerus * @mux: USB Type-C Connector Multiplexer/DeMultiplexer 271bdecb33aSHeikki Krogerus * 272bdecb33aSHeikki Krogerus * Decrements reference count for @mux. 273bdecb33aSHeikki Krogerus */ 274bdecb33aSHeikki Krogerus void typec_mux_put(struct typec_mux *mux) 275bdecb33aSHeikki Krogerus { 2763e3b8196SHeikki Krogerus if (!IS_ERR_OR_NULL(mux)) { 2773370db35SHeikki Krogerus module_put(mux->dev.parent->driver->owner); 2783370db35SHeikki Krogerus put_device(&mux->dev); 279bdecb33aSHeikki Krogerus } 2803e3b8196SHeikki Krogerus } 281bdecb33aSHeikki Krogerus EXPORT_SYMBOL_GPL(typec_mux_put); 282bdecb33aSHeikki Krogerus 283774a9df6SHeikki Krogerus int typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state) 284774a9df6SHeikki Krogerus { 285774a9df6SHeikki Krogerus if (IS_ERR_OR_NULL(mux)) 286774a9df6SHeikki Krogerus return 0; 287774a9df6SHeikki Krogerus 288774a9df6SHeikki Krogerus return mux->set(mux, state); 289774a9df6SHeikki Krogerus } 290774a9df6SHeikki Krogerus EXPORT_SYMBOL_GPL(typec_mux_set); 291774a9df6SHeikki Krogerus 2923370db35SHeikki Krogerus static void typec_mux_release(struct device *dev) 2933370db35SHeikki Krogerus { 2943370db35SHeikki Krogerus kfree(to_typec_mux(dev)); 2953370db35SHeikki Krogerus } 2963370db35SHeikki Krogerus 2973370db35SHeikki Krogerus static const struct device_type typec_mux_dev_type = { 2983370db35SHeikki Krogerus .name = "mode_switch", 2993370db35SHeikki Krogerus .release = typec_mux_release, 3003370db35SHeikki Krogerus }; 3013370db35SHeikki Krogerus 302bdecb33aSHeikki Krogerus /** 303bdecb33aSHeikki Krogerus * typec_mux_register - Register Multiplexer routing USB Type-C pins 3043370db35SHeikki Krogerus * @parent: Parent device 3053370db35SHeikki Krogerus * @desc: Multiplexer description 306bdecb33aSHeikki Krogerus * 307bdecb33aSHeikki Krogerus * USB Type-C connectors can be used for alternate modes of operation besides 308bdecb33aSHeikki Krogerus * USB when Accessory/Alternate Modes are supported. With some of those modes, 309bdecb33aSHeikki Krogerus * the pins on the connector need to be reconfigured. This function registers 310bdecb33aSHeikki Krogerus * multiplexer switches routing the pins on the connector. 311bdecb33aSHeikki Krogerus */ 3123370db35SHeikki Krogerus struct typec_mux * 3133370db35SHeikki Krogerus typec_mux_register(struct device *parent, const struct typec_mux_desc *desc) 314bdecb33aSHeikki Krogerus { 3153370db35SHeikki Krogerus struct typec_mux *mux; 3163370db35SHeikki Krogerus int ret; 317bdecb33aSHeikki Krogerus 3183370db35SHeikki Krogerus if (!desc || !desc->set) 3193370db35SHeikki Krogerus return ERR_PTR(-EINVAL); 3203370db35SHeikki Krogerus 3213370db35SHeikki Krogerus mux = kzalloc(sizeof(*mux), GFP_KERNEL); 3223370db35SHeikki Krogerus if (!mux) 3233370db35SHeikki Krogerus return ERR_PTR(-ENOMEM); 3243370db35SHeikki Krogerus 3253370db35SHeikki Krogerus mux->set = desc->set; 3263370db35SHeikki Krogerus 3273370db35SHeikki Krogerus device_initialize(&mux->dev); 3283370db35SHeikki Krogerus mux->dev.parent = parent; 3293370db35SHeikki Krogerus mux->dev.fwnode = desc->fwnode; 3303370db35SHeikki Krogerus mux->dev.class = &typec_mux_class; 3313370db35SHeikki Krogerus mux->dev.type = &typec_mux_dev_type; 3323370db35SHeikki Krogerus mux->dev.driver_data = desc->drvdata; 333ef441dd6SHeikki Krogerus dev_set_name(&mux->dev, "%s-mux", 334ef441dd6SHeikki Krogerus desc->name ? desc->name : dev_name(parent)); 3353370db35SHeikki Krogerus 3363370db35SHeikki Krogerus ret = device_add(&mux->dev); 3373370db35SHeikki Krogerus if (ret) { 3383370db35SHeikki Krogerus dev_err(parent, "failed to register mux (%d)\n", ret); 3393370db35SHeikki Krogerus put_device(&mux->dev); 3403370db35SHeikki Krogerus return ERR_PTR(ret); 3413370db35SHeikki Krogerus } 3423370db35SHeikki Krogerus 3433370db35SHeikki Krogerus return mux; 344bdecb33aSHeikki Krogerus } 345bdecb33aSHeikki Krogerus EXPORT_SYMBOL_GPL(typec_mux_register); 346bdecb33aSHeikki Krogerus 347bdecb33aSHeikki Krogerus /** 348bdecb33aSHeikki Krogerus * typec_mux_unregister - Unregister Multiplexer Switch 34974789aedSHeikki Krogerus * @mux: USB Type-C Connector Multiplexer/DeMultiplexer 350bdecb33aSHeikki Krogerus * 351bdecb33aSHeikki Krogerus * Unregister mux that was registered with typec_mux_register(). 352bdecb33aSHeikki Krogerus */ 353bdecb33aSHeikki Krogerus void typec_mux_unregister(struct typec_mux *mux) 354bdecb33aSHeikki Krogerus { 3553370db35SHeikki Krogerus if (!IS_ERR_OR_NULL(mux)) 3563370db35SHeikki Krogerus device_unregister(&mux->dev); 357bdecb33aSHeikki Krogerus } 358bdecb33aSHeikki Krogerus EXPORT_SYMBOL_GPL(typec_mux_unregister); 3593370db35SHeikki Krogerus 3603370db35SHeikki Krogerus void typec_mux_set_drvdata(struct typec_mux *mux, void *data) 3613370db35SHeikki Krogerus { 3623370db35SHeikki Krogerus dev_set_drvdata(&mux->dev, data); 3633370db35SHeikki Krogerus } 3643370db35SHeikki Krogerus EXPORT_SYMBOL_GPL(typec_mux_set_drvdata); 3653370db35SHeikki Krogerus 3663370db35SHeikki Krogerus void *typec_mux_get_drvdata(struct typec_mux *mux) 3673370db35SHeikki Krogerus { 3683370db35SHeikki Krogerus return dev_get_drvdata(&mux->dev); 3693370db35SHeikki Krogerus } 3703370db35SHeikki Krogerus EXPORT_SYMBOL_GPL(typec_mux_get_drvdata); 3713370db35SHeikki Krogerus 3723370db35SHeikki Krogerus struct class typec_mux_class = { 3733370db35SHeikki Krogerus .name = "typec_mux", 3743370db35SHeikki Krogerus .owner = THIS_MODULE, 3753370db35SHeikki Krogerus }; 376