blob: 664259d746580d3a74718c6df23b4d9a7b1e89fd [file] [log] [blame]
Greg Kroah-Hartman5fd54ac2017-11-03 11:28:30 +01001// SPDX-License-Identifier: GPL-2.0
Benoit Goby91525d02011-03-09 16:28:55 -08002/*
Benoit Goby91525d02011-03-09 16:28:55 -08003 * Copyright (C) 2010 Google, Inc.
Venu Byravarasu2d22b422013-05-16 19:43:02 +05304 * Copyright (C) 2013 NVIDIA Corporation
Benoit Goby91525d02011-03-09 16:28:55 -08005 *
6 * Author:
7 * Erik Gilling <konkers@google.com>
8 * Benoit Goby <benoit@android.com>
Venu Byravarasu2d22b422013-05-16 19:43:02 +05309 * Venu Byravarasu <vbyravarasu@nvidia.com>
Benoit Goby91525d02011-03-09 16:28:55 -080010 */
11
12#include <linux/resource.h>
13#include <linux/delay.h>
14#include <linux/slab.h>
15#include <linux/err.h>
Arnd Bergmann4265cbf2012-03-02 15:58:42 -050016#include <linux/export.h>
Stephen Warren587376a2013-06-13 11:24:08 -060017#include <linux/module.h>
Benoit Goby91525d02011-03-09 16:28:55 -080018#include <linux/platform_device.h>
Dmitry Osipenko43bcf642017-12-17 20:02:39 +030019#include <linux/iopoll.h>
Benoit Goby91525d02011-03-09 16:28:55 -080020#include <linux/gpio.h>
Venu Byravarasu3a55c6a2013-01-16 03:30:20 +000021#include <linux/of.h>
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +030022#include <linux/of_device.h>
Stephen Warrenaa607eb2012-04-12 15:46:49 -060023#include <linux/of_gpio.h>
Benoit Goby91525d02011-03-09 16:28:55 -080024#include <linux/usb/otg.h>
25#include <linux/usb/ulpi.h>
Tuomas Tynkkynen9fdb07f2013-07-25 21:38:08 +030026#include <linux/usb/of.h>
Stephen Warren91a687d2013-06-13 11:24:11 -060027#include <linux/usb/ehci_def.h>
Venu Byravarasu1ba82162012-09-05 18:50:23 +053028#include <linux/usb/tegra_usb_phy.h>
Mikko Perttunenf5b8c8b2013-07-17 10:37:49 +030029#include <linux/regulator/consumer.h>
Benoit Goby91525d02011-03-09 16:28:55 -080030
31#define ULPI_VIEWPORT 0x170
32
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +030033/* PORTSC PTS/PHCD bits, Tegra20 only */
Stephen Warren91a687d2013-06-13 11:24:11 -060034#define TEGRA_USB_PORTSC1 0x184
35#define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30)
36#define TEGRA_USB_PORTSC1_PHCD (1 << 23)
37
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +030038/* HOSTPC1 PTS/PHCD bits, Tegra30 and above */
39#define TEGRA_USB_HOSTPC1_DEVLC 0x1b4
40#define TEGRA_USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
41#define TEGRA_USB_HOSTPC1_DEVLC_PHCD (1 << 22)
42
Stephen Warren91a687d2013-06-13 11:24:11 -060043/* Bits of PORTSC1, which will get cleared by writing 1 into them */
44#define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
45
Benoit Goby91525d02011-03-09 16:28:55 -080046#define USB_SUSP_CTRL 0x400
47#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
48#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
49#define USB_SUSP_CLR (1 << 5)
50#define USB_PHY_CLK_VALID (1 << 7)
51#define UTMIP_RESET (1 << 11)
52#define UHSIC_RESET (1 << 11)
53#define UTMIP_PHY_ENABLE (1 << 12)
54#define ULPI_PHY_ENABLE (1 << 13)
55#define USB_SUSP_SET (1 << 14)
56#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
57
58#define USB1_LEGACY_CTRL 0x410
59#define USB1_NO_LEGACY_MODE (1 << 0)
60#define USB1_VBUS_SENSE_CTL_MASK (3 << 1)
61#define USB1_VBUS_SENSE_CTL_VBUS_WAKEUP (0 << 1)
62#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
63 (1 << 1)
64#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD (2 << 1)
65#define USB1_VBUS_SENSE_CTL_A_SESS_VLD (3 << 1)
66
67#define ULPI_TIMING_CTRL_0 0x424
68#define ULPI_OUTPUT_PINMUX_BYP (1 << 10)
69#define ULPI_CLKOUT_PINMUX_BYP (1 << 11)
70
71#define ULPI_TIMING_CTRL_1 0x428
72#define ULPI_DATA_TRIMMER_LOAD (1 << 0)
73#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1)
74#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16)
75#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17)
76#define ULPI_DIR_TRIMMER_LOAD (1 << 24)
77#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25)
78
79#define UTMIP_PLL_CFG1 0x804
80#define UTMIP_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
81#define UTMIP_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
82
83#define UTMIP_XCVR_CFG0 0x808
84#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
Tuomas Tynkkynenf5833a02013-08-12 16:06:50 +030085#define UTMIP_XCVR_SETUP_MSB(x) ((((x) & 0x70) >> 4) << 22)
Benoit Goby91525d02011-03-09 16:28:55 -080086#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
87#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
88#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
89#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
90#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
Tuomas Tynkkynenf5833a02013-08-12 16:06:50 +030091#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
Tuomas Tynkkynene497a242013-08-12 16:06:53 +030092#define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4)
93#define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25)
Benoit Goby91525d02011-03-09 16:28:55 -080094
95#define UTMIP_BIAS_CFG0 0x80c
96#define UTMIP_OTGPD (1 << 11)
97#define UTMIP_BIASPD (1 << 10)
Tuomas Tynkkynene497a242013-08-12 16:06:53 +030098#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0)
99#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2)
100#define UTMIP_HSDISCON_LEVEL_MSB(x) ((((x) & 0x4) >> 2) << 24)
Benoit Goby91525d02011-03-09 16:28:55 -0800101
102#define UTMIP_HSRX_CFG0 0x810
103#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
104#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
105
106#define UTMIP_HSRX_CFG1 0x814
107#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
108
109#define UTMIP_TX_CFG0 0x820
110#define UTMIP_FS_PREABMLE_J (1 << 19)
111#define UTMIP_HS_DISCON_DISABLE (1 << 8)
112
113#define UTMIP_MISC_CFG0 0x824
114#define UTMIP_DPDM_OBSERVE (1 << 26)
115#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27)
116#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf)
117#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe)
118#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
119#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
120#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22)
121
122#define UTMIP_MISC_CFG1 0x828
123#define UTMIP_PLL_ACTIVE_DLY_COUNT(x) (((x) & 0x1f) << 18)
124#define UTMIP_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 6)
125
126#define UTMIP_DEBOUNCE_CFG0 0x82c
127#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
128
129#define UTMIP_BAT_CHRG_CFG0 0x830
130#define UTMIP_PD_CHRG (1 << 0)
131
132#define UTMIP_SPARE_CFG0 0x834
133#define FUSE_SETUP_SEL (1 << 3)
134
135#define UTMIP_XCVR_CFG1 0x838
136#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
137#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
138#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4)
139#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
140
141#define UTMIP_BIAS_CFG1 0x83c
142#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
143
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +0300144/* For Tegra30 and above only, the address is different in Tegra20 */
145#define USB_USBMODE 0x1f8
146#define USB_USBMODE_MASK (3 << 0)
147#define USB_USBMODE_HOST (3 << 0)
148#define USB_USBMODE_DEVICE (2 << 0)
149
Benoit Goby91525d02011-03-09 16:28:55 -0800150static DEFINE_SPINLOCK(utmip_pad_lock);
151static int utmip_pad_count;
152
153struct tegra_xtal_freq {
154 int freq;
155 u8 enable_delay;
156 u8 stable_count;
157 u8 active_delay;
158 u8 xtal_freq_count;
159 u16 debounce;
160};
161
162static const struct tegra_xtal_freq tegra_freq_table[] = {
163 {
164 .freq = 12000000,
165 .enable_delay = 0x02,
166 .stable_count = 0x2F,
167 .active_delay = 0x04,
168 .xtal_freq_count = 0x76,
169 .debounce = 0x7530,
170 },
171 {
172 .freq = 13000000,
173 .enable_delay = 0x02,
174 .stable_count = 0x33,
175 .active_delay = 0x05,
176 .xtal_freq_count = 0x7F,
177 .debounce = 0x7EF4,
178 },
179 {
180 .freq = 19200000,
181 .enable_delay = 0x03,
182 .stable_count = 0x4B,
183 .active_delay = 0x06,
184 .xtal_freq_count = 0xBB,
185 .debounce = 0xBB80,
186 },
187 {
188 .freq = 26000000,
189 .enable_delay = 0x04,
190 .stable_count = 0x66,
191 .active_delay = 0x09,
192 .xtal_freq_count = 0xFE,
193 .debounce = 0xFDE8,
194 },
195};
196
Stephen Warren91a687d2013-06-13 11:24:11 -0600197static void set_pts(struct tegra_usb_phy *phy, u8 pts_val)
198{
199 void __iomem *base = phy->regs;
200 unsigned long val;
201
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +0300202 if (phy->soc_config->has_hostpc) {
203 val = readl(base + TEGRA_USB_HOSTPC1_DEVLC);
204 val &= ~TEGRA_USB_HOSTPC1_DEVLC_PTS(~0);
205 val |= TEGRA_USB_HOSTPC1_DEVLC_PTS(pts_val);
206 writel(val, base + TEGRA_USB_HOSTPC1_DEVLC);
207 } else {
208 val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
209 val &= ~TEGRA_USB_PORTSC1_PTS(~0);
210 val |= TEGRA_USB_PORTSC1_PTS(pts_val);
211 writel(val, base + TEGRA_USB_PORTSC1);
212 }
Stephen Warren91a687d2013-06-13 11:24:11 -0600213}
214
215static void set_phcd(struct tegra_usb_phy *phy, bool enable)
216{
217 void __iomem *base = phy->regs;
218 unsigned long val;
219
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +0300220 if (phy->soc_config->has_hostpc) {
221 val = readl(base + TEGRA_USB_HOSTPC1_DEVLC);
222 if (enable)
223 val |= TEGRA_USB_HOSTPC1_DEVLC_PHCD;
224 else
225 val &= ~TEGRA_USB_HOSTPC1_DEVLC_PHCD;
226 writel(val, base + TEGRA_USB_HOSTPC1_DEVLC);
227 } else {
228 val = readl(base + TEGRA_USB_PORTSC1) & ~PORT_RWC_BITS;
229 if (enable)
230 val |= TEGRA_USB_PORTSC1_PHCD;
231 else
232 val &= ~TEGRA_USB_PORTSC1_PHCD;
233 writel(val, base + TEGRA_USB_PORTSC1);
234 }
Stephen Warren91a687d2013-06-13 11:24:11 -0600235}
236
Benoit Goby91525d02011-03-09 16:28:55 -0800237static int utmip_pad_open(struct tegra_usb_phy *phy)
238{
Dmitry Osipenko14347032018-04-10 01:02:58 +0300239 int ret;
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300240
Dmitry Osipenko14347032018-04-10 01:02:58 +0300241 ret = clk_prepare_enable(phy->pad_clk);
242 if (ret) {
243 dev_err(phy->u_phy.dev,
244 "Failed to enable UTMI-pads clock: %d\n", ret);
245 return ret;
246 }
247
248 spin_lock(&utmip_pad_lock);
249
250 ret = reset_control_deassert(phy->pad_rst);
251 if (ret) {
252 dev_err(phy->u_phy.dev,
253 "Failed to initialize UTMI-pads reset: %d\n", ret);
254 goto unlock;
255 }
256
257 ret = reset_control_assert(phy->pad_rst);
258 if (ret) {
259 dev_err(phy->u_phy.dev,
260 "Failed to assert UTMI-pads reset: %d\n", ret);
261 goto unlock;
262 }
263
264 udelay(1);
265
266 ret = reset_control_deassert(phy->pad_rst);
267 if (ret)
268 dev_err(phy->u_phy.dev,
269 "Failed to deassert UTMI-pads reset: %d\n", ret);
270unlock:
271 spin_unlock(&utmip_pad_lock);
272
273 clk_disable_unprepare(phy->pad_clk);
274
275 return ret;
276}
277
278static int utmip_pad_close(struct tegra_usb_phy *phy)
279{
280 int ret;
281
282 ret = clk_prepare_enable(phy->pad_clk);
283 if (ret) {
284 dev_err(phy->u_phy.dev,
285 "Failed to enable UTMI-pads clock: %d\n", ret);
286 return ret;
287 }
288
289 ret = reset_control_assert(phy->pad_rst);
290 if (ret)
291 dev_err(phy->u_phy.dev,
292 "Failed to assert UTMI-pads reset: %d\n", ret);
293
294 udelay(1);
295
296 clk_disable_unprepare(phy->pad_clk);
297
298 return ret;
Benoit Goby91525d02011-03-09 16:28:55 -0800299}
300
Benoit Goby91525d02011-03-09 16:28:55 -0800301static void utmip_pad_power_on(struct tegra_usb_phy *phy)
302{
303 unsigned long val, flags;
304 void __iomem *base = phy->pad_regs;
Tuomas Tynkkynene497a242013-08-12 16:06:53 +0300305 struct tegra_utmip_config *config = phy->config;
Benoit Goby91525d02011-03-09 16:28:55 -0800306
Prashant Gaikwad6a5278d2012-06-05 09:59:35 +0530307 clk_prepare_enable(phy->pad_clk);
Benoit Goby91525d02011-03-09 16:28:55 -0800308
309 spin_lock_irqsave(&utmip_pad_lock, flags);
310
311 if (utmip_pad_count++ == 0) {
312 val = readl(base + UTMIP_BIAS_CFG0);
313 val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
Tuomas Tynkkynene497a242013-08-12 16:06:53 +0300314
315 if (phy->soc_config->requires_extra_tuning_parameters) {
316 val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) |
317 UTMIP_HSDISCON_LEVEL(~0) |
318 UTMIP_HSDISCON_LEVEL_MSB(~0));
319
320 val |= UTMIP_HSSQUELCH_LEVEL(config->hssquelch_level);
321 val |= UTMIP_HSDISCON_LEVEL(config->hsdiscon_level);
322 val |= UTMIP_HSDISCON_LEVEL_MSB(config->hsdiscon_level);
323 }
Benoit Goby91525d02011-03-09 16:28:55 -0800324 writel(val, base + UTMIP_BIAS_CFG0);
325 }
326
327 spin_unlock_irqrestore(&utmip_pad_lock, flags);
328
Prashant Gaikwad6a5278d2012-06-05 09:59:35 +0530329 clk_disable_unprepare(phy->pad_clk);
Benoit Goby91525d02011-03-09 16:28:55 -0800330}
331
332static int utmip_pad_power_off(struct tegra_usb_phy *phy)
333{
334 unsigned long val, flags;
335 void __iomem *base = phy->pad_regs;
336
337 if (!utmip_pad_count) {
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300338 dev_err(phy->u_phy.dev, "UTMIP pad already powered off\n");
Benoit Goby91525d02011-03-09 16:28:55 -0800339 return -EINVAL;
340 }
341
Prashant Gaikwad6a5278d2012-06-05 09:59:35 +0530342 clk_prepare_enable(phy->pad_clk);
Benoit Goby91525d02011-03-09 16:28:55 -0800343
344 spin_lock_irqsave(&utmip_pad_lock, flags);
345
346 if (--utmip_pad_count == 0) {
347 val = readl(base + UTMIP_BIAS_CFG0);
348 val |= UTMIP_OTGPD | UTMIP_BIASPD;
349 writel(val, base + UTMIP_BIAS_CFG0);
350 }
351
352 spin_unlock_irqrestore(&utmip_pad_lock, flags);
353
Prashant Gaikwad6a5278d2012-06-05 09:59:35 +0530354 clk_disable_unprepare(phy->pad_clk);
Benoit Goby91525d02011-03-09 16:28:55 -0800355
356 return 0;
357}
358
359static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
360{
Dmitry Osipenko43bcf642017-12-17 20:02:39 +0300361 u32 tmp;
362
363 return readl_poll_timeout(reg, tmp, (tmp & mask) == result,
364 2000, 6000);
Benoit Goby91525d02011-03-09 16:28:55 -0800365}
366
367static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
368{
369 unsigned long val;
370 void __iomem *base = phy->regs;
371
Jon Hunter203f44c42017-10-02 12:22:53 +0100372 /*
373 * The USB driver may have already initiated the phy clock
374 * disable so wait to see if the clock turns off and if not
375 * then proceed with gating the clock.
376 */
377 if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) == 0)
378 return;
379
Venu Byravarasu3a55c6a2013-01-16 03:30:20 +0000380 if (phy->is_legacy_phy) {
Benoit Goby91525d02011-03-09 16:28:55 -0800381 val = readl(base + USB_SUSP_CTRL);
382 val |= USB_SUSP_SET;
383 writel(val, base + USB_SUSP_CTRL);
384
385 udelay(10);
386
387 val = readl(base + USB_SUSP_CTRL);
388 val &= ~USB_SUSP_SET;
389 writel(val, base + USB_SUSP_CTRL);
Venu Byravarasubbdabdb2013-01-17 20:15:37 +0000390 } else
Stephen Warren91a687d2013-06-13 11:24:11 -0600391 set_phcd(phy, true);
Benoit Goby91525d02011-03-09 16:28:55 -0800392
393 if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300394 dev_err(phy->u_phy.dev,
395 "Timeout waiting for PHY to stabilize on disable\n");
Benoit Goby91525d02011-03-09 16:28:55 -0800396}
397
398static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
399{
400 unsigned long val;
401 void __iomem *base = phy->regs;
402
Jon Hunter203f44c42017-10-02 12:22:53 +0100403 /*
404 * The USB driver may have already initiated the phy clock
405 * enable so wait to see if the clock turns on and if not
406 * then proceed with ungating the clock.
407 */
408 if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
409 USB_PHY_CLK_VALID) == 0)
410 return;
411
Venu Byravarasu3a55c6a2013-01-16 03:30:20 +0000412 if (phy->is_legacy_phy) {
Benoit Goby91525d02011-03-09 16:28:55 -0800413 val = readl(base + USB_SUSP_CTRL);
414 val |= USB_SUSP_CLR;
415 writel(val, base + USB_SUSP_CTRL);
416
417 udelay(10);
418
419 val = readl(base + USB_SUSP_CTRL);
420 val &= ~USB_SUSP_CLR;
421 writel(val, base + USB_SUSP_CTRL);
Venu Byravarasubbdabdb2013-01-17 20:15:37 +0000422 } else
Stephen Warren91a687d2013-06-13 11:24:11 -0600423 set_phcd(phy, false);
Benoit Goby91525d02011-03-09 16:28:55 -0800424
425 if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
426 USB_PHY_CLK_VALID))
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300427 dev_err(phy->u_phy.dev,
428 "Timeout waiting for PHY to stabilize on enable\n");
Benoit Goby91525d02011-03-09 16:28:55 -0800429}
430
431static int utmi_phy_power_on(struct tegra_usb_phy *phy)
432{
433 unsigned long val;
434 void __iomem *base = phy->regs;
435 struct tegra_utmip_config *config = phy->config;
436
437 val = readl(base + USB_SUSP_CTRL);
438 val |= UTMIP_RESET;
439 writel(val, base + USB_SUSP_CTRL);
440
Venu Byravarasu3a55c6a2013-01-16 03:30:20 +0000441 if (phy->is_legacy_phy) {
Benoit Goby91525d02011-03-09 16:28:55 -0800442 val = readl(base + USB1_LEGACY_CTRL);
443 val |= USB1_NO_LEGACY_MODE;
444 writel(val, base + USB1_LEGACY_CTRL);
445 }
446
447 val = readl(base + UTMIP_TX_CFG0);
Tuomas Tynkkynenf5833a02013-08-12 16:06:50 +0300448 val |= UTMIP_FS_PREABMLE_J;
Benoit Goby91525d02011-03-09 16:28:55 -0800449 writel(val, base + UTMIP_TX_CFG0);
450
451 val = readl(base + UTMIP_HSRX_CFG0);
452 val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
453 val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
454 val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
455 writel(val, base + UTMIP_HSRX_CFG0);
456
457 val = readl(base + UTMIP_HSRX_CFG1);
458 val &= ~UTMIP_HS_SYNC_START_DLY(~0);
459 val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
460 writel(val, base + UTMIP_HSRX_CFG1);
461
462 val = readl(base + UTMIP_DEBOUNCE_CFG0);
463 val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
464 val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
465 writel(val, base + UTMIP_DEBOUNCE_CFG0);
466
467 val = readl(base + UTMIP_MISC_CFG0);
468 val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
469 writel(val, base + UTMIP_MISC_CFG0);
470
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +0300471 if (!phy->soc_config->utmi_pll_config_in_car_module) {
472 val = readl(base + UTMIP_MISC_CFG1);
473 val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) |
474 UTMIP_PLLU_STABLE_COUNT(~0));
475 val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
476 UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
477 writel(val, base + UTMIP_MISC_CFG1);
Benoit Goby91525d02011-03-09 16:28:55 -0800478
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +0300479 val = readl(base + UTMIP_PLL_CFG1);
480 val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) |
481 UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
482 val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
483 UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
484 writel(val, base + UTMIP_PLL_CFG1);
485 }
Benoit Goby91525d02011-03-09 16:28:55 -0800486
Tuomas Tynkkynen6558d7e2013-07-25 21:38:09 +0300487 if (phy->mode == USB_DR_MODE_PERIPHERAL) {
Benoit Goby91525d02011-03-09 16:28:55 -0800488 val = readl(base + USB_SUSP_CTRL);
489 val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
490 writel(val, base + USB_SUSP_CTRL);
Tuomas Tynkkynenf5833a02013-08-12 16:06:50 +0300491
492 val = readl(base + UTMIP_BAT_CHRG_CFG0);
493 val &= ~UTMIP_PD_CHRG;
494 writel(val, base + UTMIP_BAT_CHRG_CFG0);
495 } else {
496 val = readl(base + UTMIP_BAT_CHRG_CFG0);
497 val |= UTMIP_PD_CHRG;
498 writel(val, base + UTMIP_BAT_CHRG_CFG0);
Benoit Goby91525d02011-03-09 16:28:55 -0800499 }
500
501 utmip_pad_power_on(phy);
502
503 val = readl(base + UTMIP_XCVR_CFG0);
504 val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
Tuomas Tynkkynenf5833a02013-08-12 16:06:50 +0300505 UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_LSBIAS_SEL |
506 UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_SETUP_MSB(~0) |
Tuomas Tynkkynene497a242013-08-12 16:06:53 +0300507 UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0));
508
509 if (!config->xcvr_setup_use_fuses) {
510 val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
511 val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup);
512 }
Benoit Goby91525d02011-03-09 16:28:55 -0800513 val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
514 val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
Tuomas Tynkkynene497a242013-08-12 16:06:53 +0300515
516 if (phy->soc_config->requires_extra_tuning_parameters) {
517 val &= ~(UTMIP_XCVR_HSSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
518 val |= UTMIP_XCVR_HSSLEW(config->xcvr_hsslew);
519 val |= UTMIP_XCVR_HSSLEW_MSB(config->xcvr_hsslew);
520 }
Benoit Goby91525d02011-03-09 16:28:55 -0800521 writel(val, base + UTMIP_XCVR_CFG0);
522
523 val = readl(base + UTMIP_XCVR_CFG1);
524 val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
525 UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
526 val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
527 writel(val, base + UTMIP_XCVR_CFG1);
528
Benoit Goby91525d02011-03-09 16:28:55 -0800529 val = readl(base + UTMIP_BIAS_CFG1);
530 val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
531 val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
532 writel(val, base + UTMIP_BIAS_CFG1);
533
Tuomas Tynkkynene497a242013-08-12 16:06:53 +0300534 val = readl(base + UTMIP_SPARE_CFG0);
535 if (config->xcvr_setup_use_fuses)
536 val |= FUSE_SETUP_SEL;
537 else
538 val &= ~FUSE_SETUP_SEL;
539 writel(val, base + UTMIP_SPARE_CFG0);
540
541 if (!phy->is_legacy_phy) {
Benoit Goby91525d02011-03-09 16:28:55 -0800542 val = readl(base + USB_SUSP_CTRL);
543 val |= UTMIP_PHY_ENABLE;
544 writel(val, base + USB_SUSP_CTRL);
545 }
546
547 val = readl(base + USB_SUSP_CTRL);
548 val &= ~UTMIP_RESET;
549 writel(val, base + USB_SUSP_CTRL);
550
Venu Byravarasu3a55c6a2013-01-16 03:30:20 +0000551 if (phy->is_legacy_phy) {
Benoit Goby91525d02011-03-09 16:28:55 -0800552 val = readl(base + USB1_LEGACY_CTRL);
553 val &= ~USB1_VBUS_SENSE_CTL_MASK;
554 val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD;
555 writel(val, base + USB1_LEGACY_CTRL);
556
557 val = readl(base + USB_SUSP_CTRL);
558 val &= ~USB_SUSP_SET;
559 writel(val, base + USB_SUSP_CTRL);
560 }
561
562 utmi_phy_clk_enable(phy);
563
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +0300564 if (phy->soc_config->requires_usbmode_setup) {
565 val = readl(base + USB_USBMODE);
566 val &= ~USB_USBMODE_MASK;
567 if (phy->mode == USB_DR_MODE_HOST)
568 val |= USB_USBMODE_HOST;
569 else
570 val |= USB_USBMODE_DEVICE;
571 writel(val, base + USB_USBMODE);
572 }
573
Venu Byravarasubbdabdb2013-01-17 20:15:37 +0000574 if (!phy->is_legacy_phy)
Stephen Warren91a687d2013-06-13 11:24:11 -0600575 set_pts(phy, 0);
Benoit Goby91525d02011-03-09 16:28:55 -0800576
577 return 0;
578}
579
Venu Byravarasu1ba82162012-09-05 18:50:23 +0530580static int utmi_phy_power_off(struct tegra_usb_phy *phy)
Benoit Goby91525d02011-03-09 16:28:55 -0800581{
582 unsigned long val;
583 void __iomem *base = phy->regs;
584
585 utmi_phy_clk_disable(phy);
586
Tuomas Tynkkynen6558d7e2013-07-25 21:38:09 +0300587 if (phy->mode == USB_DR_MODE_PERIPHERAL) {
Benoit Goby91525d02011-03-09 16:28:55 -0800588 val = readl(base + USB_SUSP_CTRL);
589 val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
590 val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
591 writel(val, base + USB_SUSP_CTRL);
592 }
593
594 val = readl(base + USB_SUSP_CTRL);
595 val |= UTMIP_RESET;
596 writel(val, base + USB_SUSP_CTRL);
597
598 val = readl(base + UTMIP_BAT_CHRG_CFG0);
599 val |= UTMIP_PD_CHRG;
600 writel(val, base + UTMIP_BAT_CHRG_CFG0);
601
602 val = readl(base + UTMIP_XCVR_CFG0);
603 val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
604 UTMIP_FORCE_PDZI_POWERDOWN;
605 writel(val, base + UTMIP_XCVR_CFG0);
606
607 val = readl(base + UTMIP_XCVR_CFG1);
608 val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
609 UTMIP_FORCE_PDDR_POWERDOWN;
610 writel(val, base + UTMIP_XCVR_CFG1);
611
Venu Byravarasu1ba82162012-09-05 18:50:23 +0530612 return utmip_pad_power_off(phy);
Benoit Goby91525d02011-03-09 16:28:55 -0800613}
614
615static void utmi_phy_preresume(struct tegra_usb_phy *phy)
616{
617 unsigned long val;
618 void __iomem *base = phy->regs;
619
620 val = readl(base + UTMIP_TX_CFG0);
621 val |= UTMIP_HS_DISCON_DISABLE;
622 writel(val, base + UTMIP_TX_CFG0);
623}
624
625static void utmi_phy_postresume(struct tegra_usb_phy *phy)
626{
627 unsigned long val;
628 void __iomem *base = phy->regs;
629
630 val = readl(base + UTMIP_TX_CFG0);
631 val &= ~UTMIP_HS_DISCON_DISABLE;
632 writel(val, base + UTMIP_TX_CFG0);
633}
634
635static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
636 enum tegra_usb_phy_port_speed port_speed)
637{
638 unsigned long val;
639 void __iomem *base = phy->regs;
640
641 val = readl(base + UTMIP_MISC_CFG0);
642 val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
643 if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
644 val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
645 else
646 val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
647 writel(val, base + UTMIP_MISC_CFG0);
648 udelay(1);
649
650 val = readl(base + UTMIP_MISC_CFG0);
651 val |= UTMIP_DPDM_OBSERVE;
652 writel(val, base + UTMIP_MISC_CFG0);
653 udelay(10);
654}
655
656static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
657{
658 unsigned long val;
659 void __iomem *base = phy->regs;
660
661 val = readl(base + UTMIP_MISC_CFG0);
662 val &= ~UTMIP_DPDM_OBSERVE;
663 writel(val, base + UTMIP_MISC_CFG0);
664 udelay(10);
665}
666
667static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
668{
669 int ret;
670 unsigned long val;
671 void __iomem *base = phy->regs;
Benoit Goby91525d02011-03-09 16:28:55 -0800672
Venu Byravarasu6829f922013-05-16 19:43:01 +0530673 ret = gpio_direction_output(phy->reset_gpio, 0);
674 if (ret < 0) {
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300675 dev_err(phy->u_phy.dev, "GPIO %d not set to 0: %d\n",
676 phy->reset_gpio, ret);
Venu Byravarasu6829f922013-05-16 19:43:01 +0530677 return ret;
678 }
Benoit Goby91525d02011-03-09 16:28:55 -0800679 msleep(5);
Venu Byravarasu6829f922013-05-16 19:43:01 +0530680 ret = gpio_direction_output(phy->reset_gpio, 1);
681 if (ret < 0) {
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300682 dev_err(phy->u_phy.dev, "GPIO %d not set to 1: %d\n",
683 phy->reset_gpio, ret);
Venu Byravarasu6829f922013-05-16 19:43:01 +0530684 return ret;
685 }
Benoit Goby91525d02011-03-09 16:28:55 -0800686
Prashant Gaikwad6a5278d2012-06-05 09:59:35 +0530687 clk_prepare_enable(phy->clk);
Benoit Goby91525d02011-03-09 16:28:55 -0800688 msleep(1);
689
690 val = readl(base + USB_SUSP_CTRL);
691 val |= UHSIC_RESET;
692 writel(val, base + USB_SUSP_CTRL);
693
694 val = readl(base + ULPI_TIMING_CTRL_0);
695 val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
696 writel(val, base + ULPI_TIMING_CTRL_0);
697
698 val = readl(base + USB_SUSP_CTRL);
699 val |= ULPI_PHY_ENABLE;
700 writel(val, base + USB_SUSP_CTRL);
701
702 val = 0;
703 writel(val, base + ULPI_TIMING_CTRL_1);
704
705 val |= ULPI_DATA_TRIMMER_SEL(4);
706 val |= ULPI_STPDIRNXT_TRIMMER_SEL(4);
707 val |= ULPI_DIR_TRIMMER_SEL(4);
708 writel(val, base + ULPI_TIMING_CTRL_1);
709 udelay(10);
710
711 val |= ULPI_DATA_TRIMMER_LOAD;
712 val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
713 val |= ULPI_DIR_TRIMMER_LOAD;
714 writel(val, base + ULPI_TIMING_CTRL_1);
715
716 /* Fix VbusInvalid due to floating VBUS */
Heikki Krogerusb96d3b02012-02-13 13:24:18 +0200717 ret = usb_phy_io_write(phy->ulpi, 0x40, 0x08);
Benoit Goby91525d02011-03-09 16:28:55 -0800718 if (ret) {
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300719 dev_err(phy->u_phy.dev, "ULPI write failed: %d\n", ret);
Benoit Goby91525d02011-03-09 16:28:55 -0800720 return ret;
721 }
722
Heikki Krogerusb96d3b02012-02-13 13:24:18 +0200723 ret = usb_phy_io_write(phy->ulpi, 0x80, 0x0B);
Benoit Goby91525d02011-03-09 16:28:55 -0800724 if (ret) {
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300725 dev_err(phy->u_phy.dev, "ULPI write failed: %d\n", ret);
Benoit Goby91525d02011-03-09 16:28:55 -0800726 return ret;
727 }
728
Benoit Goby91525d02011-03-09 16:28:55 -0800729 val = readl(base + USB_SUSP_CTRL);
730 val |= USB_SUSP_CLR;
731 writel(val, base + USB_SUSP_CTRL);
732 udelay(100);
733
734 val = readl(base + USB_SUSP_CTRL);
735 val &= ~USB_SUSP_CLR;
736 writel(val, base + USB_SUSP_CTRL);
737
738 return 0;
739}
740
Venu Byravarasu1ba82162012-09-05 18:50:23 +0530741static int ulpi_phy_power_off(struct tegra_usb_phy *phy)
Benoit Goby91525d02011-03-09 16:28:55 -0800742{
Dmitry Osipenko28d190a2020-01-06 04:33:59 +0300743 int err;
744
745 err = gpio_direction_output(phy->reset_gpio, 0);
746 if (err) {
747 dev_err(phy->u_phy.dev, "reset GPIO not asserted: %d\n", err);
748 return err;
749 }
750
751 usleep_range(5000, 6000);
752
753 clk_disable_unprepare(phy->clk);
754
755 return 0;
Venu Byravarasu1ba82162012-09-05 18:50:23 +0530756}
757
Venu Byravarasu1ba82162012-09-05 18:50:23 +0530758static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
759{
Dmitry Osipenko18bd8bf2020-01-06 04:34:00 +0300760 int err;
761
762 if (phy->powered_on)
763 return 0;
764
Venu Byravarasu3f9db1a2013-01-16 03:30:21 +0000765 if (phy->is_ulpi_phy)
Dmitry Osipenko18bd8bf2020-01-06 04:34:00 +0300766 err = ulpi_phy_power_on(phy);
Venu Byravarasu1ba82162012-09-05 18:50:23 +0530767 else
Dmitry Osipenko18bd8bf2020-01-06 04:34:00 +0300768 err = utmi_phy_power_on(phy);
769 if (err)
770 return err;
771
772 phy->powered_on = true;
773
774 return 0;
Venu Byravarasu1ba82162012-09-05 18:50:23 +0530775}
776
777static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
778{
Dmitry Osipenko18bd8bf2020-01-06 04:34:00 +0300779 int err;
780
781 if (!phy->powered_on)
782 return 0;
783
Venu Byravarasu3f9db1a2013-01-16 03:30:21 +0000784 if (phy->is_ulpi_phy)
Dmitry Osipenko18bd8bf2020-01-06 04:34:00 +0300785 err = ulpi_phy_power_off(phy);
Venu Byravarasu1ba82162012-09-05 18:50:23 +0530786 else
Dmitry Osipenko18bd8bf2020-01-06 04:34:00 +0300787 err = utmi_phy_power_off(phy);
788 if (err)
789 return err;
790
791 phy->powered_on = false;
792
793 return 0;
Venu Byravarasu1ba82162012-09-05 18:50:23 +0530794}
795
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +0300796static void tegra_usb_phy_shutdown(struct usb_phy *u_phy)
797{
798 struct tegra_usb_phy *phy = container_of(u_phy, struct tegra_usb_phy,
799 u_phy);
800
801 if (WARN_ON(!phy->freq))
802 return;
803
804 tegra_usb_phy_power_off(phy);
805
806 if (!phy->is_ulpi_phy)
807 utmip_pad_close(phy);
808
809 if (!IS_ERR(phy->vbus))
810 regulator_disable(phy->vbus);
811
812 clk_disable_unprepare(phy->pll_u);
813
814 phy->freq = NULL;
815}
816
817static int tegra_usb_phy_set_suspend(struct usb_phy *x, int suspend)
Venu Byravarasu1ba82162012-09-05 18:50:23 +0530818{
819 struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +0300820
821 if (WARN_ON(!phy->freq))
822 return -EINVAL;
823
Venu Byravarasu1ba82162012-09-05 18:50:23 +0530824 if (suspend)
825 return tegra_usb_phy_power_off(phy);
826 else
827 return tegra_usb_phy_power_on(phy);
Benoit Goby91525d02011-03-09 16:28:55 -0800828}
829
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530830static int ulpi_open(struct tegra_usb_phy *phy)
Benoit Goby91525d02011-03-09 16:28:55 -0800831{
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530832 int err;
833
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530834 err = gpio_direction_output(phy->reset_gpio, 0);
835 if (err < 0) {
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300836 dev_err(phy->u_phy.dev,
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +0300837 "ULPI reset GPIO %d direction not asserted: %d\n",
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300838 phy->reset_gpio, err);
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530839 return err;
840 }
841
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530842 return 0;
843}
844
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +0300845static int tegra_usb_phy_init(struct usb_phy *u_phy)
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530846{
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +0300847 struct tegra_usb_phy *phy = container_of(u_phy, struct tegra_usb_phy,
848 u_phy);
Benoit Goby91525d02011-03-09 16:28:55 -0800849 unsigned long parent_rate;
850 int i;
851 int err;
852
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +0300853 if (WARN_ON(phy->freq))
854 return 0;
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530855
856 err = clk_prepare_enable(phy->pll_u);
857 if (err)
858 return err;
Benoit Goby91525d02011-03-09 16:28:55 -0800859
860 parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
861 for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
862 if (tegra_freq_table[i].freq == parent_rate) {
863 phy->freq = &tegra_freq_table[i];
864 break;
865 }
866 }
867 if (!phy->freq) {
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300868 dev_err(phy->u_phy.dev, "Invalid pll_u parent rate %ld\n",
869 parent_rate);
Benoit Goby91525d02011-03-09 16:28:55 -0800870 err = -EINVAL;
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530871 goto fail;
Benoit Goby91525d02011-03-09 16:28:55 -0800872 }
873
Mikko Perttunenf5b8c8b2013-07-17 10:37:49 +0300874 if (!IS_ERR(phy->vbus)) {
875 err = regulator_enable(phy->vbus);
876 if (err) {
Tuomas Tynkkynen185d0fd2013-07-25 21:38:01 +0300877 dev_err(phy->u_phy.dev,
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300878 "Failed to enable USB VBUS regulator: %d\n",
Mikko Perttunenf5b8c8b2013-07-17 10:37:49 +0300879 err);
880 goto fail;
881 }
882 }
883
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530884 if (phy->is_ulpi_phy)
885 err = ulpi_open(phy);
886 else
887 err = utmip_pad_open(phy);
888 if (err < 0)
889 goto fail;
Benoit Goby91525d02011-03-09 16:28:55 -0800890
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +0300891 err = tegra_usb_phy_power_on(phy);
892 if (err)
893 goto close_phy;
894
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530895 return 0;
Benoit Goby91525d02011-03-09 16:28:55 -0800896
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +0300897close_phy:
898 if (!phy->is_ulpi_phy)
899 utmip_pad_close(phy);
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530900fail:
Prashant Gaikwad6a5278d2012-06-05 09:59:35 +0530901 clk_disable_unprepare(phy->pll_u);
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +0300902
903 phy->freq = NULL;
904
Venu Byravarasu2d22b422013-05-16 19:43:02 +0530905 return err;
Benoit Goby91525d02011-03-09 16:28:55 -0800906}
907
Venu Byravarasuab137d02013-01-24 15:57:03 +0530908void tegra_usb_phy_preresume(struct usb_phy *x)
Benoit Goby91525d02011-03-09 16:28:55 -0800909{
Venu Byravarasuab137d02013-01-24 15:57:03 +0530910 struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
911
Venu Byravarasu3f9db1a2013-01-16 03:30:21 +0000912 if (!phy->is_ulpi_phy)
Benoit Goby91525d02011-03-09 16:28:55 -0800913 utmi_phy_preresume(phy);
914}
Arnd Bergmann4265cbf2012-03-02 15:58:42 -0500915EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume);
Benoit Goby91525d02011-03-09 16:28:55 -0800916
Venu Byravarasuab137d02013-01-24 15:57:03 +0530917void tegra_usb_phy_postresume(struct usb_phy *x)
Benoit Goby91525d02011-03-09 16:28:55 -0800918{
Venu Byravarasuab137d02013-01-24 15:57:03 +0530919 struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
920
Venu Byravarasu3f9db1a2013-01-16 03:30:21 +0000921 if (!phy->is_ulpi_phy)
Benoit Goby91525d02011-03-09 16:28:55 -0800922 utmi_phy_postresume(phy);
923}
Arnd Bergmann4265cbf2012-03-02 15:58:42 -0500924EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume);
Benoit Goby91525d02011-03-09 16:28:55 -0800925
Venu Byravarasuab137d02013-01-24 15:57:03 +0530926void tegra_ehci_phy_restore_start(struct usb_phy *x,
Benoit Goby91525d02011-03-09 16:28:55 -0800927 enum tegra_usb_phy_port_speed port_speed)
928{
Venu Byravarasuab137d02013-01-24 15:57:03 +0530929 struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
930
Venu Byravarasu3f9db1a2013-01-16 03:30:21 +0000931 if (!phy->is_ulpi_phy)
Benoit Goby91525d02011-03-09 16:28:55 -0800932 utmi_phy_restore_start(phy, port_speed);
933}
Arnd Bergmann4265cbf2012-03-02 15:58:42 -0500934EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start);
Benoit Goby91525d02011-03-09 16:28:55 -0800935
Venu Byravarasuab137d02013-01-24 15:57:03 +0530936void tegra_ehci_phy_restore_end(struct usb_phy *x)
Benoit Goby91525d02011-03-09 16:28:55 -0800937{
Venu Byravarasuab137d02013-01-24 15:57:03 +0530938 struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
939
Venu Byravarasu3f9db1a2013-01-16 03:30:21 +0000940 if (!phy->is_ulpi_phy)
Benoit Goby91525d02011-03-09 16:28:55 -0800941 utmi_phy_restore_end(phy);
942}
Arnd Bergmann4265cbf2012-03-02 15:58:42 -0500943EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
Benoit Goby91525d02011-03-09 16:28:55 -0800944
Mikko Perttunen81d5dfe2013-07-17 09:31:01 +0300945static int read_utmi_param(struct platform_device *pdev, const char *param,
946 u8 *dest)
947{
948 u32 value;
949 int err = of_property_read_u32(pdev->dev.of_node, param, &value);
950 *dest = (u8)value;
951 if (err < 0)
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300952 dev_err(&pdev->dev,
953 "Failed to read USB UTMI parameter %s: %d\n",
Mikko Perttunen81d5dfe2013-07-17 09:31:01 +0300954 param, err);
955 return err;
956}
957
958static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy,
959 struct platform_device *pdev)
960{
961 struct resource *res;
962 int err;
963 struct tegra_utmip_config *config;
964
965 tegra_phy->is_ulpi_phy = false;
966
967 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
968 if (!res) {
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300969 dev_err(&pdev->dev, "Failed to get UTMI pad regs\n");
Mikko Perttunen81d5dfe2013-07-17 09:31:01 +0300970 return -ENXIO;
971 }
972
973 tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
974 resource_size(res));
Chris Ruehl851dd022013-12-04 10:02:44 +0800975 if (!tegra_phy->pad_regs) {
Dmitry Osipenkof59cd942018-04-10 01:02:57 +0300976 dev_err(&pdev->dev, "Failed to remap UTMI pad regs\n");
Mikko Perttunen81d5dfe2013-07-17 09:31:01 +0300977 return -ENOMEM;
978 }
979
Thierry Reding9ce9ec92014-07-21 13:37:37 +0200980 tegra_phy->config = devm_kzalloc(&pdev->dev, sizeof(*config),
981 GFP_KERNEL);
Peter Chen01ad32d2014-10-14 15:56:13 +0800982 if (!tegra_phy->config)
Mikko Perttunen81d5dfe2013-07-17 09:31:01 +0300983 return -ENOMEM;
Mikko Perttunen81d5dfe2013-07-17 09:31:01 +0300984
985 config = tegra_phy->config;
986
987 err = read_utmi_param(pdev, "nvidia,hssync-start-delay",
988 &config->hssync_start_delay);
989 if (err < 0)
990 return err;
991
992 err = read_utmi_param(pdev, "nvidia,elastic-limit",
993 &config->elastic_limit);
994 if (err < 0)
995 return err;
996
997 err = read_utmi_param(pdev, "nvidia,idle-wait-delay",
998 &config->idle_wait_delay);
999 if (err < 0)
1000 return err;
1001
1002 err = read_utmi_param(pdev, "nvidia,term-range-adj",
1003 &config->term_range_adj);
1004 if (err < 0)
1005 return err;
1006
Mikko Perttunen81d5dfe2013-07-17 09:31:01 +03001007 err = read_utmi_param(pdev, "nvidia,xcvr-lsfslew",
1008 &config->xcvr_lsfslew);
1009 if (err < 0)
1010 return err;
1011
1012 err = read_utmi_param(pdev, "nvidia,xcvr-lsrslew",
1013 &config->xcvr_lsrslew);
1014 if (err < 0)
1015 return err;
1016
Tuomas Tynkkynene497a242013-08-12 16:06:53 +03001017 if (tegra_phy->soc_config->requires_extra_tuning_parameters) {
1018 err = read_utmi_param(pdev, "nvidia,xcvr-hsslew",
1019 &config->xcvr_hsslew);
1020 if (err < 0)
1021 return err;
1022
1023 err = read_utmi_param(pdev, "nvidia,hssquelch-level",
1024 &config->hssquelch_level);
1025 if (err < 0)
1026 return err;
1027
1028 err = read_utmi_param(pdev, "nvidia,hsdiscon-level",
1029 &config->hsdiscon_level);
1030 if (err < 0)
1031 return err;
1032 }
1033
1034 config->xcvr_setup_use_fuses = of_property_read_bool(
1035 pdev->dev.of_node, "nvidia,xcvr-setup-use-fuses");
1036
1037 if (!config->xcvr_setup_use_fuses) {
1038 err = read_utmi_param(pdev, "nvidia,xcvr-setup",
1039 &config->xcvr_setup);
1040 if (err < 0)
1041 return err;
1042 }
1043
Mikko Perttunen81d5dfe2013-07-17 09:31:01 +03001044 return 0;
1045}
1046
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +03001047static const struct tegra_phy_soc_config tegra20_soc_config = {
1048 .utmi_pll_config_in_car_module = false,
1049 .has_hostpc = false,
1050 .requires_usbmode_setup = false,
1051 .requires_extra_tuning_parameters = false,
1052};
1053
1054static const struct tegra_phy_soc_config tegra30_soc_config = {
1055 .utmi_pll_config_in_car_module = true,
1056 .has_hostpc = true,
1057 .requires_usbmode_setup = true,
1058 .requires_extra_tuning_parameters = true,
1059};
1060
Jingoo Han0f0520b2014-06-18 13:43:50 +09001061static const struct of_device_id tegra_usb_phy_id_table[] = {
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +03001062 { .compatible = "nvidia,tegra30-usb-phy", .data = &tegra30_soc_config },
1063 { .compatible = "nvidia,tegra20-usb-phy", .data = &tegra20_soc_config },
1064 { },
1065};
1066MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table);
1067
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301068static int tegra_usb_phy_probe(struct platform_device *pdev)
1069{
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +03001070 const struct of_device_id *match;
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301071 struct resource *res;
1072 struct tegra_usb_phy *tegra_phy = NULL;
1073 struct device_node *np = pdev->dev.of_node;
Tuomas Tynkkynen9fdb07f2013-07-25 21:38:08 +03001074 enum usb_phy_interface phy_type;
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301075 int err;
1076
1077 tegra_phy = devm_kzalloc(&pdev->dev, sizeof(*tegra_phy), GFP_KERNEL);
Peter Chen01ad32d2014-10-14 15:56:13 +08001078 if (!tegra_phy)
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301079 return -ENOMEM;
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301080
Tuomas Tynkkynen3e635202013-08-12 16:06:51 +03001081 match = of_match_device(tegra_usb_phy_id_table, &pdev->dev);
1082 if (!match) {
1083 dev_err(&pdev->dev, "Error: No device match found\n");
1084 return -ENODEV;
1085 }
1086 tegra_phy->soc_config = match->data;
1087
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301088 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1089 if (!res) {
1090 dev_err(&pdev->dev, "Failed to get I/O memory\n");
1091 return -ENXIO;
1092 }
1093
1094 tegra_phy->regs = devm_ioremap(&pdev->dev, res->start,
1095 resource_size(res));
1096 if (!tegra_phy->regs) {
1097 dev_err(&pdev->dev, "Failed to remap I/O memory\n");
1098 return -ENOMEM;
1099 }
1100
1101 tegra_phy->is_legacy_phy =
1102 of_property_read_bool(np, "nvidia,has-legacy-mode");
1103
Tuomas Tynkkynen9fdb07f2013-07-25 21:38:08 +03001104 phy_type = of_usb_get_phy_mode(np);
Tuomas Tynkkynena554aea2013-07-25 22:24:09 +03001105 switch (phy_type) {
1106 case USBPHY_INTERFACE_MODE_UTMI:
Mikko Perttunen81d5dfe2013-07-17 09:31:01 +03001107 err = utmi_phy_probe(tegra_phy, pdev);
1108 if (err < 0)
1109 return err;
Tuomas Tynkkynena554aea2013-07-25 22:24:09 +03001110 break;
1111
1112 case USBPHY_INTERFACE_MODE_ULPI:
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301113 tegra_phy->is_ulpi_phy = true;
1114
1115 tegra_phy->reset_gpio =
1116 of_get_named_gpio(np, "nvidia,phy-reset-gpio", 0);
1117 if (!gpio_is_valid(tegra_phy->reset_gpio)) {
Dmitry Osipenkof59cd942018-04-10 01:02:57 +03001118 dev_err(&pdev->dev,
1119 "Invalid GPIO: %d\n", tegra_phy->reset_gpio);
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301120 return tegra_phy->reset_gpio;
1121 }
Mikko Perttunen81d5dfe2013-07-17 09:31:01 +03001122 tegra_phy->config = NULL;
Tuomas Tynkkynena554aea2013-07-25 22:24:09 +03001123 break;
1124
1125 default:
Dmitry Osipenkof59cd942018-04-10 01:02:57 +03001126 dev_err(&pdev->dev, "phy_type %u is invalid or unsupported\n",
1127 phy_type);
Tuomas Tynkkynen9fdb07f2013-07-25 21:38:08 +03001128 return -EINVAL;
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301129 }
1130
Tuomas Tynkkynen6558d7e2013-07-25 21:38:09 +03001131 if (of_find_property(np, "dr_mode", NULL))
Heikki Krogerus06e71142015-09-21 11:14:34 +03001132 tegra_phy->mode = usb_get_dr_mode(&pdev->dev);
Tuomas Tynkkynen6558d7e2013-07-25 21:38:09 +03001133 else
1134 tegra_phy->mode = USB_DR_MODE_HOST;
1135
1136 if (tegra_phy->mode == USB_DR_MODE_UNKNOWN) {
1137 dev_err(&pdev->dev, "dr_mode is invalid\n");
1138 return -EINVAL;
1139 }
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301140
Mikko Perttunenf5b8c8b2013-07-17 10:37:49 +03001141 /* On some boards, the VBUS regulator doesn't need to be controlled */
1142 if (of_find_property(np, "vbus-supply", NULL)) {
1143 tegra_phy->vbus = devm_regulator_get(&pdev->dev, "vbus");
1144 if (IS_ERR(tegra_phy->vbus))
1145 return PTR_ERR(tegra_phy->vbus);
1146 } else {
1147 dev_notice(&pdev->dev, "no vbus regulator");
1148 tegra_phy->vbus = ERR_PTR(-ENODEV);
1149 }
1150
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +03001151 tegra_phy->pll_u = devm_clk_get(&pdev->dev, "pll_u");
1152 err = PTR_ERR_OR_ZERO(tegra_phy->pll_u);
1153 if (err) {
1154 dev_err(&pdev->dev, "Failed to get pll_u clock: %d\n", err);
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301155 return err;
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +03001156 }
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301157
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +03001158 if (tegra_phy->is_ulpi_phy) {
1159 tegra_phy->clk = devm_clk_get(&pdev->dev, "ulpi-link");
1160 err = PTR_ERR_OR_ZERO(tegra_phy->clk);
1161 if (err) {
1162 dev_err(&pdev->dev,
1163 "Failed to get ULPI clock: %d\n", err);
1164 return err;
1165 }
1166
1167 err = devm_gpio_request(&pdev->dev, tegra_phy->reset_gpio,
1168 "ulpi_phy_reset_b");
1169 if (err < 0) {
1170 dev_err(&pdev->dev, "Request failed for GPIO %d: %d\n",
1171 tegra_phy->reset_gpio, err);
1172 return err;
1173 }
1174
1175 tegra_phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
1176 if (!tegra_phy->ulpi) {
1177 dev_err(&pdev->dev, "Failed to create ULPI OTG\n");
1178 err = -ENOMEM;
1179 return err;
1180 }
1181
1182 tegra_phy->ulpi->io_priv = tegra_phy->regs + ULPI_VIEWPORT;
1183 } else {
1184 tegra_phy->pad_clk = devm_clk_get(&pdev->dev, "utmi-pads");
1185 err = PTR_ERR_OR_ZERO(tegra_phy->pad_clk);
1186 if (err) {
1187 dev_err(&pdev->dev,
1188 "Failed to get UTMIP pad clock: %d\n", err);
1189 return err;
1190 }
1191
1192 tegra_phy->pad_rst = devm_reset_control_get_optional_shared(
1193 &pdev->dev, "utmi-pads");
1194 err = PTR_ERR_OR_ZERO(tegra_phy->pad_rst);
1195 if (err) {
1196 dev_err(&pdev->dev,
1197 "Failed to get UTMI-pads reset: %d\n", err);
1198 return err;
1199 }
1200 }
1201
1202 tegra_phy->u_phy.dev = &pdev->dev;
1203 tegra_phy->u_phy.init = tegra_usb_phy_init;
1204 tegra_phy->u_phy.shutdown = tegra_usb_phy_shutdown;
1205 tegra_phy->u_phy.set_suspend = tegra_usb_phy_set_suspend;
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301206
Libo Chen72031b52013-08-30 11:23:32 +08001207 platform_set_drvdata(pdev, tegra_phy);
Tuomas Tynkkynen0ee5b4a2013-07-25 21:38:05 +03001208
1209 err = usb_add_phy_dev(&tegra_phy->u_phy);
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +03001210 if (err < 0)
1211 goto free_ulpi;
Tuomas Tynkkynen0ee5b4a2013-07-25 21:38:05 +03001212
1213 return 0;
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +03001214
1215free_ulpi:
1216 if (tegra_phy->ulpi) {
1217 kfree(tegra_phy->ulpi->otg);
1218 kfree(tegra_phy->ulpi);
1219 }
1220
1221 return err;
Tuomas Tynkkynen0ee5b4a2013-07-25 21:38:05 +03001222}
1223
1224static int tegra_usb_phy_remove(struct platform_device *pdev)
1225{
1226 struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev);
1227
1228 usb_remove_phy(&tegra_phy->u_phy);
Dmitry Osipenko5dcdafd2020-01-06 04:34:01 +03001229
1230 if (tegra_phy->ulpi) {
1231 kfree(tegra_phy->ulpi->otg);
1232 kfree(tegra_phy->ulpi);
1233 }
Tuomas Tynkkynen0ee5b4a2013-07-25 21:38:05 +03001234
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301235 return 0;
1236}
1237
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301238static struct platform_driver tegra_usb_phy_driver = {
1239 .probe = tegra_usb_phy_probe,
Tuomas Tynkkynen0ee5b4a2013-07-25 21:38:05 +03001240 .remove = tegra_usb_phy_remove,
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301241 .driver = {
1242 .name = "tegra-phy",
Sachin Kamat787239202013-09-30 09:44:47 +05301243 .of_match_table = tegra_usb_phy_id_table,
Venu Byravarasu2d22b422013-05-16 19:43:02 +05301244 },
1245};
1246module_platform_driver(tegra_usb_phy_driver);
1247
Stephen Warren587376a2013-06-13 11:24:08 -06001248MODULE_DESCRIPTION("Tegra USB PHY driver");
1249MODULE_LICENSE("GPL v2");