aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phy
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-06-27 15:44:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-06-27 15:44:34 -0400
commit78c10e556ed904d5bfbd71e9cadd8ce8f25d6982 (patch)
treef73c802d60e81ff9e9fd2465eab096834d0227cd /drivers/phy
parentd2c3ac7e7e39ec6d37e4114ae7444948561e59af (diff)
parent9ff897c4e8d5bd05ad7009f84a395596d4953858 (diff)
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle: - Improvements to the tlb_dump code - KVM fixes - Add support for appended DTB - Minor improvements to the R12000 support - Minor improvements to the R12000 support - Various platform improvments for BCM47xx - The usual pile of minor cleanups - A number of BPF fixes and improvments - Some improvments to the support for R3000 and DECstations - Some improvments to the ATH79 platform support - A major patchset for the JZ4740 SOC adding support for the CI20 platform - Add support for the Pistachio SOC - Minor BMIPS/BCM63xx platform support improvments. - Avoid "SYNC 0" as memory barrier when unlocking spinlocks - Add support for the XWR-1750 board. - Paul's __cpuinit/__cpuinitdata cleanups. - New Malta CPU board support large memory so enable ZONE_DMA32. * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (131 commits) MIPS: spinlock: Adjust arch_spin_lock back-off time MIPS: asmmacro: Ensure 64-bit FP registers are used with MSA MIPS: BCM47xx: Simplify handling SPROM revisions MIPS: Cobalt Don't use module_init in non-modular MTD registration. MIPS: BCM47xx: Move NVRAM driver to the drivers/firmware/ MIPS: use for_each_sg() MIPS: BCM47xx: Don't select BCMA_HOST_PCI MIPS: BCM47xx: Add helper variable for storing NVRAM length MIPS: IRQ/IP27: Move IRQ allocation API to platform code. MIPS: Replace smp_mb with release barrier function in unlocks. MIPS: i8259: DT support MIPS: Malta: Basic DT plumbing MIPS: include errno.h for ENODEV in mips-cm.h MIPS: Define GCR_GIC_STATUS register fields MIPS: BPF: Introduce BPF ASM helpers MIPS: BPF: Use BPF register names to describe the ABI MIPS: BPF: Move register definition to the BPF header MIPS: net: BPF: Replace RSIZE with SZREG MIPS: BPF: Free up some callee-saved registers MIPS: Xtalk: Update xwidget.h with known Xtalk device numbers ...
Diffstat (limited to 'drivers/phy')
-rw-r--r--drivers/phy/Kconfig7
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/phy-pistachio-usb.c206
3 files changed, 214 insertions, 0 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 487d057431cc..c0e6ede3e27d 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -267,6 +267,13 @@ config PHY_EXYNOS5_USBDRD
267 This driver provides PHY interface for USB 3.0 DRD controller 267 This driver provides PHY interface for USB 3.0 DRD controller
268 present on Exynos5 SoC series. 268 present on Exynos5 SoC series.
269 269
270config PHY_PISTACHIO_USB
271 tristate "IMG Pistachio USB2.0 PHY driver"
272 depends on MACH_PISTACHIO
273 select GENERIC_PHY
274 help
275 Enable this to support the USB2.0 PHY on the IMG Pistachio SoC.
276
270config PHY_QCOM_APQ8064_SATA 277config PHY_QCOM_APQ8064_SATA
271 tristate "Qualcomm APQ8064 SATA SerDes/PHY driver" 278 tristate "Qualcomm APQ8064 SATA SerDes/PHY driver"
272 depends on ARCH_QCOM 279 depends on ARCH_QCOM
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 42f58e95aff0..f344e1b2e825 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
44obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o 44obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
45obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o 45obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
46obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o 46obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o
47obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
diff --git a/drivers/phy/phy-pistachio-usb.c b/drivers/phy/phy-pistachio-usb.c
new file mode 100644
index 000000000000..c6db35e6bb63
--- /dev/null
+++ b/drivers/phy/phy-pistachio-usb.c
@@ -0,0 +1,206 @@
1/*
2 * IMG Pistachio USB PHY driver
3 *
4 * Copyright (C) 2015 Google, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 */
10
11#include <linux/clk.h>
12#include <linux/delay.h>
13#include <linux/io.h>
14#include <linux/kernel.h>
15#include <linux/mfd/syscon.h>
16#include <linux/module.h>
17#include <linux/of.h>
18#include <linux/phy/phy.h>
19#include <linux/platform_device.h>
20#include <linux/regmap.h>
21
22#include <dt-bindings/phy/phy-pistachio-usb.h>
23
24#define USB_PHY_CONTROL1 0x04
25#define USB_PHY_CONTROL1_FSEL_SHIFT 2
26#define USB_PHY_CONTROL1_FSEL_MASK 0x7
27
28#define USB_PHY_STRAP_CONTROL 0x10
29#define USB_PHY_STRAP_CONTROL_REFCLK_SHIFT 4
30#define USB_PHY_STRAP_CONTROL_REFCLK_MASK 0x3
31
32#define USB_PHY_STATUS 0x14
33#define USB_PHY_STATUS_RX_PHY_CLK BIT(9)
34#define USB_PHY_STATUS_RX_UTMI_CLK BIT(8)
35#define USB_PHY_STATUS_VBUS_FAULT BIT(7)
36
37struct pistachio_usb_phy {
38 struct device *dev;
39 struct regmap *cr_top;
40 struct clk *phy_clk;
41 unsigned int refclk;
42};
43
44static const unsigned long fsel_rate_map[] = {
45 9600000,
46 10000000,
47 12000000,
48 19200000,
49 20000000,
50 24000000,
51 0,
52 50000000,
53};
54
55static int pistachio_usb_phy_power_on(struct phy *phy)
56{
57 struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);
58 unsigned long timeout, rate;
59 unsigned int i;
60 int ret;
61
62 ret = clk_prepare_enable(p_phy->phy_clk);
63 if (ret < 0) {
64 dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret);
65 return ret;
66 }
67
68 regmap_update_bits(p_phy->cr_top, USB_PHY_STRAP_CONTROL,
69 USB_PHY_STRAP_CONTROL_REFCLK_MASK <<
70 USB_PHY_STRAP_CONTROL_REFCLK_SHIFT,
71 p_phy->refclk << USB_PHY_STRAP_CONTROL_REFCLK_SHIFT);
72
73 rate = clk_get_rate(p_phy->phy_clk);
74 if (p_phy->refclk == REFCLK_XO_CRYSTAL && rate != 12000000) {
75 dev_err(p_phy->dev, "Unsupported rate for XO crystal: %ld\n",
76 rate);
77 ret = -EINVAL;
78 goto disable_clk;
79 }
80
81 for (i = 0; i < ARRAY_SIZE(fsel_rate_map); i++) {
82 if (rate == fsel_rate_map[i])
83 break;
84 }
85 if (i == ARRAY_SIZE(fsel_rate_map)) {
86 dev_err(p_phy->dev, "Unsupported clock rate: %lu\n", rate);
87 ret = -EINVAL;
88 goto disable_clk;
89 }
90
91 regmap_update_bits(p_phy->cr_top, USB_PHY_CONTROL1,
92 USB_PHY_CONTROL1_FSEL_MASK <<
93 USB_PHY_CONTROL1_FSEL_SHIFT,
94 i << USB_PHY_CONTROL1_FSEL_SHIFT);
95
96 timeout = jiffies + msecs_to_jiffies(200);
97 while (time_before(jiffies, timeout)) {
98 unsigned int val;
99
100 regmap_read(p_phy->cr_top, USB_PHY_STATUS, &val);
101 if (val & USB_PHY_STATUS_VBUS_FAULT) {
102 dev_err(p_phy->dev, "VBUS fault detected\n");
103 ret = -EIO;
104 goto disable_clk;
105 }
106 if ((val & USB_PHY_STATUS_RX_PHY_CLK) &&
107 (val & USB_PHY_STATUS_RX_UTMI_CLK))
108 return 0;
109 usleep_range(1000, 1500);
110 }
111
112 dev_err(p_phy->dev, "Timed out waiting for PHY to power on\n");
113 ret = -ETIMEDOUT;
114
115disable_clk:
116 clk_disable_unprepare(p_phy->phy_clk);
117 return ret;
118}
119
120static int pistachio_usb_phy_power_off(struct phy *phy)
121{
122 struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);
123
124 clk_disable_unprepare(p_phy->phy_clk);
125
126 return 0;
127}
128
129static const struct phy_ops pistachio_usb_phy_ops = {
130 .power_on = pistachio_usb_phy_power_on,
131 .power_off = pistachio_usb_phy_power_off,
132 .owner = THIS_MODULE,
133};
134
135static int pistachio_usb_phy_probe(struct platform_device *pdev)
136{
137 struct pistachio_usb_phy *p_phy;
138 struct phy_provider *provider;
139 struct phy *phy;
140 int ret;
141
142 p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL);
143 if (!p_phy)
144 return -ENOMEM;
145 p_phy->dev = &pdev->dev;
146 platform_set_drvdata(pdev, p_phy);
147
148 p_phy->cr_top = syscon_regmap_lookup_by_phandle(p_phy->dev->of_node,
149 "img,cr-top");
150 if (IS_ERR(p_phy->cr_top)) {
151 dev_err(p_phy->dev, "Failed to get CR_TOP registers: %ld\n",
152 PTR_ERR(p_phy->cr_top));
153 return PTR_ERR(p_phy->cr_top);
154 }
155
156 p_phy->phy_clk = devm_clk_get(p_phy->dev, "usb_phy");
157 if (IS_ERR(p_phy->phy_clk)) {
158 dev_err(p_phy->dev, "Failed to get usb_phy clock: %ld\n",
159 PTR_ERR(p_phy->phy_clk));
160 return PTR_ERR(p_phy->phy_clk);
161 }
162
163 ret = of_property_read_u32(p_phy->dev->of_node, "img,refclk",
164 &p_phy->refclk);
165 if (ret < 0) {
166 dev_err(p_phy->dev, "No reference clock selector specified\n");
167 return ret;
168 }
169
170 phy = devm_phy_create(p_phy->dev, NULL, &pistachio_usb_phy_ops);
171 if (IS_ERR(phy)) {
172 dev_err(p_phy->dev, "Failed to create PHY: %ld\n",
173 PTR_ERR(phy));
174 return PTR_ERR(phy);
175 }
176 phy_set_drvdata(phy, p_phy);
177
178 provider = devm_of_phy_provider_register(p_phy->dev,
179 of_phy_simple_xlate);
180 if (IS_ERR(provider)) {
181 dev_err(p_phy->dev, "Failed to register PHY provider: %ld\n",
182 PTR_ERR(provider));
183 return PTR_ERR(provider);
184 }
185
186 return 0;
187}
188
189static const struct of_device_id pistachio_usb_phy_of_match[] = {
190 { .compatible = "img,pistachio-usb-phy", },
191 { },
192};
193MODULE_DEVICE_TABLE(of, pistachio_usb_phy_of_match);
194
195static struct platform_driver pistachio_usb_phy_driver = {
196 .probe = pistachio_usb_phy_probe,
197 .driver = {
198 .name = "pistachio-usb-phy",
199 .of_match_table = pistachio_usb_phy_of_match,
200 },
201};
202module_platform_driver(pistachio_usb_phy_driver);
203
204MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>");
205MODULE_DESCRIPTION("IMG Pistachio USB2.0 PHY driver");
206MODULE_LICENSE("GPL v2");