diff options
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 584d2b465f84..f41cb4f3d715 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -1254,6 +1254,9 @@ fail: | |||
1254 | } | 1254 | } |
1255 | EXPORT_SYMBOL_GPL(gpiochip_add); | 1255 | EXPORT_SYMBOL_GPL(gpiochip_add); |
1256 | 1256 | ||
1257 | /* Forward-declaration */ | ||
1258 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); | ||
1259 | |||
1257 | /** | 1260 | /** |
1258 | * gpiochip_remove() - unregister a gpio_chip | 1261 | * gpiochip_remove() - unregister a gpio_chip |
1259 | * @chip: the chip to unregister | 1262 | * @chip: the chip to unregister |
@@ -1270,6 +1273,7 @@ int gpiochip_remove(struct gpio_chip *chip) | |||
1270 | 1273 | ||
1271 | spin_lock_irqsave(&gpio_lock, flags); | 1274 | spin_lock_irqsave(&gpio_lock, flags); |
1272 | 1275 | ||
1276 | gpiochip_irqchip_remove(chip); | ||
1273 | gpiochip_remove_pin_ranges(chip); | 1277 | gpiochip_remove_pin_ranges(chip); |
1274 | of_gpiochip_remove(chip); | 1278 | of_gpiochip_remove(chip); |
1275 | 1279 | ||
@@ -1339,6 +1343,190 @@ static struct gpio_chip *find_chip_by_name(const char *name) | |||
1339 | return gpiochip_find((void *)name, gpiochip_match_name); | 1343 | return gpiochip_find((void *)name, gpiochip_match_name); |
1340 | } | 1344 | } |
1341 | 1345 | ||
1346 | #ifdef CONFIG_GPIOLIB_IRQCHIP | ||
1347 | |||
1348 | /* | ||
1349 | * The following is irqchip helper code for gpiochips. | ||
1350 | */ | ||
1351 | |||
1352 | /** | ||
1353 | * gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip | ||
1354 | * @gpiochip: the gpiochip to add the irqchip to | ||
1355 | * @irqchip: the irqchip to add to the gpiochip | ||
1356 | * @parent_irq: the irq number corresponding to the parent IRQ for this | ||
1357 | * chained irqchip | ||
1358 | * @parent_handler: the parent interrupt handler for the accumulated IRQ | ||
1359 | * coming out of the gpiochip | ||
1360 | */ | ||
1361 | void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, | ||
1362 | struct irq_chip *irqchip, | ||
1363 | int parent_irq, | ||
1364 | irq_flow_handler_t parent_handler) | ||
1365 | { | ||
1366 | irq_set_chained_handler(parent_irq, parent_handler); | ||
1367 | /* | ||
1368 | * The parent irqchip is already using the chip_data for this | ||
1369 | * irqchip, so our callbacks simply use the handler_data. | ||
1370 | */ | ||
1371 | irq_set_handler_data(parent_irq, gpiochip); | ||
1372 | } | ||
1373 | EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); | ||
1374 | |||
1375 | /** | ||
1376 | * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip | ||
1377 | * @d: the irqdomain used by this irqchip | ||
1378 | * @irq: the global irq number used by this GPIO irqchip irq | ||
1379 | * @hwirq: the local IRQ/GPIO line offset on this gpiochip | ||
1380 | * | ||
1381 | * This function will set up the mapping for a certain IRQ line on a | ||
1382 | * gpiochip by assigning the gpiochip as chip data, and using the irqchip | ||
1383 | * stored inside the gpiochip. | ||
1384 | */ | ||
1385 | static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, | ||
1386 | irq_hw_number_t hwirq) | ||
1387 | { | ||
1388 | struct gpio_chip *chip = d->host_data; | ||
1389 | |||
1390 | irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); | ||
1391 | irq_set_chip_data(irq, chip); | ||
1392 | #ifdef CONFIG_ARM | ||
1393 | set_irq_flags(irq, IRQF_VALID); | ||
1394 | #else | ||
1395 | irq_set_noprobe(irq); | ||
1396 | #endif | ||
1397 | irq_set_irq_type(irq, chip->irq_default_type); | ||
1398 | |||
1399 | return 0; | ||
1400 | } | ||
1401 | |||
1402 | static const struct irq_domain_ops gpiochip_domain_ops = { | ||
1403 | .map = gpiochip_irq_map, | ||
1404 | /* Virtually all GPIO irqchips are twocell:ed */ | ||
1405 | .xlate = irq_domain_xlate_twocell, | ||
1406 | }; | ||
1407 | |||
1408 | static int gpiochip_irq_reqres(struct irq_data *d) | ||
1409 | { | ||
1410 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d); | ||
1411 | |||
1412 | if (gpio_lock_as_irq(chip, d->hwirq)) { | ||
1413 | chip_err(chip, | ||
1414 | "unable to lock HW IRQ %lu for IRQ\n", | ||
1415 | d->hwirq); | ||
1416 | return -EINVAL; | ||
1417 | } | ||
1418 | return 0; | ||
1419 | } | ||
1420 | |||
1421 | static void gpiochip_irq_relres(struct irq_data *d) | ||
1422 | { | ||
1423 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d); | ||
1424 | |||
1425 | gpio_unlock_as_irq(chip, d->hwirq); | ||
1426 | } | ||
1427 | |||
1428 | static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) | ||
1429 | { | ||
1430 | return irq_find_mapping(chip->irqdomain, offset); | ||
1431 | } | ||
1432 | |||
1433 | /** | ||
1434 | * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip | ||
1435 | * @gpiochip: the gpiochip to remove the irqchip from | ||
1436 | * | ||
1437 | * This is called only from gpiochip_remove() | ||
1438 | */ | ||
1439 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) | ||
1440 | { | ||
1441 | if (gpiochip->irqdomain) | ||
1442 | irq_domain_remove(gpiochip->irqdomain); | ||
1443 | |||
1444 | if (gpiochip->irqchip) { | ||
1445 | gpiochip->irqchip->irq_request_resources = NULL; | ||
1446 | gpiochip->irqchip->irq_release_resources = NULL; | ||
1447 | gpiochip->irqchip = NULL; | ||
1448 | } | ||
1449 | } | ||
1450 | |||
1451 | /** | ||
1452 | * gpiochip_irqchip_add() - adds an irqchip to a gpiochip | ||
1453 | * @gpiochip: the gpiochip to add the irqchip to | ||
1454 | * @irqchip: the irqchip to add to the gpiochip | ||
1455 | * @first_irq: if not dynamically assigned, the base (first) IRQ to | ||
1456 | * allocate gpiochip irqs from | ||
1457 | * @handler: the irq handler to use (often a predefined irq core function) | ||
1458 | * @type: the default type for IRQs on this irqchip | ||
1459 | * | ||
1460 | * This function closely associates a certain irqchip with a certain | ||
1461 | * gpiochip, providing an irq domain to translate the local IRQs to | ||
1462 | * global irqs in the gpiolib core, and making sure that the gpiochip | ||
1463 | * is passed as chip data to all related functions. Driver callbacks | ||
1464 | * need to use container_of() to get their local state containers back | ||
1465 | * from the gpiochip passed as chip data. An irqdomain will be stored | ||
1466 | * in the gpiochip that shall be used by the driver to handle IRQ number | ||
1467 | * translation. The gpiochip will need to be initialized and registered | ||
1468 | * before calling this function. | ||
1469 | * | ||
1470 | * This function will handle two cell:ed simple IRQs. Everything else | ||
1471 | * need to be open coded. | ||
1472 | */ | ||
1473 | int gpiochip_irqchip_add(struct gpio_chip *gpiochip, | ||
1474 | struct irq_chip *irqchip, | ||
1475 | unsigned int first_irq, | ||
1476 | irq_flow_handler_t handler, | ||
1477 | unsigned int type) | ||
1478 | { | ||
1479 | struct device_node *of_node; | ||
1480 | unsigned int offset; | ||
1481 | |||
1482 | if (!gpiochip || !irqchip) | ||
1483 | return -EINVAL; | ||
1484 | |||
1485 | if (!gpiochip->dev) { | ||
1486 | pr_err("missing gpiochip .dev parent pointer\n"); | ||
1487 | return -EINVAL; | ||
1488 | } | ||
1489 | of_node = gpiochip->dev->of_node; | ||
1490 | #ifdef CONFIG_OF_GPIO | ||
1491 | /* | ||
1492 | * If the gpiochip has an assigned OF node this takes precendence | ||
1493 | * FIXME: get rid of this and use gpiochip->dev->of_node everywhere | ||
1494 | */ | ||
1495 | if (gpiochip->of_node) | ||
1496 | of_node = gpiochip->of_node; | ||
1497 | #endif | ||
1498 | gpiochip->irqchip = irqchip; | ||
1499 | gpiochip->irq_handler = handler; | ||
1500 | gpiochip->irq_default_type = type; | ||
1501 | gpiochip->to_irq = gpiochip_to_irq; | ||
1502 | gpiochip->irqdomain = irq_domain_add_simple(of_node, | ||
1503 | gpiochip->ngpio, first_irq, | ||
1504 | &gpiochip_domain_ops, gpiochip); | ||
1505 | if (!gpiochip->irqdomain) { | ||
1506 | gpiochip->irqchip = NULL; | ||
1507 | return -EINVAL; | ||
1508 | } | ||
1509 | irqchip->irq_request_resources = gpiochip_irq_reqres; | ||
1510 | irqchip->irq_release_resources = gpiochip_irq_relres; | ||
1511 | |||
1512 | /* | ||
1513 | * Prepare the mapping since the irqchip shall be orthogonal to | ||
1514 | * any gpiochip calls. If the first_irq was zero, this is | ||
1515 | * necessary to allocate descriptors for all IRQs. | ||
1516 | */ | ||
1517 | for (offset = 0; offset < gpiochip->ngpio; offset++) | ||
1518 | irq_create_mapping(gpiochip->irqdomain, offset); | ||
1519 | |||
1520 | return 0; | ||
1521 | } | ||
1522 | EXPORT_SYMBOL_GPL(gpiochip_irqchip_add); | ||
1523 | |||
1524 | #else /* CONFIG_GPIOLIB_IRQCHIP */ | ||
1525 | |||
1526 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} | ||
1527 | |||
1528 | #endif /* CONFIG_GPIOLIB_IRQCHIP */ | ||
1529 | |||
1342 | #ifdef CONFIG_PINCTRL | 1530 | #ifdef CONFIG_PINCTRL |
1343 | 1531 | ||
1344 | /** | 1532 | /** |