201 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 0x008C19#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 0xA09C25#define FSM_DIFZ_FRC BIT(18)26 27#define MP_LN_DIG_RX_AC 0xA0AC28#define FRC_RX_SQ_EN BIT(0)29#define RX_SQ_EN BIT(1)30 31#define MP_LN_RX_44 0xB04432#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 238 39struct ufs_mtk_phy {40 struct device *dev;41 void __iomem *mmio;42 struct clk_bulk_data clks[UFSPHY_CLKS_CNT];43};44 45static 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 50static 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 60static 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 91static 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 119static 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 133static 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 144static 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 150static 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 183static const struct of_device_id ufs_mtk_phy_of_match[] = {184 {.compatible = "mediatek,mt8183-ufsphy"},185 {},186};187MODULE_DEVICE_TABLE(of, ufs_mtk_phy_of_match);188 189static 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};196module_platform_driver(ufs_mtk_phy_driver);197 198MODULE_DESCRIPTION("Universal Flash Storage (UFS) MediaTek MPHY");199MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>");200MODULE_LICENSE("GPL v2");201