1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2019 MediaTek Inc. 4 * Author: Stanley Chu <stanley.chu@mediatek.com> 5 */ 6 7 #include <linux/clk.h> 8 #include <linux/delay.h> 9 #include <linux/io.h> 10 #include <linux/module.h> 11 #include <linux/phy/phy.h> 12 #include <linux/platform_device.h> 13 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) 20 21 #define MP_LN_DIG_RX_9C 0xA09C 22 #define FSM_DIFZ_FRC BIT(18) 23 24 #define MP_LN_DIG_RX_AC 0xA0AC 25 #define FRC_RX_SQ_EN BIT(0) 26 #define RX_SQ_EN BIT(1) 27 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) 33 34 struct ufs_mtk_phy { 35 struct device *dev; 36 void __iomem *mmio; 37 struct clk *mp_clk; 38 struct clk *unipro_clk; 39 }; 40 41 static inline u32 mphy_readl(struct ufs_mtk_phy *phy, u32 reg) 42 { 43 return readl(phy->mmio + reg); 44 } 45 46 static inline void mphy_writel(struct ufs_mtk_phy *phy, u32 val, u32 reg) 47 { 48 writel(val, phy->mmio + reg); 49 } 50 51 static void mphy_set_bit(struct ufs_mtk_phy *phy, u32 reg, u32 bit) 52 { 53 u32 val; 54 55 val = mphy_readl(phy, reg); 56 val |= bit; 57 mphy_writel(phy, val, reg); 58 } 59 60 static void mphy_clr_bit(struct ufs_mtk_phy *phy, u32 reg, u32 bit) 61 { 62 u32 val; 63 64 val = mphy_readl(phy, reg); 65 val &= ~bit; 66 mphy_writel(phy, val, reg); 67 } 68 69 static struct ufs_mtk_phy *get_ufs_mtk_phy(struct phy *generic_phy) 70 { 71 return (struct ufs_mtk_phy *)phy_get_drvdata(generic_phy); 72 } 73 74 static int ufs_mtk_phy_clk_init(struct ufs_mtk_phy *phy) 75 { 76 struct device *dev = phy->dev; 77 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); 82 } 83 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); 88 } 89 90 return 0; 91 } 92 93 static void ufs_mtk_phy_set_active(struct ufs_mtk_phy *phy) 94 { 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); 98 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); 102 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); 106 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); 110 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); 114 115 /* delay 1us to wait DIFZ stable */ 116 udelay(1); 117 118 /* release DIFZ */ 119 mphy_clr_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); 120 } 121 122 static void ufs_mtk_phy_set_deep_hibern(struct ufs_mtk_phy *phy) 123 { 124 /* force DIFZ */ 125 mphy_set_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); 126 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); 130 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); 134 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); 138 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); 142 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); 146 } 147 148 static int ufs_mtk_phy_power_on(struct phy *generic_phy) 149 { 150 struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); 151 int ret; 152 153 ret = clk_prepare_enable(phy->unipro_clk); 154 if (ret) { 155 dev_err(phy->dev, "unipro_clk enable failed %d\n", ret); 156 goto out; 157 } 158 159 ret = clk_prepare_enable(phy->mp_clk); 160 if (ret) { 161 dev_err(phy->dev, "mp_clk enable failed %d\n", ret); 162 goto out_unprepare_unipro_clk; 163 } 164 165 ufs_mtk_phy_set_active(phy); 166 167 return 0; 168 169 out_unprepare_unipro_clk: 170 clk_disable_unprepare(phy->unipro_clk); 171 out: 172 return ret; 173 } 174 175 static int ufs_mtk_phy_power_off(struct phy *generic_phy) 176 { 177 struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); 178 179 ufs_mtk_phy_set_deep_hibern(phy); 180 181 clk_disable_unprepare(phy->unipro_clk); 182 clk_disable_unprepare(phy->mp_clk); 183 184 return 0; 185 } 186 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, 191 }; 192 193 static int ufs_mtk_phy_probe(struct platform_device *pdev) 194 { 195 struct device *dev = &pdev->dev; 196 struct phy *generic_phy; 197 struct phy_provider *phy_provider; 198 struct resource *res; 199 struct ufs_mtk_phy *phy; 200 int ret; 201 202 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 203 if (!phy) 204 return -ENOMEM; 205 206 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 207 phy->mmio = devm_ioremap_resource(dev, res); 208 if (IS_ERR(phy->mmio)) 209 return PTR_ERR(phy->mmio); 210 211 phy->dev = dev; 212 213 ret = ufs_mtk_phy_clk_init(phy); 214 if (ret) 215 return ret; 216 217 generic_phy = devm_phy_create(dev, NULL, &ufs_mtk_phy_ops); 218 if (IS_ERR(generic_phy)) 219 return PTR_ERR(generic_phy); 220 221 phy_set_drvdata(generic_phy, phy); 222 223 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 224 225 return PTR_ERR_OR_ZERO(phy_provider); 226 } 227 228 static const struct of_device_id ufs_mtk_phy_of_match[] = { 229 {.compatible = "mediatek,mt8183-ufsphy"}, 230 {}, 231 }; 232 MODULE_DEVICE_TABLE(of, ufs_mtk_phy_of_match); 233 234 static struct platform_driver ufs_mtk_phy_driver = { 235 .probe = ufs_mtk_phy_probe, 236 .driver = { 237 .of_match_table = ufs_mtk_phy_of_match, 238 .name = "ufs_mtk_phy", 239 }, 240 }; 241 module_platform_driver(ufs_mtk_phy_driver); 242 243 MODULE_DESCRIPTION("Universal Flash Storage (UFS) MediaTek MPHY"); 244 MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>"); 245 MODULE_LICENSE("GPL v2"); 246