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