dmaengine: imx-sdma: Let the core do the device node validation
[linux/fpc-iii.git] / drivers / scsi / ufs / ufs-mediatek.c
blob0f6ff33ce52eea963c64c5d76e1071d37a23cb9f
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2019 MediaTek Inc.
4 * Authors:
5 * Stanley Chu <stanley.chu@mediatek.com>
6 * Peter Wang <peter.wang@mediatek.com>
7 */
9 #include <linux/of.h>
10 #include <linux/of_address.h>
11 #include <linux/phy/phy.h>
12 #include <linux/platform_device.h>
14 #include "ufshcd.h"
15 #include "ufshcd-pltfrm.h"
16 #include "unipro.h"
17 #include "ufs-mediatek.h"
19 static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable)
21 u32 tmp;
23 if (enable) {
24 ufshcd_dme_get(hba,
25 UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
26 tmp = tmp |
27 (1 << RX_SYMBOL_CLK_GATE_EN) |
28 (1 << SYS_CLK_GATE_EN) |
29 (1 << TX_CLK_GATE_EN);
30 ufshcd_dme_set(hba,
31 UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
33 ufshcd_dme_get(hba,
34 UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
35 tmp = tmp & ~(1 << TX_SYMBOL_CLK_REQ_FORCE);
36 ufshcd_dme_set(hba,
37 UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
38 } else {
39 ufshcd_dme_get(hba,
40 UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
41 tmp = tmp & ~((1 << RX_SYMBOL_CLK_GATE_EN) |
42 (1 << SYS_CLK_GATE_EN) |
43 (1 << TX_CLK_GATE_EN));
44 ufshcd_dme_set(hba,
45 UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
47 ufshcd_dme_get(hba,
48 UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
49 tmp = tmp | (1 << TX_SYMBOL_CLK_REQ_FORCE);
50 ufshcd_dme_set(hba,
51 UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
55 static int ufs_mtk_bind_mphy(struct ufs_hba *hba)
57 struct ufs_mtk_host *host = ufshcd_get_variant(hba);
58 struct device *dev = hba->dev;
59 struct device_node *np = dev->of_node;
60 int err = 0;
62 host->mphy = devm_of_phy_get_by_index(dev, np, 0);
64 if (host->mphy == ERR_PTR(-EPROBE_DEFER)) {
66 * UFS driver might be probed before the phy driver does.
67 * In that case we would like to return EPROBE_DEFER code.
69 err = -EPROBE_DEFER;
70 dev_info(dev,
71 "%s: required phy hasn't probed yet. err = %d\n",
72 __func__, err);
73 } else if (IS_ERR(host->mphy)) {
74 err = PTR_ERR(host->mphy);
75 dev_info(dev, "%s: PHY get failed %d\n", __func__, err);
78 if (err)
79 host->mphy = NULL;
81 return err;
84 /**
85 * ufs_mtk_setup_clocks - enables/disable clocks
86 * @hba: host controller instance
87 * @on: If true, enable clocks else disable them.
88 * @status: PRE_CHANGE or POST_CHANGE notify
90 * Returns 0 on success, non-zero on failure.
92 static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
93 enum ufs_notify_change_status status)
95 struct ufs_mtk_host *host = ufshcd_get_variant(hba);
96 int ret = -EINVAL;
99 * In case ufs_mtk_init() is not yet done, simply ignore.
100 * This ufs_mtk_setup_clocks() shall be called from
101 * ufs_mtk_init() after init is done.
103 if (!host)
104 return 0;
106 switch (status) {
107 case PRE_CHANGE:
108 if (!on)
109 ret = phy_power_off(host->mphy);
110 break;
111 case POST_CHANGE:
112 if (on)
113 ret = phy_power_on(host->mphy);
114 break;
117 return ret;
121 * ufs_mtk_init - find other essential mmio bases
122 * @hba: host controller instance
124 * Binds PHY with controller and powers up PHY enabling clocks
125 * and regulators.
127 * Returns -EPROBE_DEFER if binding fails, returns negative error
128 * on phy power up failure and returns zero on success.
130 static int ufs_mtk_init(struct ufs_hba *hba)
132 struct ufs_mtk_host *host;
133 struct device *dev = hba->dev;
134 int err = 0;
136 host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
137 if (!host) {
138 err = -ENOMEM;
139 dev_info(dev, "%s: no memory for mtk ufs host\n", __func__);
140 goto out;
143 host->hba = hba;
144 ufshcd_set_variant(hba, host);
146 err = ufs_mtk_bind_mphy(hba);
147 if (err)
148 goto out_variant_clear;
151 * ufshcd_vops_init() is invoked after
152 * ufshcd_setup_clock(true) in ufshcd_hba_init() thus
153 * phy clock setup is skipped.
155 * Enable phy clocks specifically here.
157 ufs_mtk_setup_clocks(hba, true, POST_CHANGE);
159 goto out;
161 out_variant_clear:
162 ufshcd_set_variant(hba, NULL);
163 out:
164 return err;
167 static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
168 struct ufs_pa_layer_attr *dev_max_params,
169 struct ufs_pa_layer_attr *dev_req_params)
171 struct ufs_dev_params host_cap;
172 int ret;
174 host_cap.tx_lanes = UFS_MTK_LIMIT_NUM_LANES_TX;
175 host_cap.rx_lanes = UFS_MTK_LIMIT_NUM_LANES_RX;
176 host_cap.hs_rx_gear = UFS_MTK_LIMIT_HSGEAR_RX;
177 host_cap.hs_tx_gear = UFS_MTK_LIMIT_HSGEAR_TX;
178 host_cap.pwm_rx_gear = UFS_MTK_LIMIT_PWMGEAR_RX;
179 host_cap.pwm_tx_gear = UFS_MTK_LIMIT_PWMGEAR_TX;
180 host_cap.rx_pwr_pwm = UFS_MTK_LIMIT_RX_PWR_PWM;
181 host_cap.tx_pwr_pwm = UFS_MTK_LIMIT_TX_PWR_PWM;
182 host_cap.rx_pwr_hs = UFS_MTK_LIMIT_RX_PWR_HS;
183 host_cap.tx_pwr_hs = UFS_MTK_LIMIT_TX_PWR_HS;
184 host_cap.hs_rate = UFS_MTK_LIMIT_HS_RATE;
185 host_cap.desired_working_mode =
186 UFS_MTK_LIMIT_DESIRED_MODE;
188 ret = ufshcd_get_pwr_dev_param(&host_cap,
189 dev_max_params,
190 dev_req_params);
191 if (ret) {
192 pr_info("%s: failed to determine capabilities\n",
193 __func__);
196 return ret;
199 static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba,
200 enum ufs_notify_change_status stage,
201 struct ufs_pa_layer_attr *dev_max_params,
202 struct ufs_pa_layer_attr *dev_req_params)
204 int ret = 0;
206 switch (stage) {
207 case PRE_CHANGE:
208 ret = ufs_mtk_pre_pwr_change(hba, dev_max_params,
209 dev_req_params);
210 break;
211 case POST_CHANGE:
212 break;
213 default:
214 ret = -EINVAL;
215 break;
218 return ret;
221 static int ufs_mtk_pre_link(struct ufs_hba *hba)
223 int ret;
224 u32 tmp;
226 /* disable deep stall */
227 ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
228 if (ret)
229 return ret;
231 tmp &= ~(1 << 6);
233 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
235 return ret;
238 static int ufs_mtk_post_link(struct ufs_hba *hba)
240 /* disable device LCC */
241 ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0);
243 /* enable unipro clock gating feature */
244 ufs_mtk_cfg_unipro_cg(hba, true);
246 return 0;
249 static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
250 enum ufs_notify_change_status stage)
252 int ret = 0;
254 switch (stage) {
255 case PRE_CHANGE:
256 ret = ufs_mtk_pre_link(hba);
257 break;
258 case POST_CHANGE:
259 ret = ufs_mtk_post_link(hba);
260 break;
261 default:
262 ret = -EINVAL;
263 break;
266 return ret;
269 static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
271 struct ufs_mtk_host *host = ufshcd_get_variant(hba);
273 if (ufshcd_is_link_hibern8(hba))
274 phy_power_off(host->mphy);
276 return 0;
279 static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
281 struct ufs_mtk_host *host = ufshcd_get_variant(hba);
283 if (ufshcd_is_link_hibern8(hba))
284 phy_power_on(host->mphy);
286 return 0;
290 * struct ufs_hba_mtk_vops - UFS MTK specific variant operations
292 * The variant operations configure the necessary controller and PHY
293 * handshake during initialization.
295 static struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
296 .name = "mediatek.ufshci",
297 .init = ufs_mtk_init,
298 .setup_clocks = ufs_mtk_setup_clocks,
299 .link_startup_notify = ufs_mtk_link_startup_notify,
300 .pwr_change_notify = ufs_mtk_pwr_change_notify,
301 .suspend = ufs_mtk_suspend,
302 .resume = ufs_mtk_resume,
306 * ufs_mtk_probe - probe routine of the driver
307 * @pdev: pointer to Platform device handle
309 * Return zero for success and non-zero for failure
311 static int ufs_mtk_probe(struct platform_device *pdev)
313 int err;
314 struct device *dev = &pdev->dev;
316 /* perform generic probe */
317 err = ufshcd_pltfrm_init(pdev, &ufs_hba_mtk_vops);
318 if (err)
319 dev_info(dev, "probe failed %d\n", err);
321 return err;
325 * ufs_mtk_remove - set driver_data of the device to NULL
326 * @pdev: pointer to platform device handle
328 * Always return 0
330 static int ufs_mtk_remove(struct platform_device *pdev)
332 struct ufs_hba *hba = platform_get_drvdata(pdev);
334 pm_runtime_get_sync(&(pdev)->dev);
335 ufshcd_remove(hba);
336 return 0;
339 static const struct of_device_id ufs_mtk_of_match[] = {
340 { .compatible = "mediatek,mt8183-ufshci"},
344 static const struct dev_pm_ops ufs_mtk_pm_ops = {
345 .suspend = ufshcd_pltfrm_suspend,
346 .resume = ufshcd_pltfrm_resume,
347 .runtime_suspend = ufshcd_pltfrm_runtime_suspend,
348 .runtime_resume = ufshcd_pltfrm_runtime_resume,
349 .runtime_idle = ufshcd_pltfrm_runtime_idle,
352 static struct platform_driver ufs_mtk_pltform = {
353 .probe = ufs_mtk_probe,
354 .remove = ufs_mtk_remove,
355 .shutdown = ufshcd_pltfrm_shutdown,
356 .driver = {
357 .name = "ufshcd-mtk",
358 .pm = &ufs_mtk_pm_ops,
359 .of_match_table = ufs_mtk_of_match,
363 MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>");
364 MODULE_AUTHOR("Peter Wang <peter.wang@mediatek.com>");
365 MODULE_DESCRIPTION("MediaTek UFS Host Driver");
366 MODULE_LICENSE("GPL v2");
368 module_platform_driver(ufs_mtk_pltform);