xref: /linux/drivers/phy/axiado/phy-axiado-emmc.c (revision 637315cb400eed1dbe721954fea437a61a2d65b2)
1*9e7dfa4bSSriNavmani A // SPDX-License-Identifier: GPL-2.0-or-later
2*9e7dfa4bSSriNavmani A /*
3*9e7dfa4bSSriNavmani A  * Axiado eMMC PHY driver
4*9e7dfa4bSSriNavmani A  *
5*9e7dfa4bSSriNavmani A  * Copyright (C) 2017 Arasan Chip Systems Inc.
6*9e7dfa4bSSriNavmani A  * Copyright (C) 2022-2026 Axiado Corporation (or its affiliates).
7*9e7dfa4bSSriNavmani A  *
8*9e7dfa4bSSriNavmani A  * Based on Arasan Driver (sdhci-pci-arasan.c)
9*9e7dfa4bSSriNavmani A  * sdhci-pci-arasan.c - Driver for Arasan PCI Controller with integrated phy.
10*9e7dfa4bSSriNavmani A  */
11*9e7dfa4bSSriNavmani A #include <linux/bitfield.h>
12*9e7dfa4bSSriNavmani A #include <linux/delay.h>
13*9e7dfa4bSSriNavmani A #include <linux/io.h>
14*9e7dfa4bSSriNavmani A #include <linux/iopoll.h>
15*9e7dfa4bSSriNavmani A #include <linux/module.h>
16*9e7dfa4bSSriNavmani A #include <linux/of.h>
17*9e7dfa4bSSriNavmani A #include <linux/phy/phy.h>
18*9e7dfa4bSSriNavmani A #include <linux/platform_device.h>
19*9e7dfa4bSSriNavmani A 
20*9e7dfa4bSSriNavmani A /* Arasan eMMC 5.1 - PHY configuration registers */
21*9e7dfa4bSSriNavmani A #define CAP_REG_IN_S1_MSB		0x04
22*9e7dfa4bSSriNavmani A #define PHY_CTRL_1			0x38
23*9e7dfa4bSSriNavmani A #define PHY_CTRL_2			0x3c
24*9e7dfa4bSSriNavmani A #define PHY_CTRL_3			0x40
25*9e7dfa4bSSriNavmani A #define STATUS				0x50
26*9e7dfa4bSSriNavmani A 
27*9e7dfa4bSSriNavmani A #define DLL_ENBL	BIT(26)
28*9e7dfa4bSSriNavmani A #define RTRIM_EN	BIT(21)
29*9e7dfa4bSSriNavmani A #define PDB_ENBL	BIT(23)
30*9e7dfa4bSSriNavmani A #define RETB_ENBL	BIT(1)
31*9e7dfa4bSSriNavmani A 
32*9e7dfa4bSSriNavmani A #define REN_STRB	BIT(27)
33*9e7dfa4bSSriNavmani A #define REN_CMD_EN	GENMASK(20, 12)
34*9e7dfa4bSSriNavmani A 
35*9e7dfa4bSSriNavmani A /* Pull-UP Enable on CMD Line */
36*9e7dfa4bSSriNavmani A #define PU_CMD_EN	GENMASK(11, 3)
37*9e7dfa4bSSriNavmani A 
38*9e7dfa4bSSriNavmani A /* Selection value for the optimum delay from 1-32 output tap lines */
39*9e7dfa4bSSriNavmani A #define OTAP_DLY	0x02
40*9e7dfa4bSSriNavmani A /* DLL charge pump current trim default [1000] */
41*9e7dfa4bSSriNavmani A #define DLL_TRM_ICP	0x08
42*9e7dfa4bSSriNavmani A /* Select the frequency range of DLL Operation */
43*9e7dfa4bSSriNavmani A #define FRQ_SEL	0x01
44*9e7dfa4bSSriNavmani A 
45*9e7dfa4bSSriNavmani A #define OTAP_SEL_MASK		GENMASK(10, 7)
46*9e7dfa4bSSriNavmani A #define DLL_TRM_MASK		GENMASK(25, 22)
47*9e7dfa4bSSriNavmani A #define DLL_FRQSEL_MASK		GENMASK(27, 25)
48*9e7dfa4bSSriNavmani A 
49*9e7dfa4bSSriNavmani A #define OTAP_SEL(x)		(FIELD_PREP(OTAP_SEL_MASK, x) | OTAPDLY_EN)
50*9e7dfa4bSSriNavmani A #define DLL_TRM(x)		(FIELD_PREP(DLL_TRM_MASK, x) | DLL_ENBL)
51*9e7dfa4bSSriNavmani A #define DLL_FRQSEL(x)	FIELD_PREP(DLL_FRQSEL_MASK, x)
52*9e7dfa4bSSriNavmani A 
53*9e7dfa4bSSriNavmani A #define OTAPDLY_EN	BIT(11)
54*9e7dfa4bSSriNavmani A 
55*9e7dfa4bSSriNavmani A #define SEL_DLY_RXCLK	BIT(18)
56*9e7dfa4bSSriNavmani A #define SEL_DLY_TXCLK	BIT(19)
57*9e7dfa4bSSriNavmani A 
58*9e7dfa4bSSriNavmani A #define CALDONE_MASK	0x40
59*9e7dfa4bSSriNavmani A #define DLL_RDY_MASK	0x1
60*9e7dfa4bSSriNavmani A #define MAX_CLK_BUF0	BIT(20)
61*9e7dfa4bSSriNavmani A #define MAX_CLK_BUF1	BIT(21)
62*9e7dfa4bSSriNavmani A #define MAX_CLK_BUF2	BIT(22)
63*9e7dfa4bSSriNavmani A 
64*9e7dfa4bSSriNavmani A #define CLK_MULTIPLIER	0xc008e
65*9e7dfa4bSSriNavmani A #define POLL_TIMEOUT_MS	3000
66*9e7dfa4bSSriNavmani A #define POLL_DELAY_US	100
67*9e7dfa4bSSriNavmani A 
68*9e7dfa4bSSriNavmani A struct axiado_emmc_phy {
69*9e7dfa4bSSriNavmani A 	void __iomem *reg_base;
70*9e7dfa4bSSriNavmani A 	struct device *dev;
71*9e7dfa4bSSriNavmani A };
72*9e7dfa4bSSriNavmani A 
73*9e7dfa4bSSriNavmani A static int axiado_emmc_phy_init(struct phy *phy)
74*9e7dfa4bSSriNavmani A {
75*9e7dfa4bSSriNavmani A 	struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy);
76*9e7dfa4bSSriNavmani A 	struct device *dev = ax_phy->dev;
77*9e7dfa4bSSriNavmani A 	u32 val;
78*9e7dfa4bSSriNavmani A 	int ret;
79*9e7dfa4bSSriNavmani A 
80*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_1);
81*9e7dfa4bSSriNavmani A 	writel(val | RETB_ENBL | RTRIM_EN, ax_phy->reg_base + PHY_CTRL_1);
82*9e7dfa4bSSriNavmani A 
83*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_3);
84*9e7dfa4bSSriNavmani A 	writel(val | PDB_ENBL, ax_phy->reg_base + PHY_CTRL_3);
85*9e7dfa4bSSriNavmani A 
86*9e7dfa4bSSriNavmani A 	ret = readl_poll_timeout(ax_phy->reg_base + STATUS, val,
87*9e7dfa4bSSriNavmani A 				 val & CALDONE_MASK, POLL_DELAY_US,
88*9e7dfa4bSSriNavmani A 				 POLL_TIMEOUT_MS * 1000);
89*9e7dfa4bSSriNavmani A 	if (ret) {
90*9e7dfa4bSSriNavmani A 		dev_err(dev, "PHY calibration timeout\n");
91*9e7dfa4bSSriNavmani A 		return ret;
92*9e7dfa4bSSriNavmani A 	}
93*9e7dfa4bSSriNavmani A 
94*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_1);
95*9e7dfa4bSSriNavmani A 	writel(val | REN_CMD_EN | PU_CMD_EN, ax_phy->reg_base + PHY_CTRL_1);
96*9e7dfa4bSSriNavmani A 
97*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_2);
98*9e7dfa4bSSriNavmani A 	writel(val | REN_STRB, ax_phy->reg_base + PHY_CTRL_2);
99*9e7dfa4bSSriNavmani A 
100*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_3);
101*9e7dfa4bSSriNavmani A 	writel(val | MAX_CLK_BUF0 | MAX_CLK_BUF1 | MAX_CLK_BUF2,
102*9e7dfa4bSSriNavmani A 	       ax_phy->reg_base + PHY_CTRL_3);
103*9e7dfa4bSSriNavmani A 
104*9e7dfa4bSSriNavmani A 	writel(CLK_MULTIPLIER, ax_phy->reg_base + CAP_REG_IN_S1_MSB);
105*9e7dfa4bSSriNavmani A 
106*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_3);
107*9e7dfa4bSSriNavmani A 	writel(val | SEL_DLY_RXCLK | SEL_DLY_TXCLK,
108*9e7dfa4bSSriNavmani A 	       ax_phy->reg_base + PHY_CTRL_3);
109*9e7dfa4bSSriNavmani A 
110*9e7dfa4bSSriNavmani A 	return 0;
111*9e7dfa4bSSriNavmani A }
112*9e7dfa4bSSriNavmani A 
113*9e7dfa4bSSriNavmani A static int axiado_emmc_phy_power_on(struct phy *phy)
114*9e7dfa4bSSriNavmani A {
115*9e7dfa4bSSriNavmani A 	struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy);
116*9e7dfa4bSSriNavmani A 	struct device *dev = ax_phy->dev;
117*9e7dfa4bSSriNavmani A 	u32 val;
118*9e7dfa4bSSriNavmani A 	int ret;
119*9e7dfa4bSSriNavmani A 
120*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_1);
121*9e7dfa4bSSriNavmani A 	writel(val | RETB_ENBL, ax_phy->reg_base + PHY_CTRL_1);
122*9e7dfa4bSSriNavmani A 
123*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_3);
124*9e7dfa4bSSriNavmani A 	writel(val | PDB_ENBL, ax_phy->reg_base + PHY_CTRL_3);
125*9e7dfa4bSSriNavmani A 
126*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_2);
127*9e7dfa4bSSriNavmani A 	writel(val | OTAP_SEL(OTAP_DLY), ax_phy->reg_base + PHY_CTRL_2);
128*9e7dfa4bSSriNavmani A 
129*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_1);
130*9e7dfa4bSSriNavmani A 	writel(val | DLL_TRM(DLL_TRM_ICP), ax_phy->reg_base + PHY_CTRL_1);
131*9e7dfa4bSSriNavmani A 
132*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_3);
133*9e7dfa4bSSriNavmani A 	writel(val | DLL_FRQSEL(FRQ_SEL), ax_phy->reg_base + PHY_CTRL_3);
134*9e7dfa4bSSriNavmani A 
135*9e7dfa4bSSriNavmani A 	ret = read_poll_timeout(readl, val, val & DLL_RDY_MASK, POLL_DELAY_US,
136*9e7dfa4bSSriNavmani A 				POLL_TIMEOUT_MS * 1000, false,
137*9e7dfa4bSSriNavmani A 				ax_phy->reg_base + STATUS);
138*9e7dfa4bSSriNavmani A 	if (ret) {
139*9e7dfa4bSSriNavmani A 		dev_err(dev, "DLL ready timeout\n");
140*9e7dfa4bSSriNavmani A 		return ret;
141*9e7dfa4bSSriNavmani A 	}
142*9e7dfa4bSSriNavmani A 
143*9e7dfa4bSSriNavmani A 	return 0;
144*9e7dfa4bSSriNavmani A }
145*9e7dfa4bSSriNavmani A 
146*9e7dfa4bSSriNavmani A static int axiado_emmc_phy_power_off(struct phy *phy)
147*9e7dfa4bSSriNavmani A {
148*9e7dfa4bSSriNavmani A 	struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy);
149*9e7dfa4bSSriNavmani A 	u32 val;
150*9e7dfa4bSSriNavmani A 
151*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_1);
152*9e7dfa4bSSriNavmani A 	val &= ~(DLL_TRM_MASK | DLL_ENBL);
153*9e7dfa4bSSriNavmani A 	writel(val, ax_phy->reg_base + PHY_CTRL_1);
154*9e7dfa4bSSriNavmani A 
155*9e7dfa4bSSriNavmani A 	val = readl(ax_phy->reg_base + PHY_CTRL_3);
156*9e7dfa4bSSriNavmani A 	val &= ~(DLL_FRQSEL_MASK | PDB_ENBL);
157*9e7dfa4bSSriNavmani A 	writel(val, ax_phy->reg_base + PHY_CTRL_3);
158*9e7dfa4bSSriNavmani A 
159*9e7dfa4bSSriNavmani A 	return 0;
160*9e7dfa4bSSriNavmani A }
161*9e7dfa4bSSriNavmani A 
162*9e7dfa4bSSriNavmani A static const struct phy_ops axiado_emmc_phy_ops = {
163*9e7dfa4bSSriNavmani A 	.init = axiado_emmc_phy_init,
164*9e7dfa4bSSriNavmani A 	.power_on = axiado_emmc_phy_power_on,
165*9e7dfa4bSSriNavmani A 	.power_off = axiado_emmc_phy_power_off,
166*9e7dfa4bSSriNavmani A 	.owner = THIS_MODULE,
167*9e7dfa4bSSriNavmani A };
168*9e7dfa4bSSriNavmani A 
169*9e7dfa4bSSriNavmani A static const struct of_device_id axiado_emmc_phy_of_match[] = {
170*9e7dfa4bSSriNavmani A 	{ .compatible = "axiado,ax3000-emmc-phy" },
171*9e7dfa4bSSriNavmani A 	{ /* sentinel */ },
172*9e7dfa4bSSriNavmani A };
173*9e7dfa4bSSriNavmani A MODULE_DEVICE_TABLE(of, axiado_emmc_phy_of_match);
174*9e7dfa4bSSriNavmani A 
175*9e7dfa4bSSriNavmani A static int axiado_emmc_phy_probe(struct platform_device *pdev)
176*9e7dfa4bSSriNavmani A {
177*9e7dfa4bSSriNavmani A 	struct axiado_emmc_phy *ax_phy;
178*9e7dfa4bSSriNavmani A 	struct phy_provider *phy_provider;
179*9e7dfa4bSSriNavmani A 	struct device *dev = &pdev->dev;
180*9e7dfa4bSSriNavmani A 	struct phy *generic_phy;
181*9e7dfa4bSSriNavmani A 
182*9e7dfa4bSSriNavmani A 	if (!dev->of_node)
183*9e7dfa4bSSriNavmani A 		return -ENODEV;
184*9e7dfa4bSSriNavmani A 
185*9e7dfa4bSSriNavmani A 	ax_phy = devm_kzalloc(dev, sizeof(*ax_phy), GFP_KERNEL);
186*9e7dfa4bSSriNavmani A 	if (!ax_phy)
187*9e7dfa4bSSriNavmani A 		return -ENOMEM;
188*9e7dfa4bSSriNavmani A 
189*9e7dfa4bSSriNavmani A 	ax_phy->reg_base = devm_platform_ioremap_resource(pdev, 0);
190*9e7dfa4bSSriNavmani A 	if (IS_ERR(ax_phy->reg_base))
191*9e7dfa4bSSriNavmani A 		return PTR_ERR(ax_phy->reg_base);
192*9e7dfa4bSSriNavmani A 
193*9e7dfa4bSSriNavmani A 	ax_phy->dev = dev;
194*9e7dfa4bSSriNavmani A 
195*9e7dfa4bSSriNavmani A 	generic_phy = devm_phy_create(dev, dev->of_node, &axiado_emmc_phy_ops);
196*9e7dfa4bSSriNavmani A 	if (IS_ERR(generic_phy))
197*9e7dfa4bSSriNavmani A 		return dev_err_probe(dev, PTR_ERR(generic_phy),
198*9e7dfa4bSSriNavmani A 				     "failed to create PHY\n");
199*9e7dfa4bSSriNavmani A 
200*9e7dfa4bSSriNavmani A 	phy_set_drvdata(generic_phy, ax_phy);
201*9e7dfa4bSSriNavmani A 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
202*9e7dfa4bSSriNavmani A 
203*9e7dfa4bSSriNavmani A 	return PTR_ERR_OR_ZERO(phy_provider);
204*9e7dfa4bSSriNavmani A }
205*9e7dfa4bSSriNavmani A 
206*9e7dfa4bSSriNavmani A static struct platform_driver axiado_emmc_phy_driver = {
207*9e7dfa4bSSriNavmani A 	.probe = axiado_emmc_phy_probe,
208*9e7dfa4bSSriNavmani A 	.driver = {
209*9e7dfa4bSSriNavmani A 		.name = "axiado-emmc-phy",
210*9e7dfa4bSSriNavmani A 		.of_match_table = axiado_emmc_phy_of_match,
211*9e7dfa4bSSriNavmani A 	},
212*9e7dfa4bSSriNavmani A };
213*9e7dfa4bSSriNavmani A module_platform_driver(axiado_emmc_phy_driver);
214*9e7dfa4bSSriNavmani A 
215*9e7dfa4bSSriNavmani A MODULE_DESCRIPTION("AX3000 eMMC PHY Driver");
216*9e7dfa4bSSriNavmani A MODULE_AUTHOR("Axiado Corporation");
217*9e7dfa4bSSriNavmani A MODULE_LICENSE("GPL");
218