/* * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ /* * SATA init module. * To be used with SATA interface on MSM targets. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* PHY registers */ #define UNIPHY_PLL_REFCLK_CFG 0x000 #define UNIPHY_PLL_POSTDIV1_CFG 0x004 #define UNIPHY_PLL_CHGPUMP_CFG 0x008 #define UNIPHY_PLL_VCOLPF_CFG 0x00C #define UNIPHY_PLL_VREG_CFG 0x010 #define UNIPHY_PLL_PWRGEN_CFG 0x014 #define UNIPHY_PLL_DMUX_CFG 0x018 #define UNIPHY_PLL_AMUX_CFG 0x01C #define UNIPHY_PLL_GLB_CFG 0x020 #define UNIPHY_PLL_POSTDIV2_CFG 0x024 #define UNIPHY_PLL_POSTDIV3_CFG 0x028 #define UNIPHY_PLL_LPFR_CFG 0x02C #define UNIPHY_PLL_LPFC1_CFG 0x030 #define UNIPHY_PLL_LPFC2_CFG 0x034 #define UNIPHY_PLL_SDM_CFG0 0x038 #define UNIPHY_PLL_SDM_CFG1 0x03C #define UNIPHY_PLL_SDM_CFG2 0x040 #define UNIPHY_PLL_SDM_CFG3 0x044 #define UNIPHY_PLL_SDM_CFG4 0x048 #define UNIPHY_PLL_SSC_CFG0 0x04C #define UNIPHY_PLL_SSC_CFG1 0x050 #define UNIPHY_PLL_SSC_CFG2 0x054 #define UNIPHY_PLL_SSC_CFG3 0x058 #define UNIPHY_PLL_LKDET_CFG0 0x05C #define UNIPHY_PLL_LKDET_CFG1 0x060 #define UNIPHY_PLL_LKDET_CFG2 0x064 #define UNIPHY_PLL_TEST_CFG 0x068 #define UNIPHY_PLL_CAL_CFG0 0x06C #define UNIPHY_PLL_CAL_CFG1 0x070 #define UNIPHY_PLL_CAL_CFG2 0x074 #define UNIPHY_PLL_CAL_CFG3 0x078 #define UNIPHY_PLL_CAL_CFG4 0x07C #define UNIPHY_PLL_CAL_CFG5 0x080 #define UNIPHY_PLL_CAL_CFG6 0x084 #define UNIPHY_PLL_CAL_CFG7 0x088 #define UNIPHY_PLL_CAL_CFG8 0x08C #define UNIPHY_PLL_CAL_CFG9 0x090 #define UNIPHY_PLL_CAL_CFG10 0x094 #define UNIPHY_PLL_CAL_CFG11 0x098 #define UNIPHY_PLL_EFUSE_CFG 0x09C #define UNIPHY_PLL_DEBUG_BUS_SEL 0x0A0 #define UNIPHY_PLL_CTRL_42 0x0A4 #define UNIPHY_PLL_CTRL_43 0x0A8 #define UNIPHY_PLL_CTRL_44 0x0AC #define UNIPHY_PLL_CTRL_45 0x0B0 #define UNIPHY_PLL_CTRL_46 0x0B4 #define UNIPHY_PLL_CTRL_47 0x0B8 #define UNIPHY_PLL_CTRL_48 0x0BC #define UNIPHY_PLL_STATUS 0x0C0 #define UNIPHY_PLL_DEBUG_BUS0 0x0C4 #define UNIPHY_PLL_DEBUG_BUS1 0x0C8 #define UNIPHY_PLL_DEBUG_BUS2 0x0CC #define UNIPHY_PLL_DEBUG_BUS3 0x0D0 #define UNIPHY_PLL_CTRL_54 0x0D4 #define SATA_PHY_SER_CTRL 0x100 #define SATA_PHY_TX_DRIV_CTRL0 0x104 #define SATA_PHY_TX_DRIV_CTRL1 0x108 #define SATA_PHY_TX_DRIV_CTRL2 0x10C #define SATA_PHY_TX_DRIV_CTRL3 0x110 #define SATA_PHY_TX_RESV0 0x114 #define SATA_PHY_TX_RESV1 0x118 #define SATA_PHY_TX_IMCAL0 0x11C #define SATA_PHY_TX_IMCAL1 0x120 #define SATA_PHY_TX_IMCAL2 0x124 #define SATA_PHY_RX_IMCAL0 0x128 #define SATA_PHY_RX_IMCAL1 0x12C #define SATA_PHY_RX_IMCAL2 0x130 #define SATA_PHY_RX_TERM 0x134 #define SATA_PHY_RX_TERM_RESV 0x138 #define SATA_PHY_EQUAL 0x13C #define SATA_PHY_EQUAL_RESV 0x140 #define SATA_PHY_OOB_TERM 0x144 #define SATA_PHY_CDR_CTRL0 0x148 #define SATA_PHY_CDR_CTRL1 0x14C #define SATA_PHY_CDR_CTRL2 0x150 #define SATA_PHY_CDR_CTRL3 0x154 #define SATA_PHY_CDR_CTRL4 0x158 #define SATA_PHY_FA_LOAD0 0x15C #define SATA_PHY_FA_LOAD1 0x160 #define SATA_PHY_CDR_CTRL_RESV 0x164 #define SATA_PHY_PI_CTRL0 0x168 #define SATA_PHY_PI_CTRL1 0x16C #define SATA_PHY_DESER_RESV 0x170 #define SATA_PHY_RX_RESV0 0x174 #define SATA_PHY_AD_TPA_CTRL 0x178 #define SATA_PHY_REFCLK_CTRL 0x17C #define SATA_PHY_POW_DWN_CTRL0 0x180 #define SATA_PHY_POW_DWN_CTRL1 0x184 #define SATA_PHY_TX_DATA_CTRL 0x188 #define SATA_PHY_BIST_GEN0 0x18C #define SATA_PHY_BIST_GEN1 0x190 #define SATA_PHY_BIST_GEN2 0x194 #define SATA_PHY_BIST_GEN3 0x198 #define SATA_PHY_LBK_CTRL 0x19C #define SATA_PHY_TEST_DEBUG_CTRL 0x1A0 #define SATA_PHY_ALIGNP 0x1A4 #define SATA_PHY_PRBS_CFG0 0x1A8 #define SATA_PHY_PRBS_CFG1 0x1AC #define SATA_PHY_PRBS_CFG2 0x1B0 #define SATA_PHY_PRBS_CFG3 0x1B4 #define SATA_PHY_CHAN_COMP_CHK_CNT 0x1B8 #define SATA_PHY_RESET_CTRL 0x1BC #define SATA_PHY_RX_CLR 0x1C0 #define SATA_PHY_RX_EBUF_CTRL 0x1C4 #define SATA_PHY_ID0 0x1C8 #define SATA_PHY_ID1 0x1CC #define SATA_PHY_ID2 0x1D0 #define SATA_PHY_ID3 0x1D4 #define SATA_PHY_RX_CHK_ERR_CNT0 0x1D8 #define SATA_PHY_RX_CHK_ERR_CNT1 0x1DC #define SATA_PHY_RX_CHK_STAT 0x1E0 #define SATA_PHY_TX_IMCAL_STAT 0x1E4 #define SATA_PHY_RX_IMCAL_STAT 0x1E8 #define SATA_PHY_RX_EBUF_STAT 0x1EC #define SATA_PHY_DEBUG_BUS_STAT0 0x1F0 #define SATA_PHY_DEBUG_BUS_STAT1 0x1F4 #define SATA_PHY_DEBUG_BUS_STAT2 0x1F8 #define SATA_PHY_DEBUG_BUS_STAT3 0x1FC #define AHCI_HOST_CAP 0x00 #define AHCI_HOST_CAP_MASK 0x1F #define AHCI_HOST_CAP_PMP (1 << 17) struct msm_sata_hba { struct platform_device *ahci_pdev; struct clk *slave_iface_clk; struct clk *bus_clk; struct clk *iface_clk; struct clk *src_clk; struct clk *rxoob_clk; struct clk *pmalive_clk; struct clk *cfg_clk; struct regulator *clk_pwr; struct regulator *pmp_pwr; void __iomem *phy_base; void __iomem *ahci_base; }; static inline void msm_sata_delay_us(unsigned int delay) { /* sleep for max. 50us more to combine processor wakeups */ usleep_range(delay, delay + 50); } static int msm_sata_clk_get_prepare_enable_set_rate(struct device *dev, const char *name, struct clk **out_clk, int rate) { int ret = 0; struct clk *clk; clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); dev_err(dev, "failed to get clk: %s err = %d\n", name, ret); goto out; } if (rate >= 0) { ret = clk_set_rate(clk, rate); if (ret) { dev_err(dev, "failed to set rate: %d clk: %s err = %d\n", rate, name, ret); goto out; } } ret = clk_prepare_enable(clk); if (ret) dev_err(dev, "failed to enable clk: %s err = %d\n", name, ret); out: if (!ret) *out_clk = clk; return ret; } static int msm_sata_clk_get_prepare_enable(struct device *dev, const char *name, struct clk **out_clk) { return msm_sata_clk_get_prepare_enable_set_rate(dev, name, out_clk, -1); } static void msm_sata_clk_put_unprepare_disable(struct clk **clk) { if (*clk) { clk_disable_unprepare(*clk); clk_put(*clk); *clk = NULL; } } static int msm_sata_hard_reset(struct device *dev) { int ret; struct msm_sata_hba *hba = dev_get_drvdata(dev); ret = clk_reset(hba->iface_clk, CLK_RESET_ASSERT); if (ret) { dev_err(dev, "iface_clk assert failed %d\n", ret); goto out; } ret = clk_reset(hba->iface_clk, CLK_RESET_DEASSERT); if (ret) { dev_err(dev, "iface_clk de-assert failed %d\n", ret); goto out; } out: return ret; } static int msm_sata_clk_init(struct device *dev) { int ret = 0; struct msm_sata_hba *hba = dev_get_drvdata(dev); /* Enable AHB clock for system fabric slave port connected to SATA */ ret = msm_sata_clk_get_prepare_enable(dev, "slave_iface_clk", &hba->slave_iface_clk); if (ret) goto out; /* Enable AHB clock for system fabric and SATA core interface */ ret = msm_sata_clk_get_prepare_enable(dev, "iface_clk", &hba->iface_clk); if (ret) goto put_dis_slave_iface_clk; /* Enable AXI clock for SATA AXI master and slave interfaces */ ret = msm_sata_clk_get_prepare_enable(dev, "bus_clk", &hba->bus_clk); if (ret) goto put_dis_iface_clk; /* Enable the source clock for pmalive, rxoob and phy ref clocks */ ret = msm_sata_clk_get_prepare_enable_set_rate(dev, "src_clk", &hba->src_clk, 100000000); if (ret) goto put_dis_bus_clk; /* * Enable RX OOB detection clock. The clock rate is * same as PHY reference clock (100MHz). */ ret = msm_sata_clk_get_prepare_enable(dev, "core_rxoob_clk", &hba->rxoob_clk); if (ret) goto put_dis_src_clk; /* * Enable power management always-on clock. The clock rate * is same as PHY reference clock (100MHz). */ ret = msm_sata_clk_get_prepare_enable(dev, "core_pmalive_clk", &hba->pmalive_clk); if (ret) goto put_dis_rxoob_clk; /* Enable PHY configuration AHB clock, fixed 64MHz clock */ ret = msm_sata_clk_get_prepare_enable(dev, "cfg_clk", &hba->cfg_clk); if (ret) goto put_dis_pmalive_clk; return ret; put_dis_pmalive_clk: msm_sata_clk_put_unprepare_disable(&hba->pmalive_clk); put_dis_rxoob_clk: msm_sata_clk_put_unprepare_disable(&hba->rxoob_clk); put_dis_src_clk: msm_sata_clk_put_unprepare_disable(&hba->src_clk); put_dis_bus_clk: msm_sata_clk_put_unprepare_disable(&hba->bus_clk); put_dis_iface_clk: msm_sata_clk_put_unprepare_disable(&hba->iface_clk); put_dis_slave_iface_clk: msm_sata_clk_put_unprepare_disable(&hba->slave_iface_clk); out: return ret; } static void msm_sata_clk_deinit(struct device *dev) { struct msm_sata_hba *hba = dev_get_drvdata(dev); msm_sata_clk_put_unprepare_disable(&hba->cfg_clk); msm_sata_clk_put_unprepare_disable(&hba->pmalive_clk); msm_sata_clk_put_unprepare_disable(&hba->rxoob_clk); msm_sata_clk_put_unprepare_disable(&hba->src_clk); msm_sata_clk_put_unprepare_disable(&hba->bus_clk); msm_sata_clk_put_unprepare_disable(&hba->iface_clk); msm_sata_clk_put_unprepare_disable(&hba->slave_iface_clk); } static int msm_sata_vreg_get_enable_set_vdd(struct device *dev, const char *name, struct regulator **out_vreg, int min_uV, int max_uV, int hpm_uA) { int ret = 0; struct regulator *vreg; vreg = devm_regulator_get(dev, name); if (IS_ERR(vreg)) { ret = PTR_ERR(vreg); dev_err(dev, "Regulator: %s get failed, err=%d\n", name, ret); goto out; } if (regulator_count_voltages(vreg) > 0) { ret = regulator_set_voltage(vreg, min_uV, max_uV); if (ret) { dev_err(dev, "Regulator: %s set voltage failed, err=%d\n", name, ret); goto err; } ret = regulator_set_optimum_mode(vreg, hpm_uA); if (ret < 0) { dev_err(dev, "Regulator: %s set optimum mode(uA_load=%d) failed, err=%d\n", name, hpm_uA, ret); goto err; } else { /* * regulator_set_optimum_mode() can return non zero * value even for success case. */ ret = 0; } } ret = regulator_enable(vreg); if (ret) dev_err(dev, "Regulator: %s enable failed, err=%d\n", name, ret); err: if (!ret) *out_vreg = vreg; else devm_regulator_put(vreg); out: return ret; } static int msm_sata_vreg_put_disable(struct device *dev, struct regulator *reg, const char *name, int max_uV) { int ret; if (!reg) return 0; ret = regulator_disable(reg); if (ret) { dev_err(dev, "Regulator: %s disable failed err=%d\n", name, ret); goto err; } if (regulator_count_voltages(reg) > 0) { ret = regulator_set_voltage(reg, 0, max_uV); if (ret < 0) { dev_err(dev, "Regulator: %s set voltage to 0 failed, err=%d\n", name, ret); goto err; } ret = regulator_set_optimum_mode(reg, 0); if (ret < 0) { dev_err(dev, "Regulator: %s set optimum mode(uA_load = 0) failed, err=%d\n", name, ret); goto err; } else { /* * regulator_set_optimum_mode() can return non zero * value even for success case. */ ret = 0; } } err: devm_regulator_put(reg); return ret; } static int msm_sata_vreg_init(struct device *dev) { int ret = 0; struct msm_sata_hba *hba = dev_get_drvdata(dev); /* * The SATA clock generator needs 3.3V supply and can consume * max. 850mA during functional mode. */ ret = msm_sata_vreg_get_enable_set_vdd(dev, "sata_ext_3p3v", &hba->clk_pwr, 3300000, 3300000, 850000); if (ret) goto out; /* Add 1ms regulator ramp-up delay */ msm_sata_delay_us(1000); /* Read AHCI capability register to check if PMP is supported.*/ if (readl_relaxed(hba->ahci_base + AHCI_HOST_CAP) & AHCI_HOST_CAP_PMP) { /* Power up port-multiplier */ ret = msm_sata_vreg_get_enable_set_vdd(dev, "sata_pmp_pwr", &hba->pmp_pwr, 1800000, 1800000, 200000); if (ret) { msm_sata_vreg_put_disable(dev, hba->clk_pwr, "sata_ext_3p3v", 3300000); goto out; } /* Add 1ms regulator ramp-up delay */ msm_sata_delay_us(1000); } out: return ret; } static void msm_sata_vreg_deinit(struct device *dev) { struct msm_sata_hba *hba = dev_get_drvdata(dev); msm_sata_vreg_put_disable(dev, hba->clk_pwr, "sata_ext_3p3v", 3300000); if (hba->pmp_pwr) msm_sata_vreg_put_disable(dev, hba->pmp_pwr, "sata_pmp_pwr", 1800000); } static void msm_sata_phy_deinit(struct device *dev) { struct msm_sata_hba *hba = dev_get_drvdata(dev); /* Power down PHY */ writel_relaxed(0xF8, hba->phy_base + SATA_PHY_POW_DWN_CTRL0); writel_relaxed(0xFE, hba->phy_base + SATA_PHY_POW_DWN_CTRL1); /* Power down PLL block */ writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_GLB_CFG); mb(); devm_iounmap(dev, hba->phy_base); } static int msm_sata_phy_init(struct device *dev) { int ret = 0; u32 reg = 0; struct platform_device *pdev = to_platform_device(dev); struct msm_sata_hba *hba = dev_get_drvdata(dev); struct resource *mem; mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_mem"); if (!mem) { dev_err(dev, "no mmio space\n"); return -EINVAL; } hba->phy_base = devm_ioremap(dev, mem->start, resource_size(mem)); if (!hba->phy_base) { dev_err(dev, "failed to allocate memory for SATA PHY\n"); return -ENOMEM; } /* SATA phy initialization */ writel_relaxed(0x01, hba->phy_base + SATA_PHY_SER_CTRL); writel_relaxed(0xB1, hba->phy_base + SATA_PHY_POW_DWN_CTRL0); mb(); msm_sata_delay_us(10); writel_relaxed(0x01, hba->phy_base + SATA_PHY_POW_DWN_CTRL0); writel_relaxed(0x3E, hba->phy_base + SATA_PHY_POW_DWN_CTRL1); writel_relaxed(0x01, hba->phy_base + SATA_PHY_RX_IMCAL0); writel_relaxed(0x01, hba->phy_base + SATA_PHY_TX_IMCAL0); writel_relaxed(0x02, hba->phy_base + SATA_PHY_TX_IMCAL2); /* Write UNIPHYPLL registers to configure PLL */ writel_relaxed(0x04, hba->phy_base + UNIPHY_PLL_REFCLK_CFG); writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_PWRGEN_CFG); writel_relaxed(0x0A, hba->phy_base + UNIPHY_PLL_CAL_CFG0); writel_relaxed(0xF3, hba->phy_base + UNIPHY_PLL_CAL_CFG8); writel_relaxed(0x01, hba->phy_base + UNIPHY_PLL_CAL_CFG9); writel_relaxed(0xED, hba->phy_base + UNIPHY_PLL_CAL_CFG10); writel_relaxed(0x02, hba->phy_base + UNIPHY_PLL_CAL_CFG11); writel_relaxed(0x36, hba->phy_base + UNIPHY_PLL_SDM_CFG0); writel_relaxed(0x0D, hba->phy_base + UNIPHY_PLL_SDM_CFG1); writel_relaxed(0xA3, hba->phy_base + UNIPHY_PLL_SDM_CFG2); writel_relaxed(0xF0, hba->phy_base + UNIPHY_PLL_SDM_CFG3); writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_SDM_CFG4); writel_relaxed(0x19, hba->phy_base + UNIPHY_PLL_SSC_CFG0); writel_relaxed(0xE1, hba->phy_base + UNIPHY_PLL_SSC_CFG1); writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_SSC_CFG2); writel_relaxed(0x11, hba->phy_base + UNIPHY_PLL_SSC_CFG3); writel_relaxed(0x04, hba->phy_base + UNIPHY_PLL_LKDET_CFG0); writel_relaxed(0xFF, hba->phy_base + UNIPHY_PLL_LKDET_CFG1); writel_relaxed(0x02, hba->phy_base + UNIPHY_PLL_GLB_CFG); mb(); msm_sata_delay_us(40); writel_relaxed(0x03, hba->phy_base + UNIPHY_PLL_GLB_CFG); mb(); msm_sata_delay_us(400); writel_relaxed(0x05, hba->phy_base + UNIPHY_PLL_LKDET_CFG2); mb(); /* poll for ready status, timeout after 1 sec */ ret = readl_poll_timeout(hba->phy_base + UNIPHY_PLL_STATUS, reg, (reg & 1 << 0), 100, 1000000); if (ret) { dev_err(dev, "poll timeout UNIPHY_PLL_STATUS\n"); goto out; } ret = readl_poll_timeout(hba->phy_base + SATA_PHY_TX_IMCAL_STAT, reg, (reg & 1 << 0), 100, 1000000); if (ret) { dev_err(dev, "poll timeout SATA_PHY_TX_IMCAL_STAT\n"); goto out; } ret = readl_poll_timeout(hba->phy_base + SATA_PHY_RX_IMCAL_STAT, reg, (reg & 1 << 0), 100, 1000000); if (ret) { dev_err(dev, "poll timeout SATA_PHY_RX_IMCAL_STAT\n"); goto out; } /* SATA phy calibrated succesfully, power up to functional mode */ writel_relaxed(0x3E, hba->phy_base + SATA_PHY_POW_DWN_CTRL1); writel_relaxed(0x01, hba->phy_base + SATA_PHY_RX_IMCAL0); writel_relaxed(0x01, hba->phy_base + SATA_PHY_TX_IMCAL0); writel_relaxed(0x00, hba->phy_base + SATA_PHY_POW_DWN_CTRL1); writel_relaxed(0x59, hba->phy_base + SATA_PHY_CDR_CTRL0); writel_relaxed(0x04, hba->phy_base + SATA_PHY_CDR_CTRL1); writel_relaxed(0x00, hba->phy_base + SATA_PHY_CDR_CTRL2); writel_relaxed(0x00, hba->phy_base + SATA_PHY_PI_CTRL0); writel_relaxed(0x00, hba->phy_base + SATA_PHY_CDR_CTRL3); writel_relaxed(0x01, hba->phy_base + SATA_PHY_POW_DWN_CTRL0); writel_relaxed(0x11, hba->phy_base + SATA_PHY_TX_DATA_CTRL); writel_relaxed(0x43, hba->phy_base + SATA_PHY_ALIGNP); writel_relaxed(0x04, hba->phy_base + SATA_PHY_OOB_TERM); writel_relaxed(0x01, hba->phy_base + SATA_PHY_EQUAL); writel_relaxed(0x09, hba->phy_base + SATA_PHY_TX_DRIV_CTRL0); writel_relaxed(0x09, hba->phy_base + SATA_PHY_TX_DRIV_CTRL1); mb(); dev_dbg(dev, "SATA PHY powered up in functional mode\n"); out: /* power down PHY in case of failure */ if (ret) msm_sata_phy_deinit(dev); return ret; } int msm_sata_init(struct device *ahci_dev, void __iomem *mmio) { int ret; struct device *dev = ahci_dev->parent; struct msm_sata_hba *hba = dev_get_drvdata(dev); /* Save ahci mmio to access vendor specific registers */ hba->ahci_base = mmio; ret = msm_sata_clk_init(dev); if (ret) { dev_err(dev, "SATA clk init failed with err=%d\n", ret); goto out; } ret = msm_sata_vreg_init(dev); if (ret) { dev_err(dev, "SATA vreg init failed with err=%d\n", ret); msm_sata_clk_deinit(dev); goto out; } ret = msm_sata_phy_init(dev); if (ret) { dev_err(dev, "SATA PHY init failed with err=%d\n", ret); msm_sata_vreg_deinit(dev); msm_sata_clk_deinit(dev); goto out; } out: return ret; } void msm_sata_deinit(struct device *ahci_dev) { struct device *dev = ahci_dev->parent; msm_sata_phy_deinit(dev); msm_sata_vreg_deinit(dev); msm_sata_clk_deinit(dev); } static int msm_sata_suspend(struct device *ahci_dev) { msm_sata_deinit(ahci_dev); return 0; } static int msm_sata_resume(struct device *ahci_dev) { int ret; struct device *dev = ahci_dev->parent; ret = msm_sata_clk_init(dev); if (ret) { dev_err(dev, "SATA clk init failed with err=%d\n", ret); /* * If clock initialization failed, that means ahci driver * cannot access any register going further. Since there is * no check within ahci driver to check for clock failures, * panic here instead of making an unclocked register access. */ BUG(); } /* Issue asynchronous reset to reset PHY */ ret = msm_sata_hard_reset(dev); if (ret) goto out; ret = msm_sata_vreg_init(dev); if (ret) { dev_err(dev, "SATA vreg init failed with err=%d\n", ret); /* Do not turn off clks, AHCI driver might do register access */ goto out; } ret = msm_sata_phy_init(dev); if (ret) { dev_err(dev, "SATA PHY init failed with err=%d\n", ret); /* Do not turn off clks, AHCI driver might do register access */ msm_sata_vreg_deinit(dev); goto out; } out: return ret; } static struct ahci_platform_data msm_ahci_pdata = { .init = msm_sata_init, .exit = msm_sata_deinit, .suspend = msm_sata_suspend, .resume = msm_sata_resume, }; static int __devinit msm_sata_probe(struct platform_device *pdev) { struct platform_device *ahci; struct msm_sata_hba *hba; int ret = 0; hba = devm_kzalloc(&pdev->dev, sizeof(struct msm_sata_hba), GFP_KERNEL); if (!hba) { dev_err(&pdev->dev, "no memory\n"); ret = -ENOMEM; goto err; } platform_set_drvdata(pdev, hba); ahci = platform_device_alloc("ahci", pdev->id); if (!ahci) { dev_err(&pdev->dev, "couldn't allocate ahci device\n"); ret = -ENOMEM; goto err_free; } dma_set_coherent_mask(&ahci->dev, pdev->dev.coherent_dma_mask); ahci->dev.parent = &pdev->dev; ahci->dev.dma_mask = pdev->dev.dma_mask; ahci->dev.dma_parms = pdev->dev.dma_parms; hba->ahci_pdev = ahci; ret = platform_device_add_resources(ahci, pdev->resource, pdev->num_resources); if (ret) { dev_err(&pdev->dev, "couldn't add resources to ahci device\n"); goto err_put_device; } ahci->dev.platform_data = &msm_ahci_pdata; ret = platform_device_add(ahci); if (ret) { dev_err(&pdev->dev, "failed to register ahci device\n"); goto err_put_device; } return 0; err_put_device: platform_device_put(ahci); err_free: devm_kfree(&pdev->dev, hba); err: return ret; } static int __devexit msm_sata_remove(struct platform_device *pdev) { struct msm_sata_hba *hba = platform_get_drvdata(pdev); platform_device_unregister(hba->ahci_pdev); return 0; } static struct platform_driver msm_sata_driver = { .probe = msm_sata_probe, .remove = __devexit_p(msm_sata_remove), .driver = { .name = "msm_sata", }, }; module_platform_driver(msm_sata_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("AHCI platform MSM Glue Layer");