| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Intel Merrifield SoC GPIO driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2016 Intel Corporation. |
|---|
| 5 | 6 | * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 8 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 9 | | - * published by the Free Software Foundation. |
|---|
| 10 | 7 | */ |
|---|
| 11 | 8 | |
|---|
| 12 | 9 | #include <linux/acpi.h> |
|---|
| 13 | 10 | #include <linux/bitops.h> |
|---|
| 14 | 11 | #include <linux/gpio/driver.h> |
|---|
| 15 | | -#include <linux/init.h> |
|---|
| 16 | 12 | #include <linux/interrupt.h> |
|---|
| 17 | 13 | #include <linux/io.h> |
|---|
| 18 | 14 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 166 | 162 | { |
|---|
| 167 | 163 | void __iomem *gpdr = gpio_reg(chip, offset, GPDR); |
|---|
| 168 | 164 | |
|---|
| 169 | | - return !(readl(gpdr) & BIT(offset % 32)); |
|---|
| 165 | + if (readl(gpdr) & BIT(offset % 32)) |
|---|
| 166 | + return GPIO_LINE_DIRECTION_OUT; |
|---|
| 167 | + |
|---|
| 168 | + return GPIO_LINE_DIRECTION_IN; |
|---|
| 170 | 169 | } |
|---|
| 171 | 170 | |
|---|
| 172 | 171 | static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, |
|---|
| .. | .. |
|---|
| 366 | 365 | chained_irq_exit(irqchip, desc); |
|---|
| 367 | 366 | } |
|---|
| 368 | 367 | |
|---|
| 369 | | -static void mrfld_irq_init_hw(struct mrfld_gpio *priv) |
|---|
| 368 | +static int mrfld_irq_init_hw(struct gpio_chip *chip) |
|---|
| 370 | 369 | { |
|---|
| 370 | + struct mrfld_gpio *priv = gpiochip_get_data(chip); |
|---|
| 371 | 371 | void __iomem *reg; |
|---|
| 372 | 372 | unsigned int base; |
|---|
| 373 | 373 | |
|---|
| .. | .. |
|---|
| 379 | 379 | reg = gpio_reg(&priv->chip, base, GFER); |
|---|
| 380 | 380 | writel(0, reg); |
|---|
| 381 | 381 | } |
|---|
| 382 | + |
|---|
| 383 | + return 0; |
|---|
| 382 | 384 | } |
|---|
| 383 | 385 | |
|---|
| 384 | | -static const char *mrfld_gpio_get_pinctrl_dev_name(void) |
|---|
| 386 | +static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv) |
|---|
| 385 | 387 | { |
|---|
| 386 | | - const char *dev_name = acpi_dev_get_first_match_name("INTC1002", NULL, -1); |
|---|
| 387 | | - return dev_name ? dev_name : "pinctrl-merrifield"; |
|---|
| 388 | + struct acpi_device *adev; |
|---|
| 389 | + const char *name; |
|---|
| 390 | + |
|---|
| 391 | + adev = acpi_dev_get_first_match_dev("INTC1002", NULL, -1); |
|---|
| 392 | + if (adev) { |
|---|
| 393 | + name = devm_kstrdup(priv->dev, acpi_dev_name(adev), GFP_KERNEL); |
|---|
| 394 | + acpi_dev_put(adev); |
|---|
| 395 | + } else { |
|---|
| 396 | + name = "pinctrl-merrifield"; |
|---|
| 397 | + } |
|---|
| 398 | + |
|---|
| 399 | + return name; |
|---|
| 400 | +} |
|---|
| 401 | + |
|---|
| 402 | +static int mrfld_gpio_add_pin_ranges(struct gpio_chip *chip) |
|---|
| 403 | +{ |
|---|
| 404 | + struct mrfld_gpio *priv = gpiochip_get_data(chip); |
|---|
| 405 | + const struct mrfld_gpio_pinrange *range; |
|---|
| 406 | + const char *pinctrl_dev_name; |
|---|
| 407 | + unsigned int i; |
|---|
| 408 | + int retval; |
|---|
| 409 | + |
|---|
| 410 | + pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv); |
|---|
| 411 | + for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { |
|---|
| 412 | + range = &mrfld_gpio_ranges[i]; |
|---|
| 413 | + retval = gpiochip_add_pin_range(&priv->chip, pinctrl_dev_name, |
|---|
| 414 | + range->gpio_base, |
|---|
| 415 | + range->pin_base, |
|---|
| 416 | + range->npins); |
|---|
| 417 | + if (retval) { |
|---|
| 418 | + dev_err(priv->dev, "failed to add GPIO pin range\n"); |
|---|
| 419 | + return retval; |
|---|
| 420 | + } |
|---|
| 421 | + } |
|---|
| 422 | + |
|---|
| 423 | + return 0; |
|---|
| 388 | 424 | } |
|---|
| 389 | 425 | |
|---|
| 390 | 426 | static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
|---|
| 391 | 427 | { |
|---|
| 392 | | - const struct mrfld_gpio_pinrange *range; |
|---|
| 393 | | - const char *pinctrl_dev_name; |
|---|
| 428 | + struct gpio_irq_chip *girq; |
|---|
| 394 | 429 | struct mrfld_gpio *priv; |
|---|
| 395 | 430 | u32 gpio_base, irq_base; |
|---|
| 396 | 431 | void __iomem *base; |
|---|
| 397 | | - unsigned int i; |
|---|
| 398 | 432 | int retval; |
|---|
| 399 | 433 | |
|---|
| 400 | 434 | retval = pcim_enable_device(pdev); |
|---|
| .. | .. |
|---|
| 409 | 443 | |
|---|
| 410 | 444 | base = pcim_iomap_table(pdev)[1]; |
|---|
| 411 | 445 | |
|---|
| 412 | | - irq_base = readl(base); |
|---|
| 413 | | - gpio_base = readl(sizeof(u32) + base); |
|---|
| 446 | + irq_base = readl(base + 0 * sizeof(u32)); |
|---|
| 447 | + gpio_base = readl(base + 1 * sizeof(u32)); |
|---|
| 414 | 448 | |
|---|
| 415 | 449 | /* Release the IO mapping, since we already get the info from BAR1 */ |
|---|
| 416 | 450 | pcim_iounmap_regions(pdev, BIT(1)); |
|---|
| .. | .. |
|---|
| 435 | 469 | priv->chip.base = gpio_base; |
|---|
| 436 | 470 | priv->chip.ngpio = MRFLD_NGPIO; |
|---|
| 437 | 471 | priv->chip.can_sleep = false; |
|---|
| 472 | + priv->chip.add_pin_ranges = mrfld_gpio_add_pin_ranges; |
|---|
| 438 | 473 | |
|---|
| 439 | 474 | raw_spin_lock_init(&priv->lock); |
|---|
| 440 | 475 | |
|---|
| 441 | | - pci_set_drvdata(pdev, priv); |
|---|
| 476 | + retval = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); |
|---|
| 477 | + if (retval < 0) |
|---|
| 478 | + return retval; |
|---|
| 479 | + |
|---|
| 480 | + girq = &priv->chip.irq; |
|---|
| 481 | + girq->chip = &mrfld_irqchip; |
|---|
| 482 | + girq->init_hw = mrfld_irq_init_hw; |
|---|
| 483 | + girq->parent_handler = mrfld_irq_handler; |
|---|
| 484 | + girq->num_parents = 1; |
|---|
| 485 | + girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, |
|---|
| 486 | + sizeof(*girq->parents), GFP_KERNEL); |
|---|
| 487 | + if (!girq->parents) |
|---|
| 488 | + return -ENOMEM; |
|---|
| 489 | + girq->parents[0] = pci_irq_vector(pdev, 0); |
|---|
| 490 | + girq->first = irq_base; |
|---|
| 491 | + girq->default_type = IRQ_TYPE_NONE; |
|---|
| 492 | + girq->handler = handle_bad_irq; |
|---|
| 493 | + |
|---|
| 442 | 494 | retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); |
|---|
| 443 | 495 | if (retval) { |
|---|
| 444 | 496 | dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); |
|---|
| 445 | 497 | return retval; |
|---|
| 446 | 498 | } |
|---|
| 447 | 499 | |
|---|
| 448 | | - pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(); |
|---|
| 449 | | - for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { |
|---|
| 450 | | - range = &mrfld_gpio_ranges[i]; |
|---|
| 451 | | - retval = gpiochip_add_pin_range(&priv->chip, |
|---|
| 452 | | - pinctrl_dev_name, |
|---|
| 453 | | - range->gpio_base, |
|---|
| 454 | | - range->pin_base, |
|---|
| 455 | | - range->npins); |
|---|
| 456 | | - if (retval) { |
|---|
| 457 | | - dev_err(&pdev->dev, "failed to add GPIO pin range\n"); |
|---|
| 458 | | - return retval; |
|---|
| 459 | | - } |
|---|
| 460 | | - } |
|---|
| 461 | | - |
|---|
| 462 | | - retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base, |
|---|
| 463 | | - handle_bad_irq, IRQ_TYPE_NONE); |
|---|
| 464 | | - if (retval) { |
|---|
| 465 | | - dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); |
|---|
| 466 | | - return retval; |
|---|
| 467 | | - } |
|---|
| 468 | | - |
|---|
| 469 | | - mrfld_irq_init_hw(priv); |
|---|
| 470 | | - |
|---|
| 471 | | - gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq, |
|---|
| 472 | | - mrfld_irq_handler); |
|---|
| 473 | | - |
|---|
| 500 | + pci_set_drvdata(pdev, priv); |
|---|
| 474 | 501 | return 0; |
|---|
| 475 | 502 | } |
|---|
| 476 | 503 | |
|---|