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/module.h>
11 #include <linux/phy/phy.h>
12 #include <linux/platform_device.h>
14 /* mphy register and offsets */
15 #define MP_GLB_DIG_8C 0x008C
16 #define FRC_PLL_ISO_EN BIT(8)
17 #define PLL_ISO_EN BIT(9)
18 #define FRC_FRC_PWR_ON BIT(10)
19 #define PLL_PWR_ON BIT(11)
21 #define MP_LN_DIG_RX_9C 0xA09C
22 #define FSM_DIFZ_FRC BIT(18)
24 #define MP_LN_DIG_RX_AC 0xA0AC
25 #define FRC_RX_SQ_EN BIT(0)
26 #define RX_SQ_EN BIT(1)
28 #define MP_LN_RX_44 0xB044
29 #define FRC_CDR_PWR_ON BIT(17)
30 #define CDR_PWR_ON BIT(18)
31 #define FRC_CDR_ISO_EN BIT(19)
32 #define CDR_ISO_EN BIT(20)
38 struct clk
*unipro_clk
;
41 static inline u32
mphy_readl(struct ufs_mtk_phy
*phy
, u32 reg
)
43 return readl(phy
->mmio
+ reg
);
46 static inline void mphy_writel(struct ufs_mtk_phy
*phy
, u32 val
, u32 reg
)
48 writel(val
, phy
->mmio
+ reg
);
51 static void mphy_set_bit(struct ufs_mtk_phy
*phy
, u32 reg
, u32 bit
)
55 val
= mphy_readl(phy
, reg
);
57 mphy_writel(phy
, val
, reg
);
60 static void mphy_clr_bit(struct ufs_mtk_phy
*phy
, u32 reg
, u32 bit
)
64 val
= mphy_readl(phy
, reg
);
66 mphy_writel(phy
, val
, reg
);
69 static struct ufs_mtk_phy
*get_ufs_mtk_phy(struct phy
*generic_phy
)
71 return (struct ufs_mtk_phy
*)phy_get_drvdata(generic_phy
);
74 static int ufs_mtk_phy_clk_init(struct ufs_mtk_phy
*phy
)
76 struct device
*dev
= phy
->dev
;
78 phy
->unipro_clk
= devm_clk_get(dev
, "unipro");
79 if (IS_ERR(phy
->unipro_clk
)) {
80 dev_err(dev
, "failed to get clock: unipro");
81 return PTR_ERR(phy
->unipro_clk
);
84 phy
->mp_clk
= devm_clk_get(dev
, "mp");
85 if (IS_ERR(phy
->mp_clk
)) {
86 dev_err(dev
, "failed to get clock: mp");
87 return PTR_ERR(phy
->mp_clk
);
93 static void ufs_mtk_phy_set_active(struct ufs_mtk_phy
*phy
)
95 /* release DA_MP_PLL_PWR_ON */
96 mphy_set_bit(phy
, MP_GLB_DIG_8C
, PLL_PWR_ON
);
97 mphy_clr_bit(phy
, MP_GLB_DIG_8C
, FRC_FRC_PWR_ON
);
99 /* release DA_MP_PLL_ISO_EN */
100 mphy_clr_bit(phy
, MP_GLB_DIG_8C
, PLL_ISO_EN
);
101 mphy_clr_bit(phy
, MP_GLB_DIG_8C
, FRC_PLL_ISO_EN
);
103 /* release DA_MP_CDR_PWR_ON */
104 mphy_set_bit(phy
, MP_LN_RX_44
, CDR_PWR_ON
);
105 mphy_clr_bit(phy
, MP_LN_RX_44
, FRC_CDR_PWR_ON
);
107 /* release DA_MP_CDR_ISO_EN */
108 mphy_clr_bit(phy
, MP_LN_RX_44
, CDR_ISO_EN
);
109 mphy_clr_bit(phy
, MP_LN_RX_44
, FRC_CDR_ISO_EN
);
111 /* release DA_MP_RX0_SQ_EN */
112 mphy_set_bit(phy
, MP_LN_DIG_RX_AC
, RX_SQ_EN
);
113 mphy_clr_bit(phy
, MP_LN_DIG_RX_AC
, FRC_RX_SQ_EN
);
115 /* delay 1us to wait DIFZ stable */
119 mphy_clr_bit(phy
, MP_LN_DIG_RX_9C
, FSM_DIFZ_FRC
);
122 static void ufs_mtk_phy_set_deep_hibern(struct ufs_mtk_phy
*phy
)
125 mphy_set_bit(phy
, MP_LN_DIG_RX_9C
, FSM_DIFZ_FRC
);
127 /* force DA_MP_RX0_SQ_EN */
128 mphy_set_bit(phy
, MP_LN_DIG_RX_AC
, FRC_RX_SQ_EN
);
129 mphy_clr_bit(phy
, MP_LN_DIG_RX_AC
, RX_SQ_EN
);
131 /* force DA_MP_CDR_ISO_EN */
132 mphy_set_bit(phy
, MP_LN_RX_44
, FRC_CDR_ISO_EN
);
133 mphy_set_bit(phy
, MP_LN_RX_44
, CDR_ISO_EN
);
135 /* force DA_MP_CDR_PWR_ON */
136 mphy_set_bit(phy
, MP_LN_RX_44
, FRC_CDR_PWR_ON
);
137 mphy_clr_bit(phy
, MP_LN_RX_44
, CDR_PWR_ON
);
139 /* force DA_MP_PLL_ISO_EN */
140 mphy_set_bit(phy
, MP_GLB_DIG_8C
, FRC_PLL_ISO_EN
);
141 mphy_set_bit(phy
, MP_GLB_DIG_8C
, PLL_ISO_EN
);
143 /* force DA_MP_PLL_PWR_ON */
144 mphy_set_bit(phy
, MP_GLB_DIG_8C
, FRC_FRC_PWR_ON
);
145 mphy_clr_bit(phy
, MP_GLB_DIG_8C
, PLL_PWR_ON
);
148 static int ufs_mtk_phy_power_on(struct phy
*generic_phy
)
150 struct ufs_mtk_phy
*phy
= get_ufs_mtk_phy(generic_phy
);
153 ret
= clk_prepare_enable(phy
->unipro_clk
);
155 dev_err(phy
->dev
, "unipro_clk enable failed %d\n", ret
);
159 ret
= clk_prepare_enable(phy
->mp_clk
);
161 dev_err(phy
->dev
, "mp_clk enable failed %d\n", ret
);
162 goto out_unprepare_unipro_clk
;
165 ufs_mtk_phy_set_active(phy
);
169 out_unprepare_unipro_clk
:
170 clk_disable_unprepare(phy
->unipro_clk
);
175 static int ufs_mtk_phy_power_off(struct phy
*generic_phy
)
177 struct ufs_mtk_phy
*phy
= get_ufs_mtk_phy(generic_phy
);
179 ufs_mtk_phy_set_deep_hibern(phy
);
181 clk_disable_unprepare(phy
->unipro_clk
);
182 clk_disable_unprepare(phy
->mp_clk
);
187 static const struct phy_ops ufs_mtk_phy_ops
= {
188 .power_on
= ufs_mtk_phy_power_on
,
189 .power_off
= ufs_mtk_phy_power_off
,
190 .owner
= THIS_MODULE
,
193 static int ufs_mtk_phy_probe(struct platform_device
*pdev
)
195 struct device
*dev
= &pdev
->dev
;
196 struct phy
*generic_phy
;
197 struct phy_provider
*phy_provider
;
198 struct ufs_mtk_phy
*phy
;
201 phy
= devm_kzalloc(dev
, sizeof(*phy
), GFP_KERNEL
);
205 phy
->mmio
= devm_platform_ioremap_resource(pdev
, 0);
206 if (IS_ERR(phy
->mmio
))
207 return PTR_ERR(phy
->mmio
);
211 ret
= ufs_mtk_phy_clk_init(phy
);
215 generic_phy
= devm_phy_create(dev
, NULL
, &ufs_mtk_phy_ops
);
216 if (IS_ERR(generic_phy
))
217 return PTR_ERR(generic_phy
);
219 phy_set_drvdata(generic_phy
, phy
);
221 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
223 return PTR_ERR_OR_ZERO(phy_provider
);
226 static const struct of_device_id ufs_mtk_phy_of_match
[] = {
227 {.compatible
= "mediatek,mt8183-ufsphy"},
230 MODULE_DEVICE_TABLE(of
, ufs_mtk_phy_of_match
);
232 static struct platform_driver ufs_mtk_phy_driver
= {
233 .probe
= ufs_mtk_phy_probe
,
235 .of_match_table
= ufs_mtk_phy_of_match
,
236 .name
= "ufs_mtk_phy",
239 module_platform_driver(ufs_mtk_phy_driver
);
241 MODULE_DESCRIPTION("Universal Flash Storage (UFS) MediaTek MPHY");
242 MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>");
243 MODULE_LICENSE("GPL v2");