aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Smirnov <andrew.smirnov@gmail.com>2017-03-28 11:42:50 -0400
committerBjorn Helgaas <bhelgaas@google.com>2017-04-04 18:54:21 -0400
commitbde4a5a00e761f55be92f62378cf5024ced79ee3 (patch)
tree43ad74ab81da00a4bd69d3e3dad521ff1806aa20
parent9b3fe6796d7c0e0c2b87243ce0c7f4744c54efad (diff)
PCI: imx6: Allow probe deferral by reset GPIO
Some designs implement reset GPIO via a GPIO expander connected to a peripheral bus. One such example would be i.MX7 Sabre board where said GPIO is provided by SPI shift register connected to a bitbanged SPI bus. To support such designs, allow reset GPIO request to defer probing of the driver. Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Lucas Stach <l.stach@pengutronix.de> Cc: yurovsky@gmail.com Cc: Fabio Estevam <fabio.estevam@nxp.com> Cc: Dong Aisheng <dongas86@gmail.com> Cc: linux-arm-kernel@lists.infradead.org
-rw-r--r--drivers/pci/dwc/pci-imx6.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c
index e0c36d6f5a21..d62ee3553cfe 100644
--- a/drivers/pci/dwc/pci-imx6.c
+++ b/drivers/pci/dwc/pci-imx6.c
@@ -595,8 +595,8 @@ static struct dw_pcie_host_ops imx6_pcie_host_ops = {
595 .host_init = imx6_pcie_host_init, 595 .host_init = imx6_pcie_host_init,
596}; 596};
597 597
598static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, 598static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
599 struct platform_device *pdev) 599 struct platform_device *pdev)
600{ 600{
601 struct dw_pcie *pci = imx6_pcie->pci; 601 struct dw_pcie *pci = imx6_pcie->pci;
602 struct pcie_port *pp = &pci->pp; 602 struct pcie_port *pp = &pci->pp;
@@ -636,7 +636,7 @@ static const struct dw_pcie_ops dw_pcie_ops = {
636 .link_up = imx6_pcie_link_up, 636 .link_up = imx6_pcie_link_up,
637}; 637};
638 638
639static int __init imx6_pcie_probe(struct platform_device *pdev) 639static int imx6_pcie_probe(struct platform_device *pdev)
640{ 640{
641 struct device *dev = &pdev->dev; 641 struct device *dev = &pdev->dev;
642 struct dw_pcie *pci; 642 struct dw_pcie *pci;
@@ -660,10 +660,6 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
660 imx6_pcie->variant = 660 imx6_pcie->variant =
661 (enum imx6_pcie_variants)of_device_get_match_data(dev); 661 (enum imx6_pcie_variants)of_device_get_match_data(dev);
662 662
663 /* Added for PCI abort handling */
664 hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0,
665 "imprecise external abort");
666
667 dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); 663 dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
668 pci->dbi_base = devm_ioremap_resource(dev, dbi_base); 664 pci->dbi_base = devm_ioremap_resource(dev, dbi_base);
669 if (IS_ERR(pci->dbi_base)) 665 if (IS_ERR(pci->dbi_base))
@@ -683,6 +679,8 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
683 dev_err(dev, "unable to get reset gpio\n"); 679 dev_err(dev, "unable to get reset gpio\n");
684 return ret; 680 return ret;
685 } 681 }
682 } else if (imx6_pcie->reset_gpio == -EPROBE_DEFER) {
683 return imx6_pcie->reset_gpio;
686 } 684 }
687 685
688 /* Fetch clocks */ 686 /* Fetch clocks */
@@ -796,11 +794,22 @@ static struct platform_driver imx6_pcie_driver = {
796 .name = "imx6q-pcie", 794 .name = "imx6q-pcie",
797 .of_match_table = imx6_pcie_of_match, 795 .of_match_table = imx6_pcie_of_match,
798 }, 796 },
797 .probe = imx6_pcie_probe,
799 .shutdown = imx6_pcie_shutdown, 798 .shutdown = imx6_pcie_shutdown,
800}; 799};
801 800
802static int __init imx6_pcie_init(void) 801static int __init imx6_pcie_init(void)
803{ 802{
804 return platform_driver_probe(&imx6_pcie_driver, imx6_pcie_probe); 803 /*
804 * Since probe() can be deferred we need to make sure that
805 * hook_fault_code is not called after __init memory is freed
806 * by kernel and since imx6q_pcie_abort_handler() is a no-op,
807 * we can install the handler here without risking it
808 * accessing some uninitialized driver state.
809 */
810 hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0,
811 "imprecise external abort");
812
813 return platform_driver_register(&imx6_pcie_driver);
805} 814}
806device_initcall(imx6_pcie_init); 815device_initcall(imx6_pcie_init);