blob: 61f1232853bfd5c1153b59884e87351620990eac [file] [log] [blame]
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -07001/*
2 * Copyright (c) 2016, 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-qrbtc-msmskunk.h"
16
17#define UFS_PHY_NAME "ufs_phy_qrbtc_msmskunk"
18
19static
20int ufs_qcom_phy_qrbtc_msmskunk_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
27 tbl_A = phy_cal_table_rate_A;
28 tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A);
29
30 tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
31 tbl_B = phy_cal_table_rate_B;
32
33 err = ufs_qcom_phy_calibrate(ufs_qcom_phy,
34 tbl_A, tbl_size_A,
35 tbl_B, tbl_size_B,
36 is_rate_B);
37
38 if (err)
39 dev_err(ufs_qcom_phy->dev,
40 "%s: ufs_qcom_phy_calibrate() failed %d\n",
41 __func__, err);
42
43 return err;
44}
45
46static int
47ufs_qcom_phy_qrbtc_msmskunk_is_pcs_ready(struct ufs_qcom_phy *phy_common)
48{
49 int err = 0;
50 u32 val;
51
52 /*
53 * The value we are polling for is 0x3D which represents the
54 * following masks:
55 * RESET_SM field: 0x5
56 * RESTRIMDONE bit: BIT(3)
57 * PLLLOCK bit: BIT(4)
58 * READY bit: BIT(5)
59 */
60 #define QSERDES_COM_RESET_SM_REG_POLL_VAL 0x3D
61 err = readl_poll_timeout(phy_common->mmio + QSERDES_COM_RESET_SM,
62 val, (val == QSERDES_COM_RESET_SM_REG_POLL_VAL), 10, 1000000);
63
64 if (err)
65 dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
66 __func__, err);
67
68 return err;
69}
70
71static void ufs_qcom_phy_qrbtc_msmskunk_start_serdes(struct ufs_qcom_phy *phy)
72{
73 u32 temp;
74
75 writel_relaxed(0x01, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
76
77 temp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
78 temp |= 0x1;
79 writel_relaxed(temp, phy->mmio + UFS_PHY_PHY_START);
80
81 /* Ensure register value is committed */
82 mb();
83}
84
85static int ufs_qcom_phy_qrbtc_msmskunk_init(struct phy *generic_phy)
86{
87 return 0;
88}
89
90struct phy_ops ufs_qcom_phy_qrbtc_msmskunk_phy_ops = {
91 .init = ufs_qcom_phy_qrbtc_msmskunk_init,
92 .exit = ufs_qcom_phy_exit,
93 .owner = THIS_MODULE,
94};
95
96struct ufs_qcom_phy_specific_ops phy_qrbtc_msmskunk_ops = {
97 .calibrate_phy = ufs_qcom_phy_qrbtc_msmskunk_phy_calibrate,
98 .start_serdes = ufs_qcom_phy_qrbtc_msmskunk_start_serdes,
99 .is_physical_coding_sublayer_ready =
100 ufs_qcom_phy_qrbtc_msmskunk_is_pcs_ready,
101};
102
103static int ufs_qcom_phy_qrbtc_msmskunk_probe(struct platform_device *pdev)
104{
105 struct device *dev = &pdev->dev;
106 struct phy *generic_phy;
107 struct ufs_qcom_phy_qrbtc_msmskunk *phy;
108 int err = 0;
109
110 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
111 if (!phy) {
112 err = -ENOMEM;
113 goto out;
114 }
115
116 generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg,
117 &ufs_qcom_phy_qrbtc_msmskunk_phy_ops, &phy_qrbtc_msmskunk_ops);
118
119 if (!generic_phy) {
120 dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
121 __func__);
122 err = -EIO;
123 goto out;
124 }
125
126 phy_set_drvdata(generic_phy, phy);
127
128 strlcpy(phy->common_cfg.name, UFS_PHY_NAME,
129 sizeof(phy->common_cfg.name));
130
131out:
132 return err;
133}
134
135static int ufs_qcom_phy_qrbtc_msmskunk_remove(struct platform_device *pdev)
136{
137 struct device *dev = &pdev->dev;
138 struct phy *generic_phy = to_phy(dev);
139 struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
140 int err = 0;
141
142 err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy);
143 if (err)
144 dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n",
145 __func__, err);
146
147 return err;
148}
149
150static const struct of_device_id ufs_qcom_phy_qrbtc_msmskunk_of_match[] = {
151 {.compatible = "qcom,ufs-phy-qrbtc-msmskunk"},
152 {},
153};
154MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qrbtc_msmskunk_of_match);
155
156static struct platform_driver ufs_qcom_phy_qrbtc_msmskunk_driver = {
157 .probe = ufs_qcom_phy_qrbtc_msmskunk_probe,
158 .remove = ufs_qcom_phy_qrbtc_msmskunk_remove,
159 .driver = {
160 .of_match_table = ufs_qcom_phy_qrbtc_msmskunk_of_match,
161 .name = "ufs_qcom_phy_qrbtc_msmskunk",
162 .owner = THIS_MODULE,
163 },
164};
165
166module_platform_driver(ufs_qcom_phy_qrbtc_msmskunk_driver);
167
168MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QRBTC MSMSKUNK");
169MODULE_LICENSE("GPL v2");