OSDN Git Service

Merge "ASoC: sdm660_cdc: Prevent MICBIAS1 enable during headset record"
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / phy / phy-qcom-ufs-qmp-v3-660.c
1 /*
2  * Copyright (c) 2013-2016, The 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-v3-660.h"
16
17 #define UFS_PHY_NAME "ufs_phy_qmp_v3_660"
18
19 static
20 int ufs_qcom_phy_qmp_v3_660_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 == 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);
36         } else {
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);
40                 err = -ENODEV;
41                 goto out;
42         }
43
44         err = ufs_qcom_phy_calibrate(ufs_qcom_phy,
45                                      tbl_A, tbl_size_A,
46                                      tbl_B, tbl_size_B,
47                                      is_rate_B);
48
49         if (err)
50                 dev_err(ufs_qcom_phy->dev,
51                         "%s: ufs_qcom_phy_calibrate() failed %d\n",
52                         __func__, err);
53
54 out:
55         return err;
56 }
57
58 static int ufs_qcom_phy_qmp_v3_660_init(struct phy *generic_phy)
59 {
60         struct ufs_qcom_phy_qmp_v3_660 *phy = phy_get_drvdata(generic_phy);
61         struct ufs_qcom_phy *phy_common = &phy->common_cfg;
62         int err;
63
64         err = ufs_qcom_phy_init_clks(generic_phy, phy_common);
65         if (err) {
66                 dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n",
67                         __func__, err);
68                 goto out;
69         }
70
71         err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common);
72         if (err) {
73                 dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
74                         __func__, err);
75                 goto out;
76         }
77
78 out:
79         return err;
80 }
81
82 static
83 void ufs_qcom_phy_qmp_v3_660_power_control(struct ufs_qcom_phy *phy,
84                                          bool power_ctrl)
85 {
86         if (!power_ctrl) {
87                 /* apply analog power collapse */
88                 writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
89                 /*
90                  * Make sure that PHY knows its analog rail is going to be
91                  * powered OFF.
92                  */
93                 mb();
94         } else {
95                 /* bring PHY out of analog power collapse */
96                 writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
97
98                 /*
99                  * Before any transactions involving PHY, ensure PHY knows
100                  * that it's analog rail is powered ON.
101                  */
102                 mb();
103         }
104 }
105
106 static inline
107 void ufs_qcom_phy_qmp_v3_660_set_tx_lane_enable(struct ufs_qcom_phy *phy,
108                                                    u32 val)
109 {
110         /*
111          * v3 PHY does not have TX_LANE_ENABLE register.
112          * Implement this function so as not to propagate error to caller.
113          */
114 }
115
116 static
117 void ufs_qcom_phy_qmp_v3_660_ctrl_rx_linecfg(struct ufs_qcom_phy *phy,
118                                                 bool ctrl)
119 {
120         u32 temp;
121
122         temp = readl_relaxed(phy->mmio + UFS_PHY_LINECFG_DISABLE);
123
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;
128
129         writel_relaxed(temp, phy->mmio + UFS_PHY_LINECFG_DISABLE);
130         /* Make sure that RX LineCfg config applied before we return */
131         mb();
132 }
133
134 static inline void ufs_qcom_phy_qmp_v3_660_start_serdes(
135                                         struct ufs_qcom_phy *phy)
136 {
137         u32 tmp;
138
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 */
144         mb();
145 }
146
147 static int ufs_qcom_phy_qmp_v3_660_is_pcs_ready(
148                                 struct ufs_qcom_phy *phy_common)
149 {
150         int err = 0;
151         u32 val;
152
153         err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
154                 val, (val & MASK_PCS_READY), 10, 1000000);
155         if (err)
156                 dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
157                         __func__, err);
158         return err;
159 }
160
161 static void ufs_qcom_phy_qmp_v3_660_dbg_register_dump(
162                                         struct ufs_qcom_phy *phy)
163 {
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,
167                                         "PHY Registers ");
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 ");
172 }
173
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,
180 };
181
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,
191 };
192
193 static int ufs_qcom_phy_qmp_v3_660_probe(struct platform_device *pdev)
194 {
195         struct device *dev = &pdev->dev;
196         struct phy *generic_phy;
197         struct ufs_qcom_phy_qmp_v3_660 *phy;
198         int err = 0;
199
200         phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
201         if (!phy) {
202                 err = -ENOMEM;
203                 goto out;
204         }
205
206         generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg,
207                                 &ufs_qcom_phy_qmp_v3_660_phy_ops,
208                                 &phy_v3_660_ops);
209
210         if (!generic_phy) {
211                 dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
212                         __func__);
213                 err = -EIO;
214                 goto out;
215         }
216
217         phy_set_drvdata(generic_phy, phy);
218
219         strlcpy(phy->common_cfg.name, UFS_PHY_NAME,
220                 sizeof(phy->common_cfg.name));
221
222 out:
223         return err;
224 }
225
226 static int ufs_qcom_phy_qmp_v3_660_remove(struct platform_device *pdev)
227 {
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);
231         int err = 0;
232
233         err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy);
234         if (err)
235                 dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n",
236                         __func__, err);
237
238         return err;
239 }
240
241 static const struct of_device_id ufs_qcom_phy_qmp_v3_660_of_match[] = {
242         {.compatible = "qcom,ufs-phy-qmp-v3-660"},
243         {},
244 };
245 MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_v3_660_of_match);
246
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,
250         .driver = {
251                 .of_match_table = ufs_qcom_phy_qmp_v3_660_of_match,
252                 .name = "ufs_qcom_phy_qmp_v3_660",
253                 .owner = THIS_MODULE,
254         },
255 };
256
257 module_platform_driver(ufs_qcom_phy_qmp_v3_660_driver);
258
259 MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP v3 660");
260 MODULE_LICENSE("GPL v2");