blob: 6834f6a0cdf49812f7c5510c95499e7373a13078 [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
Kyle Yan6a20fae2017-02-14 13:34:41 -080015#include "phy-qcom-ufs-qrbtc-sdm845.h"
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -070016
Kyle Yan6a20fae2017-02-14 13:34:41 -080017#define UFS_PHY_NAME "ufs_phy_qrbtc_sdm845"
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -070018
19static
Kyle Yan6a20fae2017-02-14 13:34:41 -080020int ufs_qcom_phy_qrbtc_sdm845_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -070021 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
Kyle Yan6a20fae2017-02-14 13:34:41 -080047ufs_qcom_phy_qrbtc_sdm845_is_pcs_ready(struct ufs_qcom_phy *phy_common)
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -070048{
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
Kyle Yan6a20fae2017-02-14 13:34:41 -080071static void ufs_qcom_phy_qrbtc_sdm845_start_serdes(struct ufs_qcom_phy *phy)
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -070072{
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
Kyle Yan6a20fae2017-02-14 13:34:41 -080085static int ufs_qcom_phy_qrbtc_sdm845_init(struct phy *generic_phy)
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -070086{
87 return 0;
88}
89
Kyle Yan6a20fae2017-02-14 13:34:41 -080090struct phy_ops ufs_qcom_phy_qrbtc_sdm845_phy_ops = {
91 .init = ufs_qcom_phy_qrbtc_sdm845_init,
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -070092 .exit = ufs_qcom_phy_exit,
93 .owner = THIS_MODULE,
94};
95
Kyle Yan6a20fae2017-02-14 13:34:41 -080096struct ufs_qcom_phy_specific_ops phy_qrbtc_sdm845_ops = {
97 .calibrate_phy = ufs_qcom_phy_qrbtc_sdm845_phy_calibrate,
98 .start_serdes = ufs_qcom_phy_qrbtc_sdm845_start_serdes,
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -070099 .is_physical_coding_sublayer_ready =
Kyle Yan6a20fae2017-02-14 13:34:41 -0800100 ufs_qcom_phy_qrbtc_sdm845_is_pcs_ready,
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -0700101};
102
Kyle Yan6a20fae2017-02-14 13:34:41 -0800103static int ufs_qcom_phy_qrbtc_sdm845_probe(struct platform_device *pdev)
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -0700104{
105 struct device *dev = &pdev->dev;
106 struct phy *generic_phy;
Kyle Yan6a20fae2017-02-14 13:34:41 -0800107 struct ufs_qcom_phy_qrbtc_sdm845 *phy;
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -0700108 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,
Kyle Yan6a20fae2017-02-14 13:34:41 -0800117 &ufs_qcom_phy_qrbtc_sdm845_phy_ops, &phy_qrbtc_sdm845_ops);
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -0700118
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
Kyle Yan6a20fae2017-02-14 13:34:41 -0800135static int ufs_qcom_phy_qrbtc_sdm845_remove(struct platform_device *pdev)
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -0700136{
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
Kyle Yan6a20fae2017-02-14 13:34:41 -0800150static const struct of_device_id ufs_qcom_phy_qrbtc_sdm845_of_match[] = {
151 {.compatible = "qcom,ufs-phy-qrbtc-sdm845"},
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -0700152 {},
153};
Kyle Yan6a20fae2017-02-14 13:34:41 -0800154MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qrbtc_sdm845_of_match);
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -0700155
Kyle Yan6a20fae2017-02-14 13:34:41 -0800156static struct platform_driver ufs_qcom_phy_qrbtc_sdm845_driver = {
157 .probe = ufs_qcom_phy_qrbtc_sdm845_probe,
158 .remove = ufs_qcom_phy_qrbtc_sdm845_remove,
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -0700159 .driver = {
Kyle Yan6a20fae2017-02-14 13:34:41 -0800160 .of_match_table = ufs_qcom_phy_qrbtc_sdm845_of_match,
161 .name = "ufs_qcom_phy_qrbtc_sdm845",
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -0700162 .owner = THIS_MODULE,
163 },
164};
165
Kyle Yan6a20fae2017-02-14 13:34:41 -0800166module_platform_driver(ufs_qcom_phy_qrbtc_sdm845_driver);
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -0700167
Kyle Yan6a20fae2017-02-14 13:34:41 -0800168MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QRBTC SDM845");
Subhash Jadavanid6cf9e62016-08-04 11:41:09 -0700169MODULE_LICENSE("GPL v2");