2 * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
15 #include "phy-qcom-ufs-qmp-v3-660.h"
17 #define UFS_PHY_NAME "ufs_phy_qmp_v3_660"
20 int ufs_qcom_phy_qmp_v3_660_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
24 int tbl_size_A, tbl_size_B;
25 struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
26 u8 major = ufs_qcom_phy->host_ctrl_rev_major;
27 u16 minor = ufs_qcom_phy->host_ctrl_rev_minor;
28 u16 step = ufs_qcom_phy->host_ctrl_rev_step;
30 tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
31 tbl_B = phy_cal_table_rate_B;
33 if ((major == 0x3) && (minor == 0x001) && (step == 0x001)) {
34 tbl_A = phy_cal_table_rate_A_3_1_1;
35 tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_3_1_1);
37 dev_err(ufs_qcom_phy->dev,
38 "%s: Unknown UFS-PHY version (major 0x%x minor 0x%x step 0x%x), no calibration values\n",
39 __func__, major, minor, step);
44 err = ufs_qcom_phy_calibrate(ufs_qcom_phy,
50 dev_err(ufs_qcom_phy->dev,
51 "%s: ufs_qcom_phy_calibrate() failed %d\n",
58 static int ufs_qcom_phy_qmp_v3_660_init(struct phy *generic_phy)
60 struct ufs_qcom_phy_qmp_v3_660 *phy = phy_get_drvdata(generic_phy);
61 struct ufs_qcom_phy *phy_common = &phy->common_cfg;
64 err = ufs_qcom_phy_init_clks(generic_phy, phy_common);
66 dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n",
71 err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common);
73 dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
83 void ufs_qcom_phy_qmp_v3_660_power_control(struct ufs_qcom_phy *phy,
87 /* apply analog power collapse */
88 writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
90 * Make sure that PHY knows its analog rail is going to be
95 /* bring PHY out of analog power collapse */
96 writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
99 * Before any transactions involving PHY, ensure PHY knows
100 * that it's analog rail is powered ON.
107 void ufs_qcom_phy_qmp_v3_660_set_tx_lane_enable(struct ufs_qcom_phy *phy,
111 * v3 PHY does not have TX_LANE_ENABLE register.
112 * Implement this function so as not to propagate error to caller.
117 void ufs_qcom_phy_qmp_v3_660_ctrl_rx_linecfg(struct ufs_qcom_phy *phy,
122 temp = readl_relaxed(phy->mmio + UFS_PHY_LINECFG_DISABLE);
124 if (ctrl) /* enable RX LineCfg */
125 temp &= ~UFS_PHY_RX_LINECFG_DISABLE_BIT;
126 else /* disable RX LineCfg */
127 temp |= UFS_PHY_RX_LINECFG_DISABLE_BIT;
129 writel_relaxed(temp, phy->mmio + UFS_PHY_LINECFG_DISABLE);
130 /* Make sure that RX LineCfg config applied before we return */
134 static inline void ufs_qcom_phy_qmp_v3_660_start_serdes(
135 struct ufs_qcom_phy *phy)
139 tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
140 tmp &= ~MASK_SERDES_START;
141 tmp |= (1 << OFFSET_SERDES_START);
142 writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START);
143 /* Ensure register value is committed */
147 static int ufs_qcom_phy_qmp_v3_660_is_pcs_ready(
148 struct ufs_qcom_phy *phy_common)
153 err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
154 val, (val & MASK_PCS_READY), 10, 1000000);
156 dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
161 static void ufs_qcom_phy_qmp_v3_660_dbg_register_dump(
162 struct ufs_qcom_phy *phy)
164 ufs_qcom_phy_dump_regs(phy, COM_BASE, COM_SIZE,
165 "PHY QSERDES COM Registers ");
166 ufs_qcom_phy_dump_regs(phy, PHY_BASE, PHY_SIZE,
168 ufs_qcom_phy_dump_regs(phy, RX_BASE, RX_SIZE,
169 "PHY RX0 Registers ");
170 ufs_qcom_phy_dump_regs(phy, TX_BASE, TX_SIZE,
171 "PHY TX0 Registers ");
174 struct phy_ops ufs_qcom_phy_qmp_v3_660_phy_ops = {
175 .init = ufs_qcom_phy_qmp_v3_660_init,
176 .exit = ufs_qcom_phy_exit,
177 .power_on = ufs_qcom_phy_power_on,
178 .power_off = ufs_qcom_phy_power_off,
179 .owner = THIS_MODULE,
182 struct ufs_qcom_phy_specific_ops phy_v3_660_ops = {
183 .calibrate_phy = ufs_qcom_phy_qmp_v3_660_phy_calibrate,
184 .start_serdes = ufs_qcom_phy_qmp_v3_660_start_serdes,
185 .is_physical_coding_sublayer_ready =
186 ufs_qcom_phy_qmp_v3_660_is_pcs_ready,
187 .set_tx_lane_enable = ufs_qcom_phy_qmp_v3_660_set_tx_lane_enable,
188 .ctrl_rx_linecfg = ufs_qcom_phy_qmp_v3_660_ctrl_rx_linecfg,
189 .power_control = ufs_qcom_phy_qmp_v3_660_power_control,
190 .dbg_register_dump = ufs_qcom_phy_qmp_v3_660_dbg_register_dump,
193 static int ufs_qcom_phy_qmp_v3_660_probe(struct platform_device *pdev)
195 struct device *dev = &pdev->dev;
196 struct phy *generic_phy;
197 struct ufs_qcom_phy_qmp_v3_660 *phy;
200 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
206 generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg,
207 &ufs_qcom_phy_qmp_v3_660_phy_ops,
211 dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
217 phy_set_drvdata(generic_phy, phy);
219 strlcpy(phy->common_cfg.name, UFS_PHY_NAME,
220 sizeof(phy->common_cfg.name));
226 static int ufs_qcom_phy_qmp_v3_660_remove(struct platform_device *pdev)
228 struct device *dev = &pdev->dev;
229 struct phy *generic_phy = to_phy(dev);
230 struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
233 err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy);
235 dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n",
241 static const struct of_device_id ufs_qcom_phy_qmp_v3_660_of_match[] = {
242 {.compatible = "qcom,ufs-phy-qmp-v3-660"},
245 MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_v3_660_of_match);
247 static struct platform_driver ufs_qcom_phy_qmp_v3_660_driver = {
248 .probe = ufs_qcom_phy_qmp_v3_660_probe,
249 .remove = ufs_qcom_phy_qmp_v3_660_remove,
251 .of_match_table = ufs_qcom_phy_qmp_v3_660_of_match,
252 .name = "ufs_qcom_phy_qmp_v3_660",
253 .owner = THIS_MODULE,
257 module_platform_driver(ufs_qcom_phy_qmp_v3_660_driver);
259 MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP v3 660");
260 MODULE_LICENSE("GPL v2");