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 #include "phy-mtk-io.h" 15 16 /* mphy register and offsets */ 17 #define MP_GLB_DIG_8C 0x008C 18 #define FRC_PLL_ISO_EN BIT(8) 19 #define PLL_ISO_EN BIT(9) 20 #define FRC_FRC_PWR_ON BIT(10) 21 #define PLL_PWR_ON BIT(11) 22 23 #define MP_LN_DIG_RX_9C 0xA09C 24 #define FSM_DIFZ_FRC BIT(18) 25 26 #define MP_LN_DIG_RX_AC 0xA0AC 27 #define FRC_RX_SQ_EN BIT(0) 28 #define RX_SQ_EN BIT(1) 29 30 #define MP_LN_RX_44 0xB044 31 #define FRC_CDR_PWR_ON BIT(17) 32 #define CDR_PWR_ON BIT(18) 33 #define FRC_CDR_ISO_EN BIT(19) 34 #define CDR_ISO_EN BIT(20) 35 36 #define UFSPHY_CLKS_CNT 2 37 38 struct ufs_mtk_phy { 39 struct device *dev; 40 void __iomem *mmio; 41 struct clk_bulk_data clks[UFSPHY_CLKS_CNT]; 42 }; 43 44 static struct ufs_mtk_phy *get_ufs_mtk_phy(struct phy *generic_phy) 45 { 46 return (struct ufs_mtk_phy *)phy_get_drvdata(generic_phy); 47 } 48 49 static int ufs_mtk_phy_clk_init(struct ufs_mtk_phy *phy) 50 { 51 struct device *dev = phy->dev; 52 struct clk_bulk_data *clks = phy->clks; 53 54 clks[0].id = "unipro"; 55 clks[1].id = "mp"; 56 return devm_clk_bulk_get(dev, UFSPHY_CLKS_CNT, clks); 57 } 58 59 static void ufs_mtk_phy_set_active(struct ufs_mtk_phy *phy) 60 { 61 void __iomem *mmio = phy->mmio; 62 63 /* release DA_MP_PLL_PWR_ON */ 64 mtk_phy_set_bits(mmio + MP_GLB_DIG_8C, PLL_PWR_ON); 65 mtk_phy_clear_bits(mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON); 66 67 /* release DA_MP_PLL_ISO_EN */ 68 mtk_phy_clear_bits(mmio + MP_GLB_DIG_8C, PLL_ISO_EN); 69 mtk_phy_clear_bits(mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN); 70 71 /* release DA_MP_CDR_PWR_ON */ 72 mtk_phy_set_bits(mmio + MP_LN_RX_44, CDR_PWR_ON); 73 mtk_phy_clear_bits(mmio + MP_LN_RX_44, FRC_CDR_PWR_ON); 74 75 /* release DA_MP_CDR_ISO_EN */ 76 mtk_phy_clear_bits(mmio + MP_LN_RX_44, CDR_ISO_EN); 77 mtk_phy_clear_bits(mmio + MP_LN_RX_44, FRC_CDR_ISO_EN); 78 79 /* release DA_MP_RX0_SQ_EN */ 80 mtk_phy_set_bits(mmio + MP_LN_DIG_RX_AC, RX_SQ_EN); 81 mtk_phy_clear_bits(mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); 82 83 /* delay 1us to wait DIFZ stable */ 84 udelay(1); 85 86 /* release DIFZ */ 87 mtk_phy_clear_bits(mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); 88 } 89 90 static void ufs_mtk_phy_set_deep_hibern(struct ufs_mtk_phy *phy) 91 { 92 void __iomem *mmio = phy->mmio; 93 94 /* force DIFZ */ 95 mtk_phy_set_bits(mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); 96 97 /* force DA_MP_RX0_SQ_EN */ 98 mtk_phy_set_bits(mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); 99 mtk_phy_clear_bits(mmio + MP_LN_DIG_RX_AC, RX_SQ_EN); 100 101 /* force DA_MP_CDR_ISO_EN */ 102 mtk_phy_set_bits(mmio + MP_LN_RX_44, FRC_CDR_ISO_EN); 103 mtk_phy_set_bits(mmio + MP_LN_RX_44, CDR_ISO_EN); 104 105 /* force DA_MP_CDR_PWR_ON */ 106 mtk_phy_set_bits(mmio + MP_LN_RX_44, FRC_CDR_PWR_ON); 107 mtk_phy_clear_bits(mmio + MP_LN_RX_44, CDR_PWR_ON); 108 109 /* force DA_MP_PLL_ISO_EN */ 110 mtk_phy_set_bits(mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN); 111 mtk_phy_set_bits(mmio + MP_GLB_DIG_8C, PLL_ISO_EN); 112 113 /* force DA_MP_PLL_PWR_ON */ 114 mtk_phy_set_bits(mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON); 115 mtk_phy_clear_bits(mmio + MP_GLB_DIG_8C, PLL_PWR_ON); 116 } 117 118 static int ufs_mtk_phy_power_on(struct phy *generic_phy) 119 { 120 struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); 121 int ret; 122 123 ret = clk_bulk_prepare_enable(UFSPHY_CLKS_CNT, phy->clks); 124 if (ret) 125 return ret; 126 127 ufs_mtk_phy_set_active(phy); 128 129 return 0; 130 } 131 132 static int ufs_mtk_phy_power_off(struct phy *generic_phy) 133 { 134 struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); 135 136 ufs_mtk_phy_set_deep_hibern(phy); 137 138 clk_bulk_disable_unprepare(UFSPHY_CLKS_CNT, phy->clks); 139 140 return 0; 141 } 142 143 static const struct phy_ops ufs_mtk_phy_ops = { 144 .power_on = ufs_mtk_phy_power_on, 145 .power_off = ufs_mtk_phy_power_off, 146 .owner = THIS_MODULE, 147 }; 148 149 static int ufs_mtk_phy_probe(struct platform_device *pdev) 150 { 151 struct device *dev = &pdev->dev; 152 struct phy *generic_phy; 153 struct phy_provider *phy_provider; 154 struct ufs_mtk_phy *phy; 155 int ret; 156 157 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 158 if (!phy) 159 return -ENOMEM; 160 161 phy->mmio = devm_platform_ioremap_resource(pdev, 0); 162 if (IS_ERR(phy->mmio)) 163 return PTR_ERR(phy->mmio); 164 165 phy->dev = dev; 166 167 ret = ufs_mtk_phy_clk_init(phy); 168 if (ret) 169 return ret; 170 171 generic_phy = devm_phy_create(dev, NULL, &ufs_mtk_phy_ops); 172 if (IS_ERR(generic_phy)) 173 return PTR_ERR(generic_phy); 174 175 phy_set_drvdata(generic_phy, phy); 176 177 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 178 179 return PTR_ERR_OR_ZERO(phy_provider); 180 } 181 182 static const struct of_device_id ufs_mtk_phy_of_match[] = { 183 {.compatible = "mediatek,mt8183-ufsphy"}, 184 {}, 185 }; 186 MODULE_DEVICE_TABLE(of, ufs_mtk_phy_of_match); 187 188 static struct platform_driver ufs_mtk_phy_driver = { 189 .probe = ufs_mtk_phy_probe, 190 .driver = { 191 .of_match_table = ufs_mtk_phy_of_match, 192 .name = "ufs_mtk_phy", 193 }, 194 }; 195 module_platform_driver(ufs_mtk_phy_driver); 196 197 MODULE_DESCRIPTION("Universal Flash Storage (UFS) MediaTek MPHY"); 198 MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>"); 199 MODULE_LICENSE("GPL v2"); 200