This source file includes following definitions.
- name_match
- dev_name_ends_with
- switch_fwnode_match
- typec_switch_match
- typec_switch_get
- typec_switch_put
- typec_switch_release
- typec_switch_register
- typec_switch_unregister
- typec_switch_set_drvdata
- typec_switch_get_drvdata
- mux_fwnode_match
- typec_mux_match
- typec_mux_get
- typec_mux_put
- typec_mux_release
- typec_mux_register
- typec_mux_unregister
- typec_mux_set_drvdata
- typec_mux_get_drvdata
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   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 #include <linux/usb/typec_mux.h>
  17 
  18 #include "bus.h"
  19 
  20 static int name_match(struct device *dev, const void *name)
  21 {
  22         return !strcmp((const char *)name, dev_name(dev));
  23 }
  24 
  25 static bool dev_name_ends_with(struct device *dev, const char *suffix)
  26 {
  27         const char *name = dev_name(dev);
  28         const int name_len = strlen(name);
  29         const int suffix_len = strlen(suffix);
  30 
  31         if (suffix_len > name_len)
  32                 return false;
  33 
  34         return strcmp(name + (name_len - suffix_len), suffix) == 0;
  35 }
  36 
  37 static int switch_fwnode_match(struct device *dev, const void *fwnode)
  38 {
  39         return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-switch");
  40 }
  41 
  42 static void *typec_switch_match(struct device_connection *con, int ep,
  43                                 void *data)
  44 {
  45         struct device *dev;
  46 
  47         if (con->fwnode) {
  48                 if (con->id && !fwnode_property_present(con->fwnode, con->id))
  49                         return NULL;
  50 
  51                 dev = class_find_device(&typec_mux_class, NULL, con->fwnode,
  52                                         switch_fwnode_match);
  53         } else {
  54                 dev = class_find_device(&typec_mux_class, NULL,
  55                                         con->endpoint[ep], name_match);
  56         }
  57 
  58         return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
  59 }
  60 
  61 
  62 
  63 
  64 
  65 
  66 
  67 
  68 
  69 
  70 struct typec_switch *typec_switch_get(struct device *dev)
  71 {
  72         struct typec_switch *sw;
  73 
  74         sw = device_connection_find_match(dev, "orientation-switch", NULL,
  75                                           typec_switch_match);
  76         if (!IS_ERR_OR_NULL(sw))
  77                 WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
  78 
  79         return sw;
  80 }
  81 EXPORT_SYMBOL_GPL(typec_switch_get);
  82 
  83 
  84 
  85 
  86 
  87 
  88 
  89 void typec_switch_put(struct typec_switch *sw)
  90 {
  91         if (!IS_ERR_OR_NULL(sw)) {
  92                 module_put(sw->dev.parent->driver->owner);
  93                 put_device(&sw->dev);
  94         }
  95 }
  96 EXPORT_SYMBOL_GPL(typec_switch_put);
  97 
  98 static void typec_switch_release(struct device *dev)
  99 {
 100         kfree(to_typec_switch(dev));
 101 }
 102 
 103 static const struct device_type typec_switch_dev_type = {
 104         .name = "orientation_switch",
 105         .release = typec_switch_release,
 106 };
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 
 115 
 116 
 117 
 118 struct typec_switch *
 119 typec_switch_register(struct device *parent,
 120                       const struct typec_switch_desc *desc)
 121 {
 122         struct typec_switch *sw;
 123         int ret;
 124 
 125         if (!desc || !desc->set)
 126                 return ERR_PTR(-EINVAL);
 127 
 128         sw = kzalloc(sizeof(*sw), GFP_KERNEL);
 129         if (!sw)
 130                 return ERR_PTR(-ENOMEM);
 131 
 132         sw->set = desc->set;
 133 
 134         device_initialize(&sw->dev);
 135         sw->dev.parent = parent;
 136         sw->dev.fwnode = desc->fwnode;
 137         sw->dev.class = &typec_mux_class;
 138         sw->dev.type = &typec_switch_dev_type;
 139         sw->dev.driver_data = desc->drvdata;
 140         dev_set_name(&sw->dev, "%s-switch", dev_name(parent));
 141 
 142         ret = device_add(&sw->dev);
 143         if (ret) {
 144                 dev_err(parent, "failed to register switch (%d)\n", ret);
 145                 put_device(&sw->dev);
 146                 return ERR_PTR(ret);
 147         }
 148 
 149         return sw;
 150 }
 151 EXPORT_SYMBOL_GPL(typec_switch_register);
 152 
 153 
 154 
 155 
 156 
 157 
 158 
 159 void typec_switch_unregister(struct typec_switch *sw)
 160 {
 161         if (!IS_ERR_OR_NULL(sw))
 162                 device_unregister(&sw->dev);
 163 }
 164 EXPORT_SYMBOL_GPL(typec_switch_unregister);
 165 
 166 void typec_switch_set_drvdata(struct typec_switch *sw, void *data)
 167 {
 168         dev_set_drvdata(&sw->dev, data);
 169 }
 170 EXPORT_SYMBOL_GPL(typec_switch_set_drvdata);
 171 
 172 void *typec_switch_get_drvdata(struct typec_switch *sw)
 173 {
 174         return dev_get_drvdata(&sw->dev);
 175 }
 176 EXPORT_SYMBOL_GPL(typec_switch_get_drvdata);
 177 
 178 
 179 
 180 static int mux_fwnode_match(struct device *dev, const void *fwnode)
 181 {
 182         return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-mux");
 183 }
 184 
 185 static void *typec_mux_match(struct device_connection *con, int ep, void *data)
 186 {
 187         const struct typec_altmode_desc *desc = data;
 188         struct device *dev;
 189         bool match;
 190         int nval;
 191         u16 *val;
 192         int i;
 193 
 194         if (!con->fwnode) {
 195                 dev = class_find_device(&typec_mux_class, NULL,
 196                                         con->endpoint[ep], name_match);
 197 
 198                 return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
 199         }
 200 
 201         
 202 
 203 
 204 
 205         match = !con->id;
 206         if (match)
 207                 goto find_mux;
 208 
 209         
 210         if (!desc) {
 211                 match = fwnode_property_present(con->fwnode, "accessory");
 212                 if (match)
 213                         goto find_mux;
 214                 return NULL;
 215         }
 216 
 217         
 218         nval = fwnode_property_count_u16(con->fwnode, "svid");
 219         if (nval <= 0)
 220                 return NULL;
 221 
 222         val = kcalloc(nval, sizeof(*val), GFP_KERNEL);
 223         if (!val)
 224                 return ERR_PTR(-ENOMEM);
 225 
 226         nval = fwnode_property_read_u16_array(con->fwnode, "svid", val, nval);
 227         if (nval < 0) {
 228                 kfree(val);
 229                 return ERR_PTR(nval);
 230         }
 231 
 232         for (i = 0; i < nval; i++) {
 233                 match = val[i] == desc->svid;
 234                 if (match) {
 235                         kfree(val);
 236                         goto find_mux;
 237                 }
 238         }
 239         kfree(val);
 240         return NULL;
 241 
 242 find_mux:
 243         dev = class_find_device(&typec_mux_class, NULL, con->fwnode,
 244                                 mux_fwnode_match);
 245 
 246         return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
 247 }
 248 
 249 
 250 
 251 
 252 
 253 
 254 
 255 
 256 
 257 
 258 
 259 struct typec_mux *typec_mux_get(struct device *dev,
 260                                 const struct typec_altmode_desc *desc)
 261 {
 262         struct typec_mux *mux;
 263 
 264         mux = device_connection_find_match(dev, "mode-switch", (void *)desc,
 265                                            typec_mux_match);
 266         if (!IS_ERR_OR_NULL(mux))
 267                 WARN_ON(!try_module_get(mux->dev.parent->driver->owner));
 268 
 269         return mux;
 270 }
 271 EXPORT_SYMBOL_GPL(typec_mux_get);
 272 
 273 
 274 
 275 
 276 
 277 
 278 
 279 void typec_mux_put(struct typec_mux *mux)
 280 {
 281         if (!IS_ERR_OR_NULL(mux)) {
 282                 module_put(mux->dev.parent->driver->owner);
 283                 put_device(&mux->dev);
 284         }
 285 }
 286 EXPORT_SYMBOL_GPL(typec_mux_put);
 287 
 288 static void typec_mux_release(struct device *dev)
 289 {
 290         kfree(to_typec_mux(dev));
 291 }
 292 
 293 static const struct device_type typec_mux_dev_type = {
 294         .name = "mode_switch",
 295         .release = typec_mux_release,
 296 };
 297 
 298 
 299 
 300 
 301 
 302 
 303 
 304 
 305 
 306 
 307 
 308 struct typec_mux *
 309 typec_mux_register(struct device *parent, const struct typec_mux_desc *desc)
 310 {
 311         struct typec_mux *mux;
 312         int ret;
 313 
 314         if (!desc || !desc->set)
 315                 return ERR_PTR(-EINVAL);
 316 
 317         mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 318         if (!mux)
 319                 return ERR_PTR(-ENOMEM);
 320 
 321         mux->set = desc->set;
 322 
 323         device_initialize(&mux->dev);
 324         mux->dev.parent = parent;
 325         mux->dev.fwnode = desc->fwnode;
 326         mux->dev.class = &typec_mux_class;
 327         mux->dev.type = &typec_mux_dev_type;
 328         mux->dev.driver_data = desc->drvdata;
 329         dev_set_name(&mux->dev, "%s-mux", dev_name(parent));
 330 
 331         ret = device_add(&mux->dev);
 332         if (ret) {
 333                 dev_err(parent, "failed to register mux (%d)\n", ret);
 334                 put_device(&mux->dev);
 335                 return ERR_PTR(ret);
 336         }
 337 
 338         return mux;
 339 }
 340 EXPORT_SYMBOL_GPL(typec_mux_register);
 341 
 342 
 343 
 344 
 345 
 346 
 347 
 348 void typec_mux_unregister(struct typec_mux *mux)
 349 {
 350         if (!IS_ERR_OR_NULL(mux))
 351                 device_unregister(&mux->dev);
 352 }
 353 EXPORT_SYMBOL_GPL(typec_mux_unregister);
 354 
 355 void typec_mux_set_drvdata(struct typec_mux *mux, void *data)
 356 {
 357         dev_set_drvdata(&mux->dev, data);
 358 }
 359 EXPORT_SYMBOL_GPL(typec_mux_set_drvdata);
 360 
 361 void *typec_mux_get_drvdata(struct typec_mux *mux)
 362 {
 363         return dev_get_drvdata(&mux->dev);
 364 }
 365 EXPORT_SYMBOL_GPL(typec_mux_get_drvdata);
 366 
 367 struct class typec_mux_class = {
 368         .name = "typec_mux",
 369         .owner = THIS_MODULE,
 370 };