OSDN Git Service

Merge android-4.4@ceee5bd (v4.4.95) into msm-4.4
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / phy / phy-qcom-ufs-qmp-14nm.c
1 /*
2  * Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
3  *
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.
7  *
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.
12  *
13  */
14
15 #include "phy-qcom-ufs-qmp-14nm.h"
16
17 #define UFS_PHY_NAME "ufs_phy_qmp_14nm"
18
19 static
20 int ufs_qcom_phy_qmp_14nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
21                                         bool is_rate_B)
22 {
23         int err;
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;
29
30         tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
31         tbl_B = phy_cal_table_rate_B;
32
33         if ((major == 0x2) && (minor == 0x000) && (step == 0x0000)) {
34                 tbl_A = phy_cal_table_rate_A_2_0_0;
35                 tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_2_0_0);
36         } else if ((major == 0x2) && (minor == 0x001) && (step == 0x0000)) {
37                 tbl_A = phy_cal_table_rate_A_2_1_0;
38                 tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_2_1_0);
39         } else if ((major == 0x2) && (minor == 0x002) && (step == 0x0000)) {
40                 tbl_A = phy_cal_table_rate_A_2_2_0;
41                 tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_2_2_0);
42                 tbl_B = phy_cal_table_rate_B_2_2_0;
43                 tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B_2_2_0);
44         } else {
45                 dev_err(ufs_qcom_phy->dev,
46                         "%s: Unknown UFS-PHY version (major 0x%x minor 0x%x step 0x%x), no calibration values\n",
47                         __func__, major, minor, step);
48                 err = -ENODEV;
49                 goto out;
50         }
51
52         err = ufs_qcom_phy_calibrate(ufs_qcom_phy,
53                                      tbl_A, tbl_size_A,
54                                      tbl_B, tbl_size_B,
55                                      is_rate_B);
56
57         if (ufs_qcom_phy->quirks & UFS_QCOM_PHY_QUIRK_VCO_MANUAL_TUNING)
58                 writel_relaxed(ufs_qcom_phy->vco_tune1_mode1,
59                         ufs_qcom_phy->mmio + QSERDES_COM_VCO_TUNE1_MODE1);
60 out:
61         if (err)
62                 dev_err(ufs_qcom_phy->dev,
63                         "%s: ufs_qcom_phy_calibrate() failed %d\n",
64                         __func__, err);
65         return err;
66 }
67
68 static
69 void ufs_qcom_phy_qmp_14nm_advertise_quirks(struct ufs_qcom_phy *phy_common)
70 {
71         u8 major = phy_common->host_ctrl_rev_major;
72         u16 minor = phy_common->host_ctrl_rev_minor;
73         u16 step = phy_common->host_ctrl_rev_step;
74
75         if ((major == 0x2) && (minor == 0x000) && (step == 0x0000))
76                 phy_common->quirks =
77                         UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE |
78                         UFS_QCOM_PHY_QUIRK_SVS_MODE |
79                         UFS_QCOM_PHY_QUIRK_VCO_MANUAL_TUNING;
80 }
81
82 static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy)
83 {
84         struct ufs_qcom_phy_qmp_14nm *phy = phy_get_drvdata(generic_phy);
85         struct ufs_qcom_phy *phy_common = &phy->common_cfg;
86         int err;
87
88         err = ufs_qcom_phy_init_clks(generic_phy, phy_common);
89         if (err) {
90                 dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n",
91                         __func__, err);
92                 goto out;
93         }
94
95         err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common);
96         if (err) {
97                 dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
98                         __func__, err);
99                 goto out;
100         }
101
102         ufs_qcom_phy_qmp_14nm_advertise_quirks(phy_common);
103
104         if (phy_common->quirks & UFS_QCOM_PHY_QUIRK_VCO_MANUAL_TUNING) {
105                 phy_common->vco_tune1_mode1 = readl_relaxed(phy_common->mmio +
106                                                 QSERDES_COM_VCO_TUNE1_MODE1);
107                 dev_info(phy_common->dev, "%s: vco_tune1_mode1 0x%x\n",
108                         __func__, phy_common->vco_tune1_mode1);
109         }
110
111 out:
112         return err;
113 }
114
115 static
116 void ufs_qcom_phy_qmp_14nm_power_control(struct ufs_qcom_phy *phy,
117                                          bool power_ctrl)
118 {
119         bool is_workaround_req = false;
120
121         if (phy->quirks &
122             UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE)
123                 is_workaround_req = true;
124
125         if (!power_ctrl) {
126                 /* apply PHY analog power collapse */
127                 if (is_workaround_req) {
128                         /* assert common reset before analog power collapse */
129                         writel_relaxed(0x1, phy->mmio + QSERDES_COM_SW_RESET);
130                         /*
131                          * make sure that reset is propogated before analog
132                          * power collapse
133                          */
134                         mb();
135                 }
136                 /* apply analog power collapse */
137                 writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
138                 /*
139                  * Make sure that PHY knows its analog rail is going to be
140                  * powered OFF.
141                  */
142                 mb();
143         } else {
144                 /* bring PHY out of analog power collapse */
145                 writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
146                 /*
147                  * Before any transactions involving PHY, ensure PHY knows
148                  * that it's analog rail is powered ON.
149                  */
150                 mb();
151                 if (is_workaround_req) {
152                         /*
153                          * de-assert common reset after coming out of analog
154                          * power collapse
155                          */
156                         writel_relaxed(0x0, phy->mmio + QSERDES_COM_SW_RESET);
157                         /* make common reset is de-asserted before proceeding */
158                         mb();
159                 }
160         }
161 }
162
163 static inline
164 void ufs_qcom_phy_qmp_14nm_set_tx_lane_enable(struct ufs_qcom_phy *phy, u32 val)
165 {
166         /*
167          * 14nm PHY does not have TX_LANE_ENABLE register.
168          * Implement this function so as not to propagate error to caller.
169          */
170 }
171
172 static
173 void ufs_qcom_phy_qmp_14nm_ctrl_rx_linecfg(struct ufs_qcom_phy *phy, bool ctrl)
174 {
175         u32 temp;
176
177         temp = readl_relaxed(phy->mmio + UFS_PHY_LINECFG_DISABLE);
178
179         if (ctrl) /* enable RX LineCfg */
180                 temp &= ~UFS_PHY_RX_LINECFG_DISABLE_BIT;
181         else /* disable RX LineCfg */
182                 temp |= UFS_PHY_RX_LINECFG_DISABLE_BIT;
183
184         writel_relaxed(temp, phy->mmio + UFS_PHY_LINECFG_DISABLE);
185         /* make sure that RX LineCfg config applied before we return */
186         mb();
187 }
188
189 static inline void ufs_qcom_phy_qmp_14nm_start_serdes(struct ufs_qcom_phy *phy)
190 {
191         u32 tmp;
192
193         tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
194         tmp &= ~MASK_SERDES_START;
195         tmp |= (1 << OFFSET_SERDES_START);
196         writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START);
197         /* Ensure register value is committed */
198         mb();
199 }
200
201 static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
202 {
203         int err = 0;
204         u32 val;
205
206         err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
207                 val, (val & MASK_PCS_READY), 10, 1000000);
208         if (err) {
209                 dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
210                         __func__, err);
211                 goto out;
212         }
213
214         if (phy_common->quirks & UFS_QCOM_PHY_QUIRK_SVS_MODE) {
215                 int i;
216
217                 for (i = 0; i < ARRAY_SIZE(phy_svs_mode_config_2_0_0); i++)
218                         writel_relaxed(phy_svs_mode_config_2_0_0[i].cfg_value,
219                                 (phy_common->mmio +
220                                 phy_svs_mode_config_2_0_0[i].reg_offset));
221                 /* apply above configuration immediately */
222                 mb();
223         }
224
225 out:
226         return err;
227 }
228
229 static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = {
230         .init           = ufs_qcom_phy_qmp_14nm_init,
231         .exit           = ufs_qcom_phy_exit,
232         .power_on       = ufs_qcom_phy_power_on,
233         .power_off      = ufs_qcom_phy_power_off,
234         .owner          = THIS_MODULE,
235 };
236
237 static struct ufs_qcom_phy_specific_ops phy_14nm_ops = {
238         .calibrate_phy          = ufs_qcom_phy_qmp_14nm_phy_calibrate,
239         .start_serdes           = ufs_qcom_phy_qmp_14nm_start_serdes,
240         .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_14nm_is_pcs_ready,
241         .set_tx_lane_enable     = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable,
242         .ctrl_rx_linecfg        = ufs_qcom_phy_qmp_14nm_ctrl_rx_linecfg,
243         .power_control          = ufs_qcom_phy_qmp_14nm_power_control,
244 };
245
246 static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev)
247 {
248         struct device *dev = &pdev->dev;
249         struct phy *generic_phy;
250         struct ufs_qcom_phy_qmp_14nm *phy;
251         int err = 0;
252
253         phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
254         if (!phy) {
255                 dev_err(dev, "%s: failed to allocate phy\n", __func__);
256                 err = -ENOMEM;
257                 goto out;
258         }
259
260         generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg,
261                                 &ufs_qcom_phy_qmp_14nm_phy_ops, &phy_14nm_ops);
262
263         if (!generic_phy) {
264                 dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
265                         __func__);
266                 err = -EIO;
267                 goto out;
268         }
269
270         phy_set_drvdata(generic_phy, phy);
271
272         strlcpy(phy->common_cfg.name, UFS_PHY_NAME,
273                 sizeof(phy->common_cfg.name));
274
275 out:
276         return err;
277 }
278
279 static int ufs_qcom_phy_qmp_14nm_remove(struct platform_device *pdev)
280 {
281         struct device *dev = &pdev->dev;
282         struct phy *generic_phy = to_phy(dev);
283         struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
284         int err = 0;
285
286         err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy);
287         if (err)
288                 dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n",
289                         __func__, err);
290
291         return err;
292 }
293
294 static const struct of_device_id ufs_qcom_phy_qmp_14nm_of_match[] = {
295         {.compatible = "qcom,ufs-phy-qmp-14nm"},
296         {},
297 };
298 MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_14nm_of_match);
299
300 static struct platform_driver ufs_qcom_phy_qmp_14nm_driver = {
301         .probe = ufs_qcom_phy_qmp_14nm_probe,
302         .remove = ufs_qcom_phy_qmp_14nm_remove,
303         .driver = {
304                 .of_match_table = ufs_qcom_phy_qmp_14nm_of_match,
305                 .name = "ufs_qcom_phy_qmp_14nm",
306         },
307 };
308
309 module_platform_driver(ufs_qcom_phy_qmp_14nm_driver);
310
311 MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP 14nm");
312 MODULE_LICENSE("GPL v2");