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/mod_devicetable.h> 11 #include <linux/module.h> 12 #include <linux/phy/phy.h> 13 #include <linux/platform_device.h> 14 15 #include "phy-mtk-io.h" 16 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) 23 24 #define MP_LN_DIG_RX_9C 0xA09C 25 #define FSM_DIFZ_FRC BIT(18) 26 27 #define MP_LN_DIG_RX_AC 0xA0AC 28 #define FRC_RX_SQ_EN BIT(0) 29 #define RX_SQ_EN BIT(1) 30 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) 36 37 #define UFSPHY_CLKS_CNT 2 38 39 struct ufs_mtk_phy { 40 struct device *dev; 41 void __iomem *mmio; 42 struct clk_bulk_data clks[UFSPHY_CLKS_CNT]; 43 }; 44 45 static struct ufs_mtk_phy *get_ufs_mtk_phy(struct phy *generic_phy) 46 { 47 return (struct ufs_mtk_phy *)phy_get_drvdata(generic_phy); 48 } 49 50 static int ufs_mtk_phy_clk_init(struct ufs_mtk_phy *phy) 51 { 52 struct device *dev = phy->dev; 53 struct clk_bulk_data *clks = phy->clks; 54 55 clks[0].id = "unipro"; 56 clks[1].id = "mp"; 57 return devm_clk_bulk_get(dev, UFSPHY_CLKS_CNT, clks); 58 } 59 60 static void ufs_mtk_phy_set_active(struct ufs_mtk_phy *phy) 61 { 62 void __iomem *mmio = phy->mmio; 63 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); 67 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); 71 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); 75 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); 79 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); 83 84 /* delay 1us to wait DIFZ stable */ 85 udelay(1); 86 87 /* release DIFZ */ 88 mtk_phy_clear_bits(mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); 89 } 90 91 static void ufs_mtk_phy_set_deep_hibern(struct ufs_mtk_phy *phy) 92 { 93 void __iomem *mmio = phy->mmio; 94 95 /* force DIFZ */ 96 mtk_phy_set_bits(mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); 97 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); 101 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); 105 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); 109 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); 113 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); 117 } 118 119 static int ufs_mtk_phy_power_on(struct phy *generic_phy) 120 { 121 struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); 122 int ret; 123 124 ret = clk_bulk_prepare_enable(UFSPHY_CLKS_CNT, phy->clks); 125 if (ret) 126 return ret; 127 128 ufs_mtk_phy_set_active(phy); 129 130 return 0; 131 } 132 133 static int ufs_mtk_phy_power_off(struct phy *generic_phy) 134 { 135 struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); 136 137 ufs_mtk_phy_set_deep_hibern(phy); 138 139 clk_bulk_disable_unprepare(UFSPHY_CLKS_CNT, phy->clks); 140 141 return 0; 142 } 143 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, 148 }; 149 150 static int ufs_mtk_phy_probe(struct platform_device *pdev) 151 { 152 struct device *dev = &pdev->dev; 153 struct phy *generic_phy; 154 struct phy_provider *phy_provider; 155 struct ufs_mtk_phy *phy; 156 int ret; 157 158 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 159 if (!phy) 160 return -ENOMEM; 161 162 phy->mmio = devm_platform_ioremap_resource(pdev, 0); 163 if (IS_ERR(phy->mmio)) 164 return PTR_ERR(phy->mmio); 165 166 phy->dev = dev; 167 168 ret = ufs_mtk_phy_clk_init(phy); 169 if (ret) 170 return ret; 171 172 generic_phy = devm_phy_create(dev, NULL, &ufs_mtk_phy_ops); 173 if (IS_ERR(generic_phy)) 174 return PTR_ERR(generic_phy); 175 176 phy_set_drvdata(generic_phy, phy); 177 178 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 179 180 return PTR_ERR_OR_ZERO(phy_provider); 181 } 182 183 static const struct of_device_id ufs_mtk_phy_of_match[] = { 184 {.compatible = "mediatek,mt8183-ufsphy"}, 185 {}, 186 }; 187 MODULE_DEVICE_TABLE(of, ufs_mtk_phy_of_match); 188 189 static struct platform_driver ufs_mtk_phy_driver = { 190 .probe = ufs_mtk_phy_probe, 191 .driver = { 192 .of_match_table = ufs_mtk_phy_of_match, 193 .name = "ufs_mtk_phy", 194 }, 195 }; 196 module_platform_driver(ufs_mtk_phy_driver); 197 198 MODULE_DESCRIPTION("Universal Flash Storage (UFS) MediaTek MPHY"); 199 MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>"); 200 MODULE_LICENSE("GPL v2"); 201