1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2019 MediaTek Inc.
4 * Author: Stanley Chu <stanley.chu@mediatek.com>
8 #include <linux/delay.h>
10 #include <linux/mod_devicetable.h>
11 #include <linux/module.h>
12 #include <linux/phy/phy.h>
13 #include <linux/platform_device.h>
15 #include "phy-mtk-io.h"
17 /* mphy register and offsets */
18 #define MP_GLB_DIG_8C 0x008C
19 #define FRC_PLL_ISO_EN BIT(8)
20 #define PLL_ISO_EN BIT(9)
21 #define FRC_FRC_PWR_ON BIT(10)
22 #define PLL_PWR_ON BIT(11)
24 #define MP_LN_DIG_RX_9C 0xA09C
25 #define FSM_DIFZ_FRC BIT(18)
27 #define MP_LN_DIG_RX_AC 0xA0AC
28 #define FRC_RX_SQ_EN BIT(0)
29 #define RX_SQ_EN BIT(1)
31 #define MP_LN_RX_44 0xB044
32 #define FRC_CDR_PWR_ON BIT(17)
33 #define CDR_PWR_ON BIT(18)
34 #define FRC_CDR_ISO_EN BIT(19)
35 #define CDR_ISO_EN BIT(20)
37 #define UFSPHY_CLKS_CNT 2
42 struct clk_bulk_data clks
[UFSPHY_CLKS_CNT
];
45 static struct ufs_mtk_phy
*get_ufs_mtk_phy(struct phy
*generic_phy
)
47 return (struct ufs_mtk_phy
*)phy_get_drvdata(generic_phy
);
50 static int ufs_mtk_phy_clk_init(struct ufs_mtk_phy
*phy
)
52 struct device
*dev
= phy
->dev
;
53 struct clk_bulk_data
*clks
= phy
->clks
;
55 clks
[0].id
= "unipro";
57 return devm_clk_bulk_get(dev
, UFSPHY_CLKS_CNT
, clks
);
60 static void ufs_mtk_phy_set_active(struct ufs_mtk_phy
*phy
)
62 void __iomem
*mmio
= phy
->mmio
;
64 /* release DA_MP_PLL_PWR_ON */
65 mtk_phy_set_bits(mmio
+ MP_GLB_DIG_8C
, PLL_PWR_ON
);
66 mtk_phy_clear_bits(mmio
+ MP_GLB_DIG_8C
, FRC_FRC_PWR_ON
);
68 /* release DA_MP_PLL_ISO_EN */
69 mtk_phy_clear_bits(mmio
+ MP_GLB_DIG_8C
, PLL_ISO_EN
);
70 mtk_phy_clear_bits(mmio
+ MP_GLB_DIG_8C
, FRC_PLL_ISO_EN
);
72 /* release DA_MP_CDR_PWR_ON */
73 mtk_phy_set_bits(mmio
+ MP_LN_RX_44
, CDR_PWR_ON
);
74 mtk_phy_clear_bits(mmio
+ MP_LN_RX_44
, FRC_CDR_PWR_ON
);
76 /* release DA_MP_CDR_ISO_EN */
77 mtk_phy_clear_bits(mmio
+ MP_LN_RX_44
, CDR_ISO_EN
);
78 mtk_phy_clear_bits(mmio
+ MP_LN_RX_44
, FRC_CDR_ISO_EN
);
80 /* release DA_MP_RX0_SQ_EN */
81 mtk_phy_set_bits(mmio
+ MP_LN_DIG_RX_AC
, RX_SQ_EN
);
82 mtk_phy_clear_bits(mmio
+ MP_LN_DIG_RX_AC
, FRC_RX_SQ_EN
);
84 /* delay 1us to wait DIFZ stable */
88 mtk_phy_clear_bits(mmio
+ MP_LN_DIG_RX_9C
, FSM_DIFZ_FRC
);
91 static void ufs_mtk_phy_set_deep_hibern(struct ufs_mtk_phy
*phy
)
93 void __iomem
*mmio
= phy
->mmio
;
96 mtk_phy_set_bits(mmio
+ MP_LN_DIG_RX_9C
, FSM_DIFZ_FRC
);
98 /* force DA_MP_RX0_SQ_EN */
99 mtk_phy_set_bits(mmio
+ MP_LN_DIG_RX_AC
, FRC_RX_SQ_EN
);
100 mtk_phy_clear_bits(mmio
+ MP_LN_DIG_RX_AC
, RX_SQ_EN
);
102 /* force DA_MP_CDR_ISO_EN */
103 mtk_phy_set_bits(mmio
+ MP_LN_RX_44
, FRC_CDR_ISO_EN
);
104 mtk_phy_set_bits(mmio
+ MP_LN_RX_44
, CDR_ISO_EN
);
106 /* force DA_MP_CDR_PWR_ON */
107 mtk_phy_set_bits(mmio
+ MP_LN_RX_44
, FRC_CDR_PWR_ON
);
108 mtk_phy_clear_bits(mmio
+ MP_LN_RX_44
, CDR_PWR_ON
);
110 /* force DA_MP_PLL_ISO_EN */
111 mtk_phy_set_bits(mmio
+ MP_GLB_DIG_8C
, FRC_PLL_ISO_EN
);
112 mtk_phy_set_bits(mmio
+ MP_GLB_DIG_8C
, PLL_ISO_EN
);
114 /* force DA_MP_PLL_PWR_ON */
115 mtk_phy_set_bits(mmio
+ MP_GLB_DIG_8C
, FRC_FRC_PWR_ON
);
116 mtk_phy_clear_bits(mmio
+ MP_GLB_DIG_8C
, PLL_PWR_ON
);
119 static int ufs_mtk_phy_power_on(struct phy
*generic_phy
)
121 struct ufs_mtk_phy
*phy
= get_ufs_mtk_phy(generic_phy
);
124 ret
= clk_bulk_prepare_enable(UFSPHY_CLKS_CNT
, phy
->clks
);
128 ufs_mtk_phy_set_active(phy
);
133 static int ufs_mtk_phy_power_off(struct phy
*generic_phy
)
135 struct ufs_mtk_phy
*phy
= get_ufs_mtk_phy(generic_phy
);
137 ufs_mtk_phy_set_deep_hibern(phy
);
139 clk_bulk_disable_unprepare(UFSPHY_CLKS_CNT
, phy
->clks
);
144 static const struct phy_ops ufs_mtk_phy_ops
= {
145 .power_on
= ufs_mtk_phy_power_on
,
146 .power_off
= ufs_mtk_phy_power_off
,
147 .owner
= THIS_MODULE
,
150 static int ufs_mtk_phy_probe(struct platform_device
*pdev
)
152 struct device
*dev
= &pdev
->dev
;
153 struct phy
*generic_phy
;
154 struct phy_provider
*phy_provider
;
155 struct ufs_mtk_phy
*phy
;
158 phy
= devm_kzalloc(dev
, sizeof(*phy
), GFP_KERNEL
);
162 phy
->mmio
= devm_platform_ioremap_resource(pdev
, 0);
163 if (IS_ERR(phy
->mmio
))
164 return PTR_ERR(phy
->mmio
);
168 ret
= ufs_mtk_phy_clk_init(phy
);
172 generic_phy
= devm_phy_create(dev
, NULL
, &ufs_mtk_phy_ops
);
173 if (IS_ERR(generic_phy
))
174 return PTR_ERR(generic_phy
);
176 phy_set_drvdata(generic_phy
, phy
);
178 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
180 return PTR_ERR_OR_ZERO(phy_provider
);
183 static const struct of_device_id ufs_mtk_phy_of_match
[] = {
184 {.compatible
= "mediatek,mt8183-ufsphy"},
187 MODULE_DEVICE_TABLE(of
, ufs_mtk_phy_of_match
);
189 static struct platform_driver ufs_mtk_phy_driver
= {
190 .probe
= ufs_mtk_phy_probe
,
192 .of_match_table
= ufs_mtk_phy_of_match
,
193 .name
= "ufs_mtk_phy",
196 module_platform_driver(ufs_mtk_phy_driver
);
198 MODULE_DESCRIPTION("Universal Flash Storage (UFS) MediaTek MPHY");
199 MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>");
200 MODULE_LICENSE("GPL v2");