| 1 | |
| 2 | |
| 3 | * Copyright (C) 2025 Linaro Ltd.
|
| 4 |
|
| 5 |
|
| 6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
| 7 |
|
| 8 | #include <linux/auxiliary_bus.h>
|
| 9 | #include <linux/cleanup.h>
|
| 10 | #include <linux/device.h>
|
| 11 | #include <linux/fwnode.h>
|
| 12 | #include <linux/gpio/consumer.h>
|
| 13 | #include <linux/gpio/machine.h>
|
| 14 | #include <linux/idr.h>
|
| 15 | #include <linux/kref.h>
|
| 16 | #include <linux/list.h>
|
| 17 | #include <linux/lockdep.h>
|
| 18 | #include <linux/module.h>
|
| 19 | #include <linux/mutex.h>
|
| 20 | #include <linux/of.h>
|
| 21 | #include <linux/overflow.h>
|
| 22 | #include <linux/printk.h>
|
| 23 | #include <linux/property.h>
|
| 24 | #include <linux/slab.h>
|
| 25 | #include <linux/string.h>
|
| 26 |
|
| 27 | #include "gpiolib.h"
|
| 28 | #include "gpiolib-shared.h"
|
| 29 |
|
| 30 |
|
| 31 | struct gpio_shared_ref {
|
| 32 | struct list_head list;
|
| 33 |
|
| 34 | struct fwnode_handle *fwnode;
|
| 35 |
|
| 36 | enum gpiod_flags flags;
|
| 37 | char *con_id;
|
| 38 | int dev_id;
|
| 39 |
|
| 40 | struct mutex lock;
|
| 41 | struct lock_class_key lock_key;
|
| 42 | struct auxiliary_device adev;
|
| 43 | struct gpiod_lookup_table *lookup;
|
| 44 | bool is_reset_gpio;
|
| 45 | };
|
| 46 |
|
| 47 |
|
| 48 | struct gpio_shared_entry {
|
| 49 | struct list_head list;
|
| 50 |
|
| 51 | struct fwnode_handle *fwnode;
|
| 52 |
|
| 53 | unsigned int offset;
|
| 54 |
|
| 55 | size_t index;
|
| 56 |
|
| 57 | struct mutex lock;
|
| 58 | struct gpio_shared_desc *shared_desc;
|
| 59 | struct kref ref;
|
| 60 | struct list_head refs;
|
| 61 | };
|
| 62 |
|
| 63 | static LIST_HEAD(gpio_shared_list);
|
| 64 | static DEFINE_IDA(gpio_shared_ida);
|
| 65 |
|
| 66 | #if IS_ENABLED(CONFIG_OF)
|
| 67 | static struct gpio_shared_entry *
|
| 68 | gpio_shared_find_entry(struct fwnode_handle *controller_node,
|
| 69 | unsigned int offset)
|
| 70 | {
|
| 71 | struct gpio_shared_entry *entry;
|
| 72 |
|
| 73 | list_for_each_entry(entry, &gpio_shared_list, list) {
|
| 74 | if (entry->fwnode == controller_node && entry->offset == offset)
|
| 75 | return entry;
|
| 76 | }
|
| 77 |
|
| 78 | return NULL;
|
| 79 | }
|
| 80 |
|
| 81 | static struct gpio_shared_ref *gpio_shared_make_ref(struct fwnode_handle *fwnode,
|
| 82 | const char *con_id,
|
| 83 | enum gpiod_flags flags)
|
| 84 | {
|
| 85 | char *con_id_cpy __free(kfree) = NULL;
|
| 86 |
|
| 87 | struct gpio_shared_ref *ref __free(kfree) = kzalloc_obj(*ref);
|
| 88 | if (!ref)
|
| 89 | return NULL;
|
| 90 |
|
| 91 | if (con_id) {
|
| 92 | con_id_cpy = kstrdup(con_id, GFP_KERNEL);
|
| 93 | if (!con_id_cpy)
|
| 94 | return NULL;
|
| 95 | }
|
| 96 |
|
| 97 | ref->dev_id = ida_alloc(&gpio_shared_ida, GFP_KERNEL);
|
| 98 | if (ref->dev_id < 0)
|
| 99 | return NULL;
|
| 100 |
|
| 101 | ref->flags = flags;
|
| 102 | ref->con_id = no_free_ptr(con_id_cpy);
|
| 103 | ref->fwnode = fwnode;
|
| 104 | lockdep_register_key(&ref->lock_key);
|
| 105 | mutex_init_with_key(&ref->lock, &ref->lock_key);
|
| 106 |
|
| 107 | return no_free_ptr(ref);
|
| 108 | }
|
| 109 |
|
| 110 | static int gpio_shared_setup_reset_proxy(struct gpio_shared_entry *entry,
|
| 111 | enum gpiod_flags flags)
|
| 112 | {
|
| 113 | struct gpio_shared_ref *ref;
|
| 114 |
|
| 115 | list_for_each_entry(ref, &entry->refs, list) {
|
| 116 | if (ref->is_reset_gpio)
|
| 117 |
|
| 118 | return 0;
|
| 119 | }
|
| 120 |
|
| 121 | ref = gpio_shared_make_ref(NULL, "reset", flags);
|
| 122 | if (!ref)
|
| 123 | return -ENOMEM;
|
| 124 |
|
| 125 | ref->is_reset_gpio = true;
|
| 126 |
|
| 127 | list_add_tail(&ref->list, &entry->refs);
|
| 128 |
|
| 129 | pr_debug("Created a secondary shared GPIO reference for potential reset-gpio device for GPIO %u at %s\n",
|
| 130 | entry->offset, fwnode_get_name(entry->fwnode));
|
| 131 |
|
| 132 | return 0;
|
| 133 | }
|
| 134 |
|
| 135 |
|
| 136 | static bool gpio_shared_of_node_ignore(struct device_node *node)
|
| 137 | {
|
| 138 |
|
| 139 | if (!of_device_is_available(node))
|
| 140 | return true;
|
| 141 |
|
| 142 | |
| 143 | * __symbols__ is a special, internal node and should not be considered
|
| 144 | * when scanning for shared GPIOs.
|
| 145 |
|
| 146 | if (of_node_name_eq(node, "__symbols__"))
|
| 147 | return true;
|
| 148 |
|
| 149 | |
| 150 | * GPIO hogs have a "gpios" property which is not a phandle and can't
|
| 151 | * possibly refer to a shared GPIO.
|
| 152 |
|
| 153 | if (of_property_present(node, "gpio-hog"))
|
| 154 | return true;
|
| 155 |
|
| 156 | return false;
|
| 157 | }
|
| 158 |
|
| 159 | static int gpio_shared_of_traverse(struct device_node *curr)
|
| 160 | {
|
| 161 | struct gpio_shared_entry *entry;
|
| 162 | size_t con_id_len, suffix_len;
|
| 163 | struct fwnode_handle *fwnode;
|
| 164 | struct of_phandle_args args;
|
| 165 | struct gpio_shared_ref *ref;
|
| 166 | struct property *prop;
|
| 167 | unsigned int offset;
|
| 168 | const char *suffix;
|
| 169 | int ret, count, i;
|
| 170 |
|
| 171 | if (gpio_shared_of_node_ignore(curr))
|
| 172 | return 0;
|
| 173 |
|
| 174 | for_each_property_of_node(curr, prop) {
|
| 175 | |
| 176 | * The standard name for a GPIO property is "foo-gpios"
|
| 177 | * or "foo-gpio". Some bindings also use "gpios" or "gpio".
|
| 178 | * There are some legacy device-trees which have a different
|
| 179 | * naming convention and for which we have rename quirks in
|
| 180 | * place in gpiolib-of.c. I don't think any of them require
|
| 181 | * support for shared GPIOs so for now let's just ignore
|
| 182 | * them. We can always just export the quirk list and
|
| 183 | * iterate over it here.
|
| 184 |
|
| 185 | if (!strends(prop->name, "-gpios") &&
|
| 186 | !strends(prop->name, "-gpio") &&
|
| 187 | strcmp(prop->name, "gpios") != 0 &&
|
| 188 | strcmp(prop->name, "gpio") != 0)
|
| 189 | continue;
|
| 190 |
|
| 191 | count = of_count_phandle_with_args(curr, prop->name,
|
| 192 | "#gpio-cells");
|
| 193 | if (count <= 0)
|
| 194 | continue;
|
| 195 |
|
| 196 | for (i = 0; i < count; i++) {
|
| 197 | struct device_node *np __free(device_node) = NULL;
|
| 198 | char *con_id __free(kfree) = NULL;
|
| 199 |
|
| 200 | ret = of_parse_phandle_with_args(curr, prop->name,
|
| 201 | "#gpio-cells", i,
|
| 202 | &args);
|
| 203 | if (ret)
|
| 204 | continue;
|
| 205 |
|
| 206 | np = args.np;
|
| 207 |
|
| 208 | if (!of_property_present(np, "gpio-controller"))
|
| 209 | continue;
|
| 210 |
|
| 211 | |
| 212 | * We support 1, 2 and 3 cell GPIO bindings in the
|
| 213 | * kernel currently. There's only one old MIPS dts that
|
| 214 | * has a one-cell binding but there's no associated
|
| 215 | * consumer so it may as well be an error. There don't
|
| 216 | * seem to be any 3-cell users of non-exclusive GPIOs,
|
| 217 | * so we can skip this as well. Let's occupy ourselves
|
| 218 | * with the predominant 2-cell binding with the first
|
| 219 | * cell indicating the hardware offset of the GPIO and
|
| 220 | * the second defining the GPIO flags of the request.
|
| 221 |
|
| 222 | if (args.args_count != 2)
|
| 223 | continue;
|
| 224 |
|
| 225 | fwnode = of_fwnode_handle(args.np);
|
| 226 | offset = args.args[0];
|
| 227 |
|
| 228 | entry = gpio_shared_find_entry(fwnode, offset);
|
| 229 | if (!entry) {
|
| 230 | entry = kzalloc_obj(*entry);
|
| 231 | if (!entry)
|
| 232 | return -ENOMEM;
|
| 233 |
|
| 234 | entry->fwnode = fwnode_handle_get(fwnode);
|
| 235 | entry->offset = offset;
|
| 236 | entry->index = count;
|
| 237 | INIT_LIST_HEAD(&entry->refs);
|
| 238 | mutex_init(&entry->lock);
|
| 239 |
|
| 240 | list_add_tail(&entry->list, &gpio_shared_list);
|
| 241 | }
|
| 242 |
|
| 243 | if (strends(prop->name, "gpios"))
|
| 244 | suffix = "-gpios";
|
| 245 | else if (strends(prop->name, "gpio"))
|
| 246 | suffix = "-gpio";
|
| 247 | else
|
| 248 | suffix = NULL;
|
| 249 | if (!suffix)
|
| 250 | continue;
|
| 251 |
|
| 252 |
|
| 253 | if (strcmp(prop->name, "gpios") && strcmp(prop->name, "gpio")) {
|
| 254 | con_id = kstrdup(prop->name, GFP_KERNEL);
|
| 255 | if (!con_id)
|
| 256 | return -ENOMEM;
|
| 257 |
|
| 258 | con_id_len = strlen(con_id);
|
| 259 | suffix_len = strlen(suffix);
|
| 260 |
|
| 261 | con_id[con_id_len - suffix_len] = '\0';
|
| 262 | }
|
| 263 |
|
| 264 | struct fwnode_handle *curr_fwnode =
|
| 265 | fwnode_handle_get(of_fwnode_handle(curr));
|
| 266 | ref = gpio_shared_make_ref(curr_fwnode, con_id, args.args[1]);
|
| 267 | if (!ref) {
|
| 268 | fwnode_handle_put(curr_fwnode);
|
| 269 | return -ENOMEM;
|
| 270 | }
|
| 271 |
|
| 272 | if (!list_empty(&entry->refs))
|
| 273 | pr_debug("GPIO %u at %s is shared by multiple firmware nodes\n",
|
| 274 | entry->offset, fwnode_get_name(entry->fwnode));
|
| 275 |
|
| 276 | list_add_tail(&ref->list, &entry->refs);
|
| 277 |
|
| 278 | if (strcmp(prop->name, "reset-gpios") == 0) {
|
| 279 | ret = gpio_shared_setup_reset_proxy(entry, args.args[1]);
|
| 280 | if (ret)
|
| 281 | return ret;
|
| 282 | }
|
| 283 | }
|
| 284 | }
|
| 285 |
|
| 286 | for_each_child_of_node_scoped(curr, child) {
|
| 287 | ret = gpio_shared_of_traverse(child);
|
| 288 | if (ret)
|
| 289 | return ret;
|
| 290 | }
|
| 291 |
|
| 292 | return 0;
|
| 293 | }
|
| 294 |
|
| 295 | static int gpio_shared_of_scan(void)
|
| 296 | {
|
| 297 | if (of_root)
|
| 298 | return gpio_shared_of_traverse(of_root);
|
| 299 |
|
| 300 | return 0;
|
| 301 | }
|
| 302 | #else
|
| 303 | static int gpio_shared_of_scan(void)
|
| 304 | {
|
| 305 | return 0;
|
| 306 | }
|
| 307 | #endif
|
| 308 |
|
| 309 | static void gpio_shared_adev_release(struct device *dev)
|
| 310 | {
|
| 311 |
|
| 312 | }
|
| 313 |
|
| 314 | static int gpio_shared_make_adev(struct gpio_device *gdev,
|
| 315 | struct gpio_shared_entry *entry,
|
| 316 | struct gpio_shared_ref *ref)
|
| 317 | {
|
| 318 | struct auxiliary_device *adev = &ref->adev;
|
| 319 | int ret;
|
| 320 |
|
| 321 | guard(mutex)(&ref->lock);
|
| 322 |
|
| 323 | memset(adev, 0, sizeof(*adev));
|
| 324 |
|
| 325 | adev->id = ref->dev_id;
|
| 326 | adev->name = "proxy";
|
| 327 | adev->dev.parent = gdev->dev.parent;
|
| 328 | adev->dev.platform_data = entry;
|
| 329 | adev->dev.release = gpio_shared_adev_release;
|
| 330 |
|
| 331 | ret = auxiliary_device_init(adev);
|
| 332 | if (ret)
|
| 333 | return ret;
|
| 334 |
|
| 335 | ret = auxiliary_device_add(adev);
|
| 336 | if (ret) {
|
| 337 | auxiliary_device_uninit(adev);
|
| 338 | return ret;
|
| 339 | }
|
| 340 |
|
| 341 | pr_debug("Created an auxiliary GPIO proxy %s for GPIO device %s\n",
|
| 342 | dev_name(&adev->dev), gpio_device_get_label(gdev));
|
| 343 |
|
| 344 | return 0;
|
| 345 | }
|
| 346 |
|
| 347 | #if IS_ENABLED(CONFIG_RESET_GPIO)
|
| 348 | |
| 349 | * Special case: reset-gpio is an auxiliary device that's created dynamically
|
| 350 | * and put in between the GPIO controller and consumers of shared GPIOs
|
| 351 | * referred to by the "reset-gpios" property.
|
| 352 | *
|
| 353 | * If the supposed consumer of a shared GPIO didn't match any of the mappings
|
| 354 | * we created when scanning the firmware nodes, it's still possible that it's
|
| 355 | * the reset-gpio device which didn't exist at the time of the scan.
|
| 356 | *
|
| 357 | * This function verifies it an return true if it's the case.
|
| 358 |
|
| 359 | static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
|
| 360 | struct gpio_shared_entry *entry,
|
| 361 | struct gpio_shared_ref *ref)
|
| 362 | {
|
| 363 | struct fwnode_handle *reset_fwnode = dev_fwnode(consumer);
|
| 364 | struct fwnode_reference_args ref_args, aux_args;
|
| 365 | struct device *parent = consumer->parent;
|
| 366 | struct gpio_shared_ref *real_ref;
|
| 367 | bool match;
|
| 368 | int ret;
|
| 369 |
|
| 370 | lockdep_assert_held(&ref->lock);
|
| 371 |
|
| 372 |
|
| 373 | if (!parent || !reset_fwnode)
|
| 374 | return false;
|
| 375 |
|
| 376 | |
| 377 | * Parent of the reset-gpio auxiliary device is the GPIO chip whose
|
| 378 | * fwnode we stored in the entry structure.
|
| 379 |
|
| 380 | if (!device_match_fwnode(parent, entry->fwnode))
|
| 381 | return false;
|
| 382 |
|
| 383 | |
| 384 | * Now we need to find the actual pin we want to assign to this
|
| 385 | * reset-gpio device. To that end: iterate over the list of references
|
| 386 | * of this entry and see if there's one, whose reset-gpios property's
|
| 387 | * arguments match the ones from this consumer's node.
|
| 388 |
|
| 389 | list_for_each_entry(real_ref, &entry->refs, list) {
|
| 390 | if (real_ref == ref)
|
| 391 | continue;
|
| 392 |
|
| 393 | guard(mutex)(&real_ref->lock);
|
| 394 |
|
| 395 | if (!real_ref->fwnode)
|
| 396 | continue;
|
| 397 |
|
| 398 | |
| 399 | * The device associated with the shared reference's firmware
|
| 400 | * node is the consumer of the reset control exposed by the
|
| 401 | * reset-gpio device. It must have a "reset-gpios" property
|
| 402 | * that's referencing the entry's firmware node.
|
| 403 | *
|
| 404 | * The reference args must agree between the real consumer and
|
| 405 | * the auxiliary reset-gpio device.
|
| 406 |
|
| 407 | ret = fwnode_property_get_reference_args(real_ref->fwnode,
|
| 408 | "reset-gpios",
|
| 409 | NULL, 2, 0, &ref_args);
|
| 410 | if (ret)
|
| 411 | continue;
|
| 412 |
|
| 413 | ret = fwnode_property_get_reference_args(reset_fwnode, "reset-gpios",
|
| 414 | NULL, 2, 0, &aux_args);
|
| 415 | if (ret) {
|
| 416 | fwnode_handle_put(ref_args.fwnode);
|
| 417 | continue;
|
| 418 | }
|
| 419 |
|
| 420 | match = ((ref_args.fwnode == entry->fwnode) &&
|
| 421 | (aux_args.fwnode == entry->fwnode) &&
|
| 422 | (ref_args.args[0] == aux_args.args[0]));
|
| 423 |
|
| 424 | fwnode_handle_put(ref_args.fwnode);
|
| 425 | fwnode_handle_put(aux_args.fwnode);
|
| 426 |
|
| 427 | if (!match)
|
| 428 | continue;
|
| 429 |
|
| 430 | |
| 431 | * Reuse the fwnode of the real device, next time we'll use it
|
| 432 | * in the normal path.
|
| 433 |
|
| 434 | ref->fwnode = fwnode_handle_get(reset_fwnode);
|
| 435 | return true;
|
| 436 | }
|
| 437 |
|
| 438 | return false;
|
| 439 | }
|
| 440 | #else
|
| 441 | static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
|
| 442 | struct gpio_shared_entry *entry,
|
| 443 | struct gpio_shared_ref *ref)
|
| 444 | {
|
| 445 | return false;
|
| 446 | }
|
| 447 | #endif
|
| 448 |
|
| 449 | int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle *fwnode,
|
| 450 | const char *con_id, unsigned long lflags)
|
| 451 | {
|
| 452 | struct gpio_shared_entry *entry;
|
| 453 | struct gpio_shared_ref *ref;
|
| 454 | const char *dev_id;
|
| 455 |
|
| 456 | if (!consumer)
|
| 457 | return -EOPNOTSUPP;
|
| 458 |
|
| 459 | dev_id = dev_name(consumer);
|
| 460 |
|
| 461 | list_for_each_entry(entry, &gpio_shared_list, list) {
|
| 462 | list_for_each_entry(ref, &entry->refs, list) {
|
| 463 | guard(mutex)(&ref->lock);
|
| 464 |
|
| 465 | if (!ref->fwnode && device_is_compatible(consumer, "reset-gpio")) {
|
| 466 | if (!gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
|
| 467 | continue;
|
| 468 | } else if (fwnode != ref->fwnode) {
|
| 469 | continue;
|
| 470 | }
|
| 471 |
|
| 472 | if ((!con_id && ref->con_id) || (con_id && !ref->con_id) ||
|
| 473 | (con_id && ref->con_id && strcmp(con_id, ref->con_id) != 0))
|
| 474 | continue;
|
| 475 |
|
| 476 |
|
| 477 | if (ref->lookup)
|
| 478 | return 0;
|
| 479 |
|
| 480 | char *key __free(kfree) =
|
| 481 | kasprintf(GFP_KERNEL,
|
| 482 | KBUILD_MODNAME ".proxy.%u",
|
| 483 | ref->adev.id);
|
| 484 | if (!key)
|
| 485 | return -ENOMEM;
|
| 486 |
|
| 487 | struct gpiod_lookup_table *lookup __free(kfree) =
|
| 488 | kzalloc_flex(*lookup, table, 2);
|
| 489 | if (!lookup)
|
| 490 | return -ENOMEM;
|
| 491 |
|
| 492 | pr_debug("Adding machine lookup entry for a shared GPIO for consumer %s, with key '%s' and con_id '%s'\n",
|
| 493 | dev_id, key, ref->con_id ?: "none");
|
| 494 |
|
| 495 | lookup->dev_id = kstrdup(dev_id, GFP_KERNEL);
|
| 496 | if (!lookup->dev_id)
|
| 497 | return -ENOMEM;
|
| 498 |
|
| 499 | lookup->table[0] = GPIO_LOOKUP(no_free_ptr(key), 0,
|
| 500 | ref->con_id, lflags);
|
| 501 |
|
| 502 | ref->lookup = no_free_ptr(lookup);
|
| 503 | gpiod_add_lookup_table(ref->lookup);
|
| 504 |
|
| 505 | return 0;
|
| 506 | }
|
| 507 | }
|
| 508 |
|
| 509 |
|
| 510 | WARN_ON(1);
|
| 511 | return -ENOENT;
|
| 512 | }
|
| 513 |
|
| 514 | static void gpio_shared_remove_adev(struct auxiliary_device *adev)
|
| 515 | {
|
| 516 | auxiliary_device_delete(adev);
|
| 517 | auxiliary_device_uninit(adev);
|
| 518 | }
|
| 519 |
|
| 520 | int gpiochip_setup_shared(struct gpio_chip *gc)
|
| 521 | {
|
| 522 | struct gpio_device *gdev = gc->gpiodev;
|
| 523 | struct gpio_shared_entry *entry;
|
| 524 | struct gpio_shared_ref *ref;
|
| 525 | struct gpio_desc *desc;
|
| 526 | int ret;
|
| 527 |
|
| 528 | list_for_each_entry(entry, &gpio_shared_list, list) {
|
| 529 | list_for_each_entry(ref, &entry->refs, list) {
|
| 530 | if (gdev->dev.parent == &ref->adev.dev) {
|
| 531 | |
| 532 | * This is a shared GPIO proxy. Mark its
|
| 533 | * descriptor as such and return here.
|
| 534 |
|
| 535 | __set_bit(GPIOD_FLAG_SHARED_PROXY,
|
| 536 | &gdev->descs[0].flags);
|
| 537 | return 0;
|
| 538 | }
|
| 539 | }
|
| 540 | }
|
| 541 |
|
| 542 | |
| 543 | * This is not a shared GPIO proxy but it still may be the device
|
| 544 | * exposing shared pins. Find them and create the proxy devices.
|
| 545 |
|
| 546 | list_for_each_entry(entry, &gpio_shared_list, list) {
|
| 547 | if (!device_match_fwnode(&gdev->dev, entry->fwnode))
|
| 548 | continue;
|
| 549 |
|
| 550 | if (list_count_nodes(&entry->refs) <= 1)
|
| 551 | continue;
|
| 552 |
|
| 553 | scoped_guard(mutex, &entry->lock) {
|
| 554 | #if IS_ENABLED(CONFIG_OF)
|
| 555 | if (is_of_node(entry->fwnode) && gc->of_xlate) {
|
| 556 | |
| 557 | * This is the earliest that we can tranlate the
|
| 558 | * devicetree offset to the chip offset.
|
| 559 |
|
| 560 | struct of_phandle_args gpiospec = { };
|
| 561 |
|
| 562 | gpiospec.np = to_of_node(entry->fwnode);
|
| 563 | gpiospec.args_count = 2;
|
| 564 | gpiospec.args[0] = entry->offset;
|
| 565 |
|
| 566 | ret = gc->of_xlate(gc, &gpiospec, NULL);
|
| 567 | if (ret < 0)
|
| 568 | return ret;
|
| 569 |
|
| 570 | entry->offset = ret;
|
| 571 | }
|
| 572 | #endif
|
| 573 |
|
| 574 | desc = &gdev->descs[entry->offset];
|
| 575 |
|
| 576 | __set_bit(GPIOD_FLAG_SHARED, &desc->flags);
|
| 577 | |
| 578 | * Shared GPIOs are not requested via the normal path. Make
|
| 579 | * them inaccessible to anyone even before we register the
|
| 580 | * chip.
|
| 581 |
|
| 582 | ret = gpiod_request_commit(desc, "shared");
|
| 583 | if (ret)
|
| 584 | return ret;
|
| 585 |
|
| 586 | pr_debug("GPIO %u owned by %s is shared by multiple consumers\n",
|
| 587 | entry->offset, gpio_device_get_label(gdev));
|
| 588 | }
|
| 589 |
|
| 590 | list_for_each_entry(ref, &entry->refs, list) {
|
| 591 | pr_debug("Setting up a shared GPIO entry for %s (con_id: '%s')\n",
|
| 592 | fwnode_get_name(ref->fwnode) ?: "(no fwnode)",
|
| 593 | ref->con_id ?: "(none)");
|
| 594 |
|
| 595 | ret = gpio_shared_make_adev(gdev, entry, ref);
|
| 596 | if (ret) {
|
| 597 | gpiod_free_commit(desc);
|
| 598 | return ret;
|
| 599 | }
|
| 600 | }
|
| 601 | }
|
| 602 |
|
| 603 | return 0;
|
| 604 | }
|
| 605 |
|
| 606 | void gpio_device_teardown_shared(struct gpio_device *gdev)
|
| 607 | {
|
| 608 | struct gpio_shared_entry *entry;
|
| 609 | struct gpio_shared_ref *ref;
|
| 610 |
|
| 611 | list_for_each_entry(entry, &gpio_shared_list, list) {
|
| 612 | if (!device_match_fwnode(&gdev->dev, entry->fwnode))
|
| 613 | continue;
|
| 614 |
|
| 615 | scoped_guard(mutex, &entry->lock)
|
| 616 | gpiod_free_commit(&gdev->descs[entry->offset]);
|
| 617 |
|
| 618 | list_for_each_entry(ref, &entry->refs, list) {
|
| 619 | if (ref->lookup) {
|
| 620 | gpiod_remove_lookup_table(ref->lookup);
|
| 621 | kfree(ref->lookup->table[0].key);
|
| 622 | kfree(ref->lookup->dev_id);
|
| 623 | kfree(ref->lookup);
|
| 624 | ref->lookup = NULL;
|
| 625 | }
|
| 626 |
|
| 627 | gpio_shared_remove_adev(&ref->adev);
|
| 628 | }
|
| 629 | }
|
| 630 | }
|
| 631 |
|
| 632 | static void gpio_shared_release(struct kref *kref)
|
| 633 | {
|
| 634 | struct gpio_shared_entry *entry =
|
| 635 | container_of(kref, struct gpio_shared_entry, ref);
|
| 636 | struct gpio_shared_desc *shared_desc;
|
| 637 |
|
| 638 | guard(mutex)(&entry->lock);
|
| 639 |
|
| 640 | shared_desc = entry->shared_desc;
|
| 641 | gpio_device_put(shared_desc->desc->gdev);
|
| 642 | mutex_destroy(&shared_desc->mutex);
|
| 643 | kfree(shared_desc);
|
| 644 | entry->shared_desc = NULL;
|
| 645 | }
|
| 646 |
|
| 647 | static void gpiod_shared_put(void *data)
|
| 648 | {
|
| 649 | struct gpio_shared_entry *entry = data;
|
| 650 |
|
| 651 | kref_put(&entry->ref, gpio_shared_release);
|
| 652 | }
|
| 653 |
|
| 654 | static struct gpio_shared_desc *
|
| 655 | gpiod_shared_desc_create(struct gpio_shared_entry *entry)
|
| 656 | {
|
| 657 | struct gpio_shared_desc *shared_desc;
|
| 658 | struct gpio_device *gdev;
|
| 659 |
|
| 660 | lockdep_assert_held(&entry->lock);
|
| 661 |
|
| 662 | shared_desc = kzalloc_obj(*shared_desc);
|
| 663 | if (!shared_desc)
|
| 664 | return ERR_PTR(-ENOMEM);
|
| 665 |
|
| 666 | gdev = gpio_device_find_by_fwnode(entry->fwnode);
|
| 667 | if (!gdev) {
|
| 668 | kfree(shared_desc);
|
| 669 | return ERR_PTR(-EPROBE_DEFER);
|
| 670 | }
|
| 671 |
|
| 672 | shared_desc->desc = &gdev->descs[entry->offset];
|
| 673 | mutex_init(&shared_desc->mutex);
|
| 674 |
|
| 675 | return shared_desc;
|
| 676 | }
|
| 677 |
|
| 678 | struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev)
|
| 679 | {
|
| 680 | struct gpio_shared_desc *shared_desc;
|
| 681 | struct gpio_shared_entry *entry;
|
| 682 | int ret;
|
| 683 |
|
| 684 | entry = dev_get_platdata(dev);
|
| 685 | if (WARN_ON(!entry))
|
| 686 |
|
| 687 | return ERR_PTR(-ENOENT);
|
| 688 |
|
| 689 | scoped_guard(mutex, &entry->lock) {
|
| 690 | if (entry->shared_desc) {
|
| 691 | kref_get(&entry->ref);
|
| 692 | shared_desc = entry->shared_desc;
|
| 693 | } else {
|
| 694 | shared_desc = gpiod_shared_desc_create(entry);
|
| 695 | if (IS_ERR(shared_desc))
|
| 696 | return ERR_CAST(shared_desc);
|
| 697 |
|
| 698 | kref_init(&entry->ref);
|
| 699 | entry->shared_desc = shared_desc;
|
| 700 | }
|
| 701 |
|
| 702 | pr_debug("Device %s acquired a reference to the shared GPIO %u owned by %s\n",
|
| 703 | dev_name(dev), gpiod_hwgpio(shared_desc->desc),
|
| 704 | gpio_device_get_label(shared_desc->desc->gdev));
|
| 705 | }
|
| 706 |
|
| 707 | ret = devm_add_action_or_reset(dev, gpiod_shared_put, entry);
|
| 708 | if (ret)
|
| 709 | return ERR_PTR(ret);
|
| 710 |
|
| 711 | return shared_desc;
|
| 712 | }
|
| 713 | EXPORT_SYMBOL_GPL(devm_gpiod_shared_get);
|
| 714 |
|
| 715 | static void gpio_shared_drop_ref(struct gpio_shared_ref *ref)
|
| 716 | {
|
| 717 | list_del(&ref->list);
|
| 718 | mutex_destroy(&ref->lock);
|
| 719 | lockdep_unregister_key(&ref->lock_key);
|
| 720 | kfree(ref->con_id);
|
| 721 | ida_free(&gpio_shared_ida, ref->dev_id);
|
| 722 | fwnode_handle_put(ref->fwnode);
|
| 723 | kfree(ref);
|
| 724 | }
|
| 725 |
|
| 726 | static void gpio_shared_drop_entry(struct gpio_shared_entry *entry)
|
| 727 | {
|
| 728 | list_del(&entry->list);
|
| 729 | mutex_destroy(&entry->lock);
|
| 730 | fwnode_handle_put(entry->fwnode);
|
| 731 | kfree(entry);
|
| 732 | }
|
| 733 |
|
| 734 | |
| 735 | * This is only called if gpio_shared_init() fails so it's in fact __init and
|
| 736 | * not __exit.
|
| 737 |
|
| 738 | static void __init gpio_shared_teardown(void)
|
| 739 | {
|
| 740 | struct gpio_shared_entry *entry, *epos;
|
| 741 | struct gpio_shared_ref *ref, *rpos;
|
| 742 |
|
| 743 | list_for_each_entry_safe(entry, epos, &gpio_shared_list, list) {
|
| 744 | list_for_each_entry_safe(ref, rpos, &entry->refs, list)
|
| 745 | gpio_shared_drop_ref(ref);
|
| 746 |
|
| 747 | gpio_shared_drop_entry(entry);
|
| 748 | }
|
| 749 | }
|
| 750 |
|
| 751 | static bool gpio_shared_entry_is_really_shared(struct gpio_shared_entry *entry)
|
| 752 | {
|
| 753 | size_t num_nodes = list_count_nodes(&entry->refs);
|
| 754 | struct gpio_shared_ref *ref;
|
| 755 |
|
| 756 | if (num_nodes <= 1)
|
| 757 | return false;
|
| 758 |
|
| 759 | if (num_nodes > 2)
|
| 760 | return true;
|
| 761 |
|
| 762 |
|
| 763 | list_for_each_entry(ref, &entry->refs, list) {
|
| 764 | |
| 765 | * Corner-case: the second reference comes from the potential
|
| 766 | * reset-gpio instance. However, this pin is not really shared
|
| 767 | * as it would have three references in this case. Avoid
|
| 768 | * creating unnecessary proxies.
|
| 769 |
|
| 770 | if (ref->is_reset_gpio)
|
| 771 | return false;
|
| 772 | }
|
| 773 |
|
| 774 | return true;
|
| 775 | }
|
| 776 |
|
| 777 | static void gpio_shared_free_exclusive(void)
|
| 778 | {
|
| 779 | struct gpio_shared_entry *entry, *epos;
|
| 780 | struct gpio_shared_ref *ref, *rpos;
|
| 781 |
|
| 782 | list_for_each_entry_safe(entry, epos, &gpio_shared_list, list) {
|
| 783 | if (gpio_shared_entry_is_really_shared(entry))
|
| 784 | continue;
|
| 785 |
|
| 786 | list_for_each_entry_safe(ref, rpos, &entry->refs, list)
|
| 787 | gpio_shared_drop_ref(ref);
|
| 788 | gpio_shared_drop_entry(entry);
|
| 789 | }
|
| 790 | }
|
| 791 |
|
| 792 | static int __init gpio_shared_init(void)
|
| 793 | {
|
| 794 | int ret;
|
| 795 |
|
| 796 |
|
| 797 | ret = gpio_shared_of_scan();
|
| 798 | if (ret) {
|
| 799 | gpio_shared_teardown();
|
| 800 | pr_err("Failed to scan OF nodes for shared GPIOs: %d\n", ret);
|
| 801 | return ret;
|
| 802 | }
|
| 803 |
|
| 804 | gpio_shared_free_exclusive();
|
| 805 |
|
| 806 | pr_debug("Finished scanning firmware nodes for shared GPIOs\n");
|
| 807 | return 0;
|
| 808 | }
|
| 809 | postcore_initcall(gpio_shared_init);
|