diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-27 15:44:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-27 15:44:34 -0400 |
commit | 78c10e556ed904d5bfbd71e9cadd8ce8f25d6982 (patch) | |
tree | f73c802d60e81ff9e9fd2465eab096834d0227cd /drivers/phy | |
parent | d2c3ac7e7e39ec6d37e4114ae7444948561e59af (diff) | |
parent | 9ff897c4e8d5bd05ad7009f84a395596d4953858 (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/Kconfig | 7 | ||||
-rw-r--r-- | drivers/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/phy/phy-pistachio-usb.c | 206 |
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 | ||
270 | config 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 | |||
270 | config PHY_QCOM_APQ8064_SATA | 277 | config 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 | |||
44 | obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o | 44 | obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o |
45 | obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o | 45 | obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o |
46 | obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o | 46 | obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o |
47 | obj-$(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 | |||
37 | struct pistachio_usb_phy { | ||
38 | struct device *dev; | ||
39 | struct regmap *cr_top; | ||
40 | struct clk *phy_clk; | ||
41 | unsigned int refclk; | ||
42 | }; | ||
43 | |||
44 | static const unsigned long fsel_rate_map[] = { | ||
45 | 9600000, | ||
46 | 10000000, | ||
47 | 12000000, | ||
48 | 19200000, | ||
49 | 20000000, | ||
50 | 24000000, | ||
51 | 0, | ||
52 | 50000000, | ||
53 | }; | ||
54 | |||
55 | static 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 | |||
115 | disable_clk: | ||
116 | clk_disable_unprepare(p_phy->phy_clk); | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static 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 | |||
129 | static 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 | |||
135 | static 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 | |||
189 | static const struct of_device_id pistachio_usb_phy_of_match[] = { | ||
190 | { .compatible = "img,pistachio-usb-phy", }, | ||
191 | { }, | ||
192 | }; | ||
193 | MODULE_DEVICE_TABLE(of, pistachio_usb_phy_of_match); | ||
194 | |||
195 | static 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 | }; | ||
202 | module_platform_driver(pistachio_usb_phy_driver); | ||
203 | |||
204 | MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>"); | ||
205 | MODULE_DESCRIPTION("IMG Pistachio USB2.0 PHY driver"); | ||
206 | MODULE_LICENSE("GPL v2"); | ||