Commit 2411a736ff09d349b0d4630ee5ff8a38d852ce3c
Committed by
Kishon Vijay Abraham I
1 parent
1cc81efe8e
phy: ralink-usb: add driver for Mediatek/Ralink
Add a driver to setup the USB phy on Mediatek/Ralink SoCs. The driver sets up power and host mode, but also needs to configure PHY registers for the MT7628 and MT7688. Signed-off-by: John Crispin <john@phrozen.org> Signed-off-by: Harvey Hunt <harvey.hunt@imgtec.com> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Showing 5 changed files with 263 additions and 0 deletions Side-by-side Diff
drivers/phy/Kconfig
... | ... | @@ -48,6 +48,7 @@ |
48 | 48 | source "drivers/phy/mediatek/Kconfig" |
49 | 49 | source "drivers/phy/motorola/Kconfig" |
50 | 50 | source "drivers/phy/qualcomm/Kconfig" |
51 | +source "drivers/phy/ralink/Kconfig" | |
51 | 52 | source "drivers/phy/renesas/Kconfig" |
52 | 53 | source "drivers/phy/rockchip/Kconfig" |
53 | 54 | source "drivers/phy/samsung/Kconfig" |
drivers/phy/Makefile
drivers/phy/ralink/Kconfig
1 | +# | |
2 | +# PHY drivers for Ralink platforms. | |
3 | +# | |
4 | +config PHY_RALINK_USB | |
5 | + tristate "Ralink USB PHY driver" | |
6 | + depends on RALINK || COMPILE_TEST | |
7 | + select GENERIC_PHY | |
8 | + select MFD_SYSCON | |
9 | + help | |
10 | + This option enables support for the Ralink USB PHY found inside | |
11 | + RT3352, MT7620, MT7628 and MT7688. |
drivers/phy/ralink/Makefile
1 | +obj-$(CONFIG_PHY_RALINK_USB) += phy-ralink-usb.o |
drivers/phy/ralink/phy-ralink-usb.c
1 | +/* | |
2 | + * Copyright (C) 2017 John Crispin <john@phrozen.org> | |
3 | + * | |
4 | + * Based on code from | |
5 | + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or modify | |
8 | + * it under the terms of the GNU General Public License as published by | |
9 | + * the Free Software Foundation; either version 2 of the License, or | |
10 | + * (at your option) any later version. | |
11 | + * | |
12 | + * This program is distributed in the hope that it will be useful, | |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + * GNU General Public License for more details. | |
16 | + */ | |
17 | + | |
18 | +#include <linux/delay.h> | |
19 | +#include <linux/err.h> | |
20 | +#include <linux/io.h> | |
21 | +#include <linux/kernel.h> | |
22 | +#include <linux/mfd/syscon.h> | |
23 | +#include <linux/module.h> | |
24 | +#include <linux/mutex.h> | |
25 | +#include <linux/of_platform.h> | |
26 | +#include <linux/phy/phy.h> | |
27 | +#include <linux/platform_device.h> | |
28 | +#include <linux/regmap.h> | |
29 | +#include <linux/reset.h> | |
30 | + | |
31 | +#define RT_SYSC_REG_SYSCFG1 0x014 | |
32 | +#define RT_SYSC_REG_CLKCFG1 0x030 | |
33 | +#define RT_SYSC_REG_USB_PHY_CFG 0x05c | |
34 | + | |
35 | +#define OFS_U2_PHY_AC0 0x800 | |
36 | +#define OFS_U2_PHY_AC1 0x804 | |
37 | +#define OFS_U2_PHY_AC2 0x808 | |
38 | +#define OFS_U2_PHY_ACR0 0x810 | |
39 | +#define OFS_U2_PHY_ACR1 0x814 | |
40 | +#define OFS_U2_PHY_ACR2 0x818 | |
41 | +#define OFS_U2_PHY_ACR3 0x81C | |
42 | +#define OFS_U2_PHY_ACR4 0x820 | |
43 | +#define OFS_U2_PHY_AMON0 0x824 | |
44 | +#define OFS_U2_PHY_DCR0 0x860 | |
45 | +#define OFS_U2_PHY_DCR1 0x864 | |
46 | +#define OFS_U2_PHY_DTM0 0x868 | |
47 | +#define OFS_U2_PHY_DTM1 0x86C | |
48 | + | |
49 | +#define RT_RSTCTRL_UDEV BIT(25) | |
50 | +#define RT_RSTCTRL_UHST BIT(22) | |
51 | +#define RT_SYSCFG1_USB0_HOST_MODE BIT(10) | |
52 | + | |
53 | +#define MT7620_CLKCFG1_UPHY0_CLK_EN BIT(25) | |
54 | +#define MT7620_CLKCFG1_UPHY1_CLK_EN BIT(22) | |
55 | +#define RT_CLKCFG1_UPHY1_CLK_EN BIT(20) | |
56 | +#define RT_CLKCFG1_UPHY0_CLK_EN BIT(18) | |
57 | + | |
58 | +#define USB_PHY_UTMI_8B60M BIT(1) | |
59 | +#define UDEV_WAKEUP BIT(0) | |
60 | + | |
61 | +struct ralink_usb_phy { | |
62 | + struct reset_control *rstdev; | |
63 | + struct reset_control *rsthost; | |
64 | + u32 clk; | |
65 | + struct phy *phy; | |
66 | + void __iomem *base; | |
67 | + struct regmap *sysctl; | |
68 | +}; | |
69 | + | |
70 | +static void u2_phy_w32(struct ralink_usb_phy *phy, u32 val, u32 reg) | |
71 | +{ | |
72 | + writel(val, phy->base + reg); | |
73 | +} | |
74 | + | |
75 | +static u32 u2_phy_r32(struct ralink_usb_phy *phy, u32 reg) | |
76 | +{ | |
77 | + return readl(phy->base + reg); | |
78 | +} | |
79 | + | |
80 | +static void ralink_usb_phy_init(struct ralink_usb_phy *phy) | |
81 | +{ | |
82 | + u2_phy_r32(phy, OFS_U2_PHY_AC2); | |
83 | + u2_phy_r32(phy, OFS_U2_PHY_ACR0); | |
84 | + u2_phy_r32(phy, OFS_U2_PHY_DCR0); | |
85 | + | |
86 | + u2_phy_w32(phy, 0x00ffff02, OFS_U2_PHY_DCR0); | |
87 | + u2_phy_r32(phy, OFS_U2_PHY_DCR0); | |
88 | + u2_phy_w32(phy, 0x00555502, OFS_U2_PHY_DCR0); | |
89 | + u2_phy_r32(phy, OFS_U2_PHY_DCR0); | |
90 | + u2_phy_w32(phy, 0x00aaaa02, OFS_U2_PHY_DCR0); | |
91 | + u2_phy_r32(phy, OFS_U2_PHY_DCR0); | |
92 | + u2_phy_w32(phy, 0x00000402, OFS_U2_PHY_DCR0); | |
93 | + u2_phy_r32(phy, OFS_U2_PHY_DCR0); | |
94 | + u2_phy_w32(phy, 0x0048086a, OFS_U2_PHY_AC0); | |
95 | + u2_phy_w32(phy, 0x4400001c, OFS_U2_PHY_AC1); | |
96 | + u2_phy_w32(phy, 0xc0200000, OFS_U2_PHY_ACR3); | |
97 | + u2_phy_w32(phy, 0x02000000, OFS_U2_PHY_DTM0); | |
98 | +} | |
99 | + | |
100 | +static int ralink_usb_phy_power_on(struct phy *_phy) | |
101 | +{ | |
102 | + struct ralink_usb_phy *phy = phy_get_drvdata(_phy); | |
103 | + u32 t; | |
104 | + | |
105 | + /* enable the phy */ | |
106 | + regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1, | |
107 | + phy->clk, phy->clk); | |
108 | + | |
109 | + /* setup host mode */ | |
110 | + regmap_update_bits(phy->sysctl, RT_SYSC_REG_SYSCFG1, | |
111 | + RT_SYSCFG1_USB0_HOST_MODE, | |
112 | + RT_SYSCFG1_USB0_HOST_MODE); | |
113 | + | |
114 | + /* deassert the reset lines */ | |
115 | + reset_control_deassert(phy->rsthost); | |
116 | + reset_control_deassert(phy->rstdev); | |
117 | + | |
118 | + /* | |
119 | + * The SDK kernel had a delay of 100ms. however on device | |
120 | + * testing showed that 10ms is enough | |
121 | + */ | |
122 | + mdelay(10); | |
123 | + | |
124 | + if (phy->base) | |
125 | + ralink_usb_phy_init(phy); | |
126 | + | |
127 | + /* print some status info */ | |
128 | + regmap_read(phy->sysctl, RT_SYSC_REG_USB_PHY_CFG, &t); | |
129 | + dev_info(&phy->phy->dev, "remote usb device wakeup %s\n", | |
130 | + (t & UDEV_WAKEUP) ? ("enabled") : ("disabled")); | |
131 | + if (t & USB_PHY_UTMI_8B60M) | |
132 | + dev_info(&phy->phy->dev, "UTMI 8bit 60MHz\n"); | |
133 | + else | |
134 | + dev_info(&phy->phy->dev, "UTMI 16bit 30MHz\n"); | |
135 | + | |
136 | + return 0; | |
137 | +} | |
138 | + | |
139 | +static int ralink_usb_phy_power_off(struct phy *_phy) | |
140 | +{ | |
141 | + struct ralink_usb_phy *phy = phy_get_drvdata(_phy); | |
142 | + | |
143 | + /* disable the phy */ | |
144 | + regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1, | |
145 | + phy->clk, 0); | |
146 | + | |
147 | + /* assert the reset lines */ | |
148 | + reset_control_assert(phy->rstdev); | |
149 | + reset_control_assert(phy->rsthost); | |
150 | + | |
151 | + return 0; | |
152 | +} | |
153 | + | |
154 | +static struct phy_ops ralink_usb_phy_ops = { | |
155 | + .power_on = ralink_usb_phy_power_on, | |
156 | + .power_off = ralink_usb_phy_power_off, | |
157 | + .owner = THIS_MODULE, | |
158 | +}; | |
159 | + | |
160 | +static const struct of_device_id ralink_usb_phy_of_match[] = { | |
161 | + { | |
162 | + .compatible = "ralink,rt3352-usbphy", | |
163 | + .data = (void *) (RT_CLKCFG1_UPHY1_CLK_EN | | |
164 | + RT_CLKCFG1_UPHY0_CLK_EN) | |
165 | + }, | |
166 | + { | |
167 | + .compatible = "mediatek,mt7620-usbphy", | |
168 | + .data = (void *) (MT7620_CLKCFG1_UPHY1_CLK_EN | | |
169 | + MT7620_CLKCFG1_UPHY0_CLK_EN) | |
170 | + }, | |
171 | + { | |
172 | + .compatible = "mediatek,mt7628-usbphy", | |
173 | + .data = (void *) (MT7620_CLKCFG1_UPHY1_CLK_EN | | |
174 | + MT7620_CLKCFG1_UPHY0_CLK_EN) }, | |
175 | + { }, | |
176 | +}; | |
177 | +MODULE_DEVICE_TABLE(of, ralink_usb_phy_of_match); | |
178 | + | |
179 | +static int ralink_usb_phy_probe(struct platform_device *pdev) | |
180 | +{ | |
181 | + struct device *dev = &pdev->dev; | |
182 | + struct resource *res; | |
183 | + struct phy_provider *phy_provider; | |
184 | + const struct of_device_id *match; | |
185 | + struct ralink_usb_phy *phy; | |
186 | + | |
187 | + match = of_match_device(ralink_usb_phy_of_match, &pdev->dev); | |
188 | + if (!match) | |
189 | + return -ENODEV; | |
190 | + | |
191 | + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); | |
192 | + if (!phy) | |
193 | + return -ENOMEM; | |
194 | + | |
195 | + phy->clk = (u32) match->data; | |
196 | + phy->base = NULL; | |
197 | + | |
198 | + phy->sysctl = syscon_regmap_lookup_by_phandle(dev->of_node, "ralink,sysctl"); | |
199 | + if (IS_ERR(phy->sysctl)) { | |
200 | + dev_err(dev, "failed to get sysctl registers\n"); | |
201 | + return PTR_ERR(phy->sysctl); | |
202 | + } | |
203 | + | |
204 | + /* The MT7628 and MT7688 require extra setup of PHY registers. */ | |
205 | + if (of_device_is_compatible(dev->of_node, "mediatek,mt7628-usbphy")) { | |
206 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
207 | + phy->base = devm_ioremap_resource(&pdev->dev, res); | |
208 | + if (IS_ERR(phy->base)) { | |
209 | + dev_err(dev, "failed to remap register memory\n"); | |
210 | + return PTR_ERR(phy->base); | |
211 | + } | |
212 | + } | |
213 | + | |
214 | + phy->rsthost = devm_reset_control_get(&pdev->dev, "host"); | |
215 | + if (IS_ERR(phy->rsthost)) { | |
216 | + dev_err(dev, "host reset is missing\n"); | |
217 | + return PTR_ERR(phy->rsthost); | |
218 | + } | |
219 | + | |
220 | + phy->rstdev = devm_reset_control_get(&pdev->dev, "device"); | |
221 | + if (IS_ERR(phy->rstdev)) { | |
222 | + dev_err(dev, "device reset is missing\n"); | |
223 | + return PTR_ERR(phy->rstdev); | |
224 | + } | |
225 | + | |
226 | + phy->phy = devm_phy_create(dev, NULL, &ralink_usb_phy_ops); | |
227 | + if (IS_ERR(phy->phy)) { | |
228 | + dev_err(dev, "failed to create PHY\n"); | |
229 | + return PTR_ERR(phy->phy); | |
230 | + } | |
231 | + phy_set_drvdata(phy->phy, phy); | |
232 | + | |
233 | + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | |
234 | + | |
235 | + return PTR_ERR_OR_ZERO(phy_provider); | |
236 | +} | |
237 | + | |
238 | +static struct platform_driver ralink_usb_phy_driver = { | |
239 | + .probe = ralink_usb_phy_probe, | |
240 | + .driver = { | |
241 | + .of_match_table = ralink_usb_phy_of_match, | |
242 | + .name = "ralink-usb-phy", | |
243 | + } | |
244 | +}; | |
245 | +module_platform_driver(ralink_usb_phy_driver); | |
246 | + | |
247 | +MODULE_DESCRIPTION("Ralink USB phy driver"); | |
248 | +MODULE_AUTHOR("John Crispin <john@phrozen.org>"); | |
249 | +MODULE_LICENSE("GPL v2"); |