Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.5-rc5 199 lines 5.2 kB view raw
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 38struct ufs_mtk_phy { 39 struct device *dev; 40 void __iomem *mmio; 41 struct clk_bulk_data clks[UFSPHY_CLKS_CNT]; 42}; 43 44static 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 49static 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 59static 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 90static 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 118static 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 132static 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 143static 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 149static 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 182static const struct of_device_id ufs_mtk_phy_of_match[] = { 183 {.compatible = "mediatek,mt8183-ufsphy"}, 184 {}, 185}; 186MODULE_DEVICE_TABLE(of, ufs_mtk_phy_of_match); 187 188static 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}; 195module_platform_driver(ufs_mtk_phy_driver); 196 197MODULE_DESCRIPTION("Universal Flash Storage (UFS) MediaTek MPHY"); 198MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>"); 199MODULE_LICENSE("GPL v2");