summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorJaehoon Chung <jh80.chung@samsung.com>2015-03-25 16:36:20 +0900
committerSeung-Woo Kim <sw0312.kim@samsung.com>2016-12-14 13:44:33 +0900
commitecbb3455a80e69109577bde1194356c3ac434962 (patch)
treee8b35174da0ca7e0868f2c1d8e972eb987a717dc /drivers/pci
parentbb27d58f6012f3308d1ae8de05a24b39e1124b5d (diff)
local/pci: pci-exynos5433: add host controller driver for exynos5433
To support exynos5433 added the pci-exynos5433.c file.(WIP) Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/host/pci-exynos5433.c571
1 files changed, 571 insertions, 0 deletions
diff --git a/drivers/pci/host/pci-exynos5433.c b/drivers/pci/host/pci-exynos5433.c
new file mode 100644
index 000000000000..31b3e1537061
--- /dev/null
+++ b/drivers/pci/host/pci-exynos5433.c
@@ -0,0 +1,571 @@
+/*
+ * PCIe host controller driver for Samsung EXYNOS5433 SoCs
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/mfd/syscon.h>
+
+#include "pcie-designware.h"
+
+#define to_exynos_pcie(x) container_of(x, struct exynos_pcie, pp)
+
+enum pcie_exynos_type {
+ PCIE_TYPE_EXYNOS5433,
+};
+
+static struct pcie_exynos_compatible {
+ char *compatible;
+ enum pcie_exynos_type ctrl_type;
+} exynos_compat[] = {
+ {
+ .compatible = "samsung,exynos5433-pcie",
+ .ctrl_type = PCIE_TYPE_EXYNOS5433,
+ },
+};
+
+/* Pcie structure for Exynos specific data */
+struct exynos_pcie {
+ void __iomem *elbi_base;
+ void __iomem *phy_base;
+ void __iomem *block_base;
+ int reset_gpio;
+ int perst_gpio;
+ struct clk *clk;
+ struct clk *bus_clk;
+ struct pcie_port pp;
+ struct regmap *pmureg;
+};
+
+/* PCIe ELBI registers */
+#define PCIE_IRQ_PULSE 0x000
+#define IRQ_INTA_ASSERT BIT(0)
+#define IRQ_INTB_ASSERT BIT(2)
+#define IRQ_INTC_ASSERT BIT(4)
+#define IRQ_INTD_ASSERT BIT(6)
+#define IRQ_RADM_PM_TO_ACK BIT(18)
+#define PCIE_IRQ_LEVEL 0x004
+#define PCIE_IRQ_SPECIAL 0x008
+#define PCIE_IRQ_EN_PULSE 0x00c
+#define PCIE_IRQ_EN_LEVEL 0x010
+#define IRQ_MSI_ENABLE BIT(2)
+#define PCIE_IRQ_EN_SPECIAL 0x014
+#define PCIE_SW_WAKE 0x018
+#define PCIE_APP_INIT_RESET 0x028
+#define PCIE_APP_LTSSM_ENABLE 0x02c
+#define PCIE_ELBI_LTSSM_DISABLE 0x0
+#define PCIE_ELBI_LTSSM_ENABLE 0x1
+#define PCIE_L1_BUG_FIX_ENABLE 0x038
+#define PCIE_APP_REQ_EXIT_L1 0x040
+#define PCIE_APPS_PM_XMT_TURNOFF 0x04c
+#define PCIE_ELBI_RDLH_LINKUP 0x074
+#define PCIE_AUX_PM_EN 0x0A4
+#define AUX_PM_DISABLE 0x0
+#define AUX_PM_ENABLE 0x1
+#define PCIE_ELBI_SLV_AWMISC 0x11c
+#define PCIE_ELBI_SLV_ARMISC 0x120
+#define PCIE_ELBI_SLV_DBI_ENABLE BIT(21)
+
+/* Workaround : PMU phy register offset */
+#define PCIE_PMU_PHY_OFFSET 0x730
+
+/* Workaround : Sysreg Fsys register offset and bit */
+#define PCIE_PHY_MAC_RESET 0x208
+#define PCIE_MAC_RESET BIT(4)
+#define PCIE_L1SUB_CM_CON 0x1010
+#define PCIE_REFCLK_GATING_EN BIT(0)
+#define PCIE_PHY_COMMON_RESET 0x1020
+#define PCIE_PHY_RESET BIT(0)
+#define PCIE_PHY_GLOBAL_RESET 0x1040
+#define PCIE_GLOBAL_RESET BIT(0)
+#define PCIE_REFCLK BIT(1)
+#define PCIE_REFCLK_MASK 0x16
+#define PCIE_APP_REQ_EXIT_L1_MODE BIT(5)
+
+/*
+ * Workaround : PHY register offset
+ * This register naming based on Exynos5433 TRM(Rev0.1)
+ * Meaning of offset naming and functionality can be difference.
+ * (In future, needs to fix as exactly naming.)
+ * So it makes the offset naming with offset's number.
+ */
+#define PCIE_PHY_OFFSET(x) ((x) * 0x4)
+
+void exynos_pcie_register_dump(struct pcie_port *pp)
+{
+ struct exynos_pcie *g_pcie = to_exynos_pcie(pp);
+ u32 i;
+
+ for (i = 0; i < 0x134; i = i + 4)
+ printk("link reg %x : %x\n", i, readl(g_pcie->elbi_base + i));
+
+ for (i = 0; i < 0x60; i++)
+ printk("phy reg %x * 4: %x\n", i, readl(g_pcie->phy_base + (i * 4)));
+}
+
+static inline void exynos_pcie_writel(void __iomem *base, u32 val, u32 offset)
+{
+ writel(val, base + offset);
+}
+
+static inline u32 exynos_pcie_readl(void __iomem *base, u32 offset)
+{
+ return readl(base + offset);
+}
+
+static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp)
+{
+ u32 val;
+ struct exynos_pcie *ep = to_exynos_pcie(pp);
+
+ val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE);
+ exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE);
+}
+
+static void exynos_pcie_enable_irq_pulse(struct pcie_port *pp)
+{
+ u32 val;
+ struct exynos_pcie *ep = to_exynos_pcie(pp);
+
+ /* enable INTX interrupt */
+ val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
+ IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
+ exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE);
+
+ exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_LEVEL);
+
+ exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_SPECIAL);
+}
+
+static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
+{
+ struct pcie_port *pp = arg;
+
+ exynos_pcie_clear_irq_pulse(pp);
+
+ return IRQ_HANDLED;
+}
+
+static void exynos_pcie_sideband_dbi_w_mode(struct pcie_port *pp, bool on)
+{
+ u32 val;
+ struct exynos_pcie *ep = to_exynos_pcie(pp);
+
+ val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC);
+ if (on)
+ val |= PCIE_ELBI_SLV_DBI_ENABLE;
+ else
+ val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
+ exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
+}
+
+static void exynos_pcie_sideband_dbi_r_mode(struct pcie_port *pp, bool on)
+{
+ u32 val;
+ struct exynos_pcie *ep = to_exynos_pcie(pp);
+
+ val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC);
+ if (on)
+ val |= PCIE_ELBI_SLV_DBI_ENABLE;
+ else
+ val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
+ exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
+}
+
+static void exynos_pcie_init_phy(struct pcie_port *pp)
+{
+ struct exynos_pcie *ep = to_exynos_pcie(pp);
+
+ exynos_pcie_writel(ep->phy_base, 0x11, PCIE_PHY_OFFSET(0x3));
+
+ /* band gap reference on */
+ exynos_pcie_writel(ep->phy_base, 0, PCIE_PHY_OFFSET(0x20));
+ exynos_pcie_writel(ep->phy_base, 0, PCIE_PHY_OFFSET(0x4b));
+
+ /* jitter tunning */
+ exynos_pcie_writel(ep->phy_base, 0x34, PCIE_PHY_OFFSET(0x4));
+ exynos_pcie_writel(ep->phy_base, 0x02, PCIE_PHY_OFFSET(0x7));
+ exynos_pcie_writel(ep->phy_base, 0x41, PCIE_PHY_OFFSET(0x21));
+ exynos_pcie_writel(ep->phy_base, 0x7F, PCIE_PHY_OFFSET(0x14));
+ exynos_pcie_writel(ep->phy_base, 0xC0, PCIE_PHY_OFFSET(0x15));
+ exynos_pcie_writel(ep->phy_base, 0x61, PCIE_PHY_OFFSET(0x36));
+
+ /* D0 uninit.. */
+ exynos_pcie_writel(ep->phy_base, 0x44, PCIE_PHY_OFFSET(0x3D));
+
+ /* 24MHz */
+ exynos_pcie_writel(ep->phy_base, 0x94, PCIE_PHY_OFFSET(0x8));
+ exynos_pcie_writel(ep->phy_base, 0xA7, PCIE_PHY_OFFSET(0x9));
+ exynos_pcie_writel(ep->phy_base, 0x93, PCIE_PHY_OFFSET(0xA));
+ exynos_pcie_writel(ep->phy_base, 0x6B, PCIE_PHY_OFFSET(0xC));
+ exynos_pcie_writel(ep->phy_base, 0xA5, PCIE_PHY_OFFSET(0xF));
+ exynos_pcie_writel(ep->phy_base, 0x34, PCIE_PHY_OFFSET(0x16));
+ exynos_pcie_writel(ep->phy_base, 0xA3, PCIE_PHY_OFFSET(0x17));
+ exynos_pcie_writel(ep->phy_base, 0xA7, PCIE_PHY_OFFSET(0x1A));
+ exynos_pcie_writel(ep->phy_base, 0x71, PCIE_PHY_OFFSET(0x23));
+ exynos_pcie_writel(ep->phy_base, 0x4C, PCIE_PHY_OFFSET(0x24));
+
+ exynos_pcie_writel(ep->phy_base, 0x0E, PCIE_PHY_OFFSET(0x26));
+ exynos_pcie_writel(ep->phy_base, 0x14, PCIE_PHY_OFFSET(0x7));
+ exynos_pcie_writel(ep->phy_base, 0x48, PCIE_PHY_OFFSET(0x43));
+ exynos_pcie_writel(ep->phy_base, 0x44, PCIE_PHY_OFFSET(0x44));
+ exynos_pcie_writel(ep->phy_base, 0x03, PCIE_PHY_OFFSET(0x45));
+ exynos_pcie_writel(ep->phy_base, 0xA7, PCIE_PHY_OFFSET(0x48));
+ exynos_pcie_writel(ep->phy_base, 0x13, PCIE_PHY_OFFSET(0x54));
+ exynos_pcie_writel(ep->phy_base, 0x04, PCIE_PHY_OFFSET(0x31));
+ exynos_pcie_writel(ep->phy_base, 0, PCIE_PHY_OFFSET(0x32));
+}
+
+static void exynos_pcie_assert_phy_reset(struct pcie_port *pp)
+{
+ struct exynos_pcie *ep = to_exynos_pcie(pp);
+ u32 val;
+
+ val = exynos_pcie_readl(ep->block_base, PCIE_PHY_COMMON_RESET);
+ val |= PCIE_PHY_RESET;
+ exynos_pcie_writel(ep->block_base, val, PCIE_PHY_COMMON_RESET);
+
+ /* PHY Mac Reset */
+ val = exynos_pcie_readl(ep->block_base, PCIE_PHY_MAC_RESET);
+ val &= ~PCIE_MAC_RESET;
+ exynos_pcie_writel(ep->block_base, val, PCIE_PHY_MAC_RESET);
+
+
+ /* PHY refclk 24MHz */
+ val = exynos_pcie_readl(ep->block_base, PCIE_PHY_GLOBAL_RESET);
+ val &= ~PCIE_REFCLK_MASK;
+ val |= PCIE_REFCLK;
+ exynos_pcie_writel(ep->block_base, val, PCIE_PHY_GLOBAL_RESET);
+
+ /* PHY Global Reset */
+ val = exynos_pcie_readl(ep->block_base, PCIE_PHY_GLOBAL_RESET);
+ val &= ~PCIE_GLOBAL_RESET;
+ exynos_pcie_writel(ep->block_base, val, PCIE_PHY_GLOBAL_RESET);
+
+ /* initialize phy */
+ exynos_pcie_init_phy(pp);
+
+ /* PHY Common Reset */
+ val = exynos_pcie_readl(ep->block_base, PCIE_PHY_COMMON_RESET);
+ val &= ~PCIE_PHY_RESET;
+ exynos_pcie_writel(ep->block_base, val, PCIE_PHY_COMMON_RESET);
+
+ /* PHY Mac Reset */
+ val = exynos_pcie_readl(ep->block_base, PCIE_PHY_MAC_RESET);
+ val |= PCIE_MAC_RESET;
+ exynos_pcie_writel(ep->block_base, val, PCIE_PHY_MAC_RESET);
+
+
+ val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE);
+ val &= ~(0x1 << 1);
+ exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE);
+}
+
+static int exynos_pcie_reset(struct pcie_port *pp)
+{
+ struct exynos_pcie *ep = to_exynos_pcie(pp);
+ u32 val;
+
+ if (ep->perst_gpio) {
+ gpio_set_value(ep->perst_gpio, 0);
+ udelay(20);
+ gpio_set_value(ep->perst_gpio, 1);
+ }
+
+
+ exynos_pcie_assert_phy_reset(pp);
+
+ /* Setup root complext */
+ dw_pcie_setup_rc(pp);
+
+ if (ep->reset_gpio) {
+ gpio_set_value(ep->reset_gpio, 1);
+ msleep(80);
+ }
+
+ /* assert LTSSM enable */
+ exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
+ PCIE_APP_LTSSM_ENABLE);
+
+ val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_LEVEL);
+ if (val & 0x10) {
+ writel(0x0c200004, ep->pp.va_cfg0_base + 0x10);
+ writel(0x0c400004, ep->pp.va_cfg0_base + 0x18);
+ return 0;
+ }
+
+ return -EPIPE;
+}
+
+static int exynos_pcie_establish_link(struct pcie_port *pp)
+{
+ struct exynos_pcie *ep = to_exynos_pcie(pp);
+ u32 val;
+ int count = 10, ret;
+
+ if (dw_pcie_link_up(pp)) {
+ dev_info(pp->dev, "Link already up\n");
+ return 0;
+ }
+
+ /* PMU control at here */
+ if (ep->pmureg) {
+ if (regmap_update_bits(ep->pmureg, PCIE_PMU_PHY_OFFSET, BIT(0), 1))
+ dev_warn(pp->dev, "Failed to update regmap bit.\n");
+ }
+
+ val = exynos_pcie_readl(ep->block_base, PCIE_PHY_GLOBAL_RESET);
+ val &= ~PCIE_APP_REQ_EXIT_L1_MODE;
+ exynos_pcie_writel(ep->block_base, val, PCIE_PHY_GLOBAL_RESET);
+
+ val = exynos_pcie_readl(ep->block_base, PCIE_L1SUB_CM_CON);
+ val &= ~PCIE_REFCLK_GATING_EN;
+ exynos_pcie_writel(ep->block_base, val, PCIE_L1SUB_CM_CON);
+
+ exynos_pcie_assert_phy_reset(pp);
+
+ /* Setup root complext */
+ dw_pcie_setup_rc(pp);
+
+ /* assert LTSSM enable */
+ exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
+ PCIE_APP_LTSSM_ENABLE);
+
+ while (!dw_pcie_link_up(pp)) {
+ usleep_range(100, 1000);
+ if (--count) {
+ ret = exynos_pcie_reset(pp);
+ if (!ret)
+ break;
+ continue;
+ }
+
+ /* Workaround */
+ exynos_pcie_register_dump(pp);
+ dev_err(pp->dev, "Failed PCIe Link up!\n");
+ return -EPIPE;
+ }
+
+ dev_info(pp->dev, "Link up!\n");
+ return 0;
+}
+
+static int exynos_pcie_link_up(struct pcie_port *pp)
+{
+ struct exynos_pcie *ep = to_exynos_pcie(pp);
+ u32 val;
+
+ val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP);
+ if (val == PCIE_ELBI_LTSSM_ENABLE)
+ return 1;
+
+ return 0;
+}
+
+static int exynos_pcie_host_init(struct pcie_port *pp)
+{
+ exynos_pcie_enable_irq_pulse(pp);
+
+ return exynos_pcie_establish_link(pp);
+}
+
+static inline void exynos_pcie_readl_rc(struct pcie_port *pp,
+ void __iomem *dbi_base, u32 *val)
+{
+ exynos_pcie_sideband_dbi_r_mode(pp, true);
+ *val = readl(dbi_base);
+ exynos_pcie_sideband_dbi_r_mode(pp, false);
+}
+
+static inline void exynos_pcie_writel_rc(struct pcie_port *pp,
+ u32 val, void __iomem *dbi_base)
+{
+ exynos_pcie_sideband_dbi_w_mode(pp, true);
+ writel(val, dbi_base);
+ exynos_pcie_sideband_dbi_w_mode(pp, false);
+}
+
+static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
+ u32 *val)
+{
+ int ret;
+
+ exynos_pcie_sideband_dbi_r_mode(pp, true);
+ ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where, size, val);
+ exynos_pcie_sideband_dbi_r_mode(pp, false);
+ return ret;
+}
+
+static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
+ u32 val)
+{
+ int ret;
+
+ exynos_pcie_sideband_dbi_w_mode(pp, true);
+ ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3),
+ where, size, val);
+ exynos_pcie_sideband_dbi_w_mode(pp, false);
+ return ret;
+}
+
+static struct pcie_host_ops exynos_pcie_host_ops = {
+ .readl_rc = exynos_pcie_readl_rc,
+ .writel_rc = exynos_pcie_writel_rc,
+ .rd_own_conf = exynos_pcie_rd_own_conf,
+ .wr_own_conf = exynos_pcie_wr_own_conf,
+ .host_init = exynos_pcie_host_init,
+ .link_up = exynos_pcie_link_up,
+};
+
+static int exynos_pcie_probe(struct platform_device *pdev)
+{
+ struct exynos_pcie *exynos_pcie;
+ struct device_node *np = pdev->dev.of_node;
+ struct pcie_port *pp;
+ struct resource *res;
+ int ret;
+
+ exynos_pcie = devm_kzalloc(&pdev->dev, sizeof(*exynos_pcie),
+ GFP_KERNEL);
+ if (!exynos_pcie)
+ return -ENOMEM;
+
+ pp = &exynos_pcie->pp;
+ pp->dev = &pdev->dev;
+
+ exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
+ exynos_pcie->perst_gpio = of_get_named_gpio(np, "perst-gpio", 0);
+
+ exynos_pcie->clk = devm_clk_get(&pdev->dev, "pcie");
+ if (IS_ERR(exynos_pcie->clk)) {
+ dev_err(&pdev->dev, "Failed to get pcie rc clock\n");
+ return PTR_ERR(exynos_pcie->clk);
+ }
+ ret = clk_prepare_enable(exynos_pcie->clk);
+ if (ret)
+ return ret;
+
+ exynos_pcie->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus");
+ if (IS_ERR(exynos_pcie->bus_clk)) {
+ dev_err(&pdev->dev, "Failed to get pcie bus clock\n");
+ ret = PTR_ERR(exynos_pcie->bus_clk);
+ goto fail_clk;
+ }
+ ret = clk_prepare_enable(exynos_pcie->bus_clk);
+ if (ret)
+ goto fail_clk;
+
+ /* Application Register */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ exynos_pcie->elbi_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(exynos_pcie->elbi_base)) {
+ ret = PTR_ERR(exynos_pcie->elbi_base);
+ goto fail_bus_clk;
+ }
+
+ /* Physical Layer Register */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ exynos_pcie->phy_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(exynos_pcie->phy_base)) {
+ ret = PTR_ERR(exynos_pcie->phy_base);
+ goto fail_bus_clk;
+ }
+
+ /* Workaround Block register(System register) */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ exynos_pcie->block_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(exynos_pcie->block_base))
+ goto fail_bus_clk;
+
+ exynos_pcie->pmureg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "samsung,pmureg-phandle");
+ if (IS_ERR(exynos_pcie->pmureg)) {
+ dev_warn(&pdev->dev, "Pmureg syscon regmap lookup failed.\n");
+ exynos_pcie->pmureg = NULL;
+ }
+
+ pp->irq = platform_get_irq(pdev, 0);
+ if (!pp->irq) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ ret = -ENODEV;
+ goto fail_bus_clk;
+ }
+ ret = devm_request_irq(&pdev->dev, pp->irq, exynos_pcie_irq_handler,
+ IRQF_SHARED, "exynos-pcie", pp);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ goto fail_bus_clk;
+ }
+
+ pp->root_bus_nr = -1;
+ pp->ops = &exynos_pcie_host_ops;
+
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize host\n");
+ goto fail_bus_clk;
+ }
+
+ platform_set_drvdata(pdev, exynos_pcie);
+
+ return 0;
+
+fail_bus_clk:
+ clk_disable_unprepare(exynos_pcie->bus_clk);
+fail_clk:
+ clk_disable_unprepare(exynos_pcie->clk);
+ return ret;
+
+}
+
+static int exynos_pcie_remove(struct platform_device *pdev)
+{
+ struct exynos_pcie *ep = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(ep->bus_clk);
+ clk_disable_unprepare(ep->clk);
+
+ return 0;
+}
+
+static const struct of_device_id exynos_pcie_of_match[] = {
+ { .compatible = "samsung,exynos5433-pcie", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_pcie_of_match);
+
+static struct platform_driver exynos_pcie_driver = {
+ .remove = exynos_pcie_remove,
+ .driver = {
+ .name = "exynos-pcie",
+ .of_match_table = exynos_pcie_of_match,
+ },
+};
+
+static int __init exynos_pcie_init(void)
+{
+ return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe);
+}
+late_initcall(exynos_pcie_init);
+
+MODULE_AUTHOR("Jingoo Han<jg1.han@samsung.com>");
+MODULE_AUTHOR("Jaehoon CHung <jh80.chung@samsung.com>");
+MODULE_LICENSE("GPL v2");