diff options
author | Olof Johansson <olof@lixom.net> | 2014-07-19 15:49:24 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2014-07-19 15:49:24 -0400 |
commit | 58cd070a8441507292604e17a505848add9b2760 (patch) | |
tree | 10e1f5decc8812b355d4fef69abddfc9107128d7 /drivers/pinctrl | |
parent | 15bebad68e9ed75ce14c93dbff8123633d9f7481 (diff) | |
parent | dc0a3938668706f3a63cde4ceb431e9189fb2a0a (diff) |
Merge tag 'tegra-for-3.17-xusb-padctl' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/dt
Merge "ARM: tegra: Add XUSB pad controller support" from Thierry Reding:
Adds device tree bindings and a driver for the XUSB pad controller found
on Tegra114 and later. This is a prerequisites for PCIe, SATA and XUSB
drivers which are all currently being reviewed or pending for merge.
This is a separate branch in case it needs to be pulled into the pinctrl
tree to resolve conflicts.
* tag 'tegra-for-3.17-xusb-padctl' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
pinctrl: Add NVIDIA Tegra XUSB pad controller support
of: Add NVIDIA Tegra XUSB pad controller binding
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r-- | drivers/pinctrl/Kconfig | 6 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-tegra-xusb.c | 973 |
3 files changed, 980 insertions, 0 deletions
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 0042ccb46b9a..0fa42be8df00 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
@@ -328,6 +328,12 @@ config PINCTRL_TEGRA124 | |||
328 | bool | 328 | bool |
329 | select PINCTRL_TEGRA | 329 | select PINCTRL_TEGRA |
330 | 330 | ||
331 | config PINCTRL_TEGRA_XUSB | ||
332 | def_bool y if ARCH_TEGRA | ||
333 | select GENERIC_PHY | ||
334 | select PINCONF | ||
335 | select PINMUX | ||
336 | |||
331 | config PINCTRL_TZ1090 | 337 | config PINCTRL_TZ1090 |
332 | bool "Toumaz Xenif TZ1090 pin control driver" | 338 | bool "Toumaz Xenif TZ1090 pin control driver" |
333 | depends on SOC_TZ1090 | 339 | depends on SOC_TZ1090 |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index c4b5d405b8f5..df8878839b44 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
@@ -55,6 +55,7 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o | |||
55 | obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o | 55 | obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o |
56 | obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o | 56 | obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o |
57 | obj-$(CONFIG_PINCTRL_TEGRA124) += pinctrl-tegra124.o | 57 | obj-$(CONFIG_PINCTRL_TEGRA124) += pinctrl-tegra124.o |
58 | obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o | ||
58 | obj-$(CONFIG_PINCTRL_TZ1090) += pinctrl-tz1090.o | 59 | obj-$(CONFIG_PINCTRL_TZ1090) += pinctrl-tz1090.o |
59 | obj-$(CONFIG_PINCTRL_TZ1090_PDC) += pinctrl-tz1090-pdc.o | 60 | obj-$(CONFIG_PINCTRL_TZ1090_PDC) += pinctrl-tz1090-pdc.o |
60 | obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o | 61 | obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o |
diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c new file mode 100644 index 000000000000..4a7daf577b49 --- /dev/null +++ b/drivers/pinctrl/pinctrl-tegra-xusb.c | |||
@@ -0,0 +1,973 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/phy/phy.h> | ||
19 | #include <linux/pinctrl/pinctrl.h> | ||
20 | #include <linux/pinctrl/pinmux.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/reset.h> | ||
23 | |||
24 | #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> | ||
25 | |||
26 | #include "core.h" | ||
27 | #include "pinctrl-utils.h" | ||
28 | |||
29 | #define XUSB_PADCTL_ELPG_PROGRAM 0x01c | ||
30 | #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26) | ||
31 | #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25) | ||
32 | #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24) | ||
33 | |||
34 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040 | ||
35 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19) | ||
36 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12) | ||
37 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1) | ||
38 | |||
39 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044 | ||
40 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6) | ||
41 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5) | ||
42 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4) | ||
43 | |||
44 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138 | ||
45 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27) | ||
46 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24) | ||
47 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3) | ||
48 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1) | ||
49 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0) | ||
50 | |||
51 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148 | ||
52 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1) | ||
53 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0) | ||
54 | |||
55 | struct tegra_xusb_padctl_function { | ||
56 | const char *name; | ||
57 | const char * const *groups; | ||
58 | unsigned int num_groups; | ||
59 | }; | ||
60 | |||
61 | struct tegra_xusb_padctl_group { | ||
62 | const unsigned int *funcs; | ||
63 | unsigned int num_funcs; | ||
64 | }; | ||
65 | |||
66 | struct tegra_xusb_padctl_soc { | ||
67 | const struct pinctrl_pin_desc *pins; | ||
68 | unsigned int num_pins; | ||
69 | |||
70 | const struct tegra_xusb_padctl_function *functions; | ||
71 | unsigned int num_functions; | ||
72 | |||
73 | const struct tegra_xusb_padctl_lane *lanes; | ||
74 | unsigned int num_lanes; | ||
75 | }; | ||
76 | |||
77 | struct tegra_xusb_padctl_lane { | ||
78 | const char *name; | ||
79 | |||
80 | unsigned int offset; | ||
81 | unsigned int shift; | ||
82 | unsigned int mask; | ||
83 | unsigned int iddq; | ||
84 | |||
85 | const unsigned int *funcs; | ||
86 | unsigned int num_funcs; | ||
87 | }; | ||
88 | |||
89 | struct tegra_xusb_padctl { | ||
90 | struct device *dev; | ||
91 | void __iomem *regs; | ||
92 | struct mutex lock; | ||
93 | struct reset_control *rst; | ||
94 | |||
95 | const struct tegra_xusb_padctl_soc *soc; | ||
96 | struct pinctrl_dev *pinctrl; | ||
97 | struct pinctrl_desc desc; | ||
98 | |||
99 | struct phy_provider *provider; | ||
100 | struct phy *phys[2]; | ||
101 | |||
102 | unsigned int enable; | ||
103 | }; | ||
104 | |||
105 | static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value, | ||
106 | unsigned long offset) | ||
107 | { | ||
108 | writel(value, padctl->regs + offset); | ||
109 | } | ||
110 | |||
111 | static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl, | ||
112 | unsigned long offset) | ||
113 | { | ||
114 | return readl(padctl->regs + offset); | ||
115 | } | ||
116 | |||
117 | static int tegra_xusb_padctl_get_groups_count(struct pinctrl_dev *pinctrl) | ||
118 | { | ||
119 | struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); | ||
120 | |||
121 | return padctl->soc->num_pins; | ||
122 | } | ||
123 | |||
124 | static const char *tegra_xusb_padctl_get_group_name(struct pinctrl_dev *pinctrl, | ||
125 | unsigned int group) | ||
126 | { | ||
127 | struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); | ||
128 | |||
129 | return padctl->soc->pins[group].name; | ||
130 | } | ||
131 | |||
132 | enum tegra_xusb_padctl_param { | ||
133 | TEGRA_XUSB_PADCTL_IDDQ, | ||
134 | }; | ||
135 | |||
136 | static const struct tegra_xusb_padctl_property { | ||
137 | const char *name; | ||
138 | enum tegra_xusb_padctl_param param; | ||
139 | } properties[] = { | ||
140 | { "nvidia,iddq", TEGRA_XUSB_PADCTL_IDDQ }, | ||
141 | }; | ||
142 | |||
143 | #define TEGRA_XUSB_PADCTL_PACK(param, value) ((param) << 16 | (value)) | ||
144 | #define TEGRA_XUSB_PADCTL_UNPACK_PARAM(config) ((config) >> 16) | ||
145 | #define TEGRA_XUSB_PADCTL_UNPACK_VALUE(config) ((config) & 0xffff) | ||
146 | |||
147 | static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl, | ||
148 | struct device_node *np, | ||
149 | struct pinctrl_map **maps, | ||
150 | unsigned int *reserved_maps, | ||
151 | unsigned int *num_maps) | ||
152 | { | ||
153 | unsigned int i, reserve = 0, num_configs = 0; | ||
154 | unsigned long config, *configs = NULL; | ||
155 | const char *function, *group; | ||
156 | struct property *prop; | ||
157 | int err = 0; | ||
158 | u32 value; | ||
159 | |||
160 | err = of_property_read_string(np, "nvidia,function", &function); | ||
161 | if (err < 0) { | ||
162 | if (err != -EINVAL) | ||
163 | return err; | ||
164 | |||
165 | function = NULL; | ||
166 | } | ||
167 | |||
168 | for (i = 0; i < ARRAY_SIZE(properties); i++) { | ||
169 | err = of_property_read_u32(np, properties[i].name, &value); | ||
170 | if (err < 0) { | ||
171 | if (err == -EINVAL) | ||
172 | continue; | ||
173 | |||
174 | return err; | ||
175 | } | ||
176 | |||
177 | config = TEGRA_XUSB_PADCTL_PACK(properties[i].param, value); | ||
178 | |||
179 | err = pinctrl_utils_add_config(padctl->pinctrl, &configs, | ||
180 | &num_configs, config); | ||
181 | if (err < 0) | ||
182 | return err; | ||
183 | } | ||
184 | |||
185 | if (function) | ||
186 | reserve++; | ||
187 | |||
188 | if (num_configs) | ||
189 | reserve++; | ||
190 | |||
191 | err = of_property_count_strings(np, "nvidia,lanes"); | ||
192 | if (err < 0) | ||
193 | return err; | ||
194 | |||
195 | reserve *= err; | ||
196 | |||
197 | err = pinctrl_utils_reserve_map(padctl->pinctrl, maps, reserved_maps, | ||
198 | num_maps, reserve); | ||
199 | if (err < 0) | ||
200 | return err; | ||
201 | |||
202 | of_property_for_each_string(np, "nvidia,lanes", prop, group) { | ||
203 | if (function) { | ||
204 | err = pinctrl_utils_add_map_mux(padctl->pinctrl, maps, | ||
205 | reserved_maps, num_maps, group, | ||
206 | function); | ||
207 | if (err < 0) | ||
208 | return err; | ||
209 | } | ||
210 | |||
211 | if (num_configs) { | ||
212 | err = pinctrl_utils_add_map_configs(padctl->pinctrl, | ||
213 | maps, reserved_maps, num_maps, group, | ||
214 | configs, num_configs, | ||
215 | PIN_MAP_TYPE_CONFIGS_GROUP); | ||
216 | if (err < 0) | ||
217 | return err; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int tegra_xusb_padctl_dt_node_to_map(struct pinctrl_dev *pinctrl, | ||
225 | struct device_node *parent, | ||
226 | struct pinctrl_map **maps, | ||
227 | unsigned int *num_maps) | ||
228 | { | ||
229 | struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); | ||
230 | unsigned int reserved_maps = 0; | ||
231 | struct device_node *np; | ||
232 | int err; | ||
233 | |||
234 | *num_maps = 0; | ||
235 | *maps = NULL; | ||
236 | |||
237 | for_each_child_of_node(parent, np) { | ||
238 | err = tegra_xusb_padctl_parse_subnode(padctl, np, maps, | ||
239 | &reserved_maps, | ||
240 | num_maps); | ||
241 | if (err < 0) | ||
242 | return err; | ||
243 | } | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static const struct pinctrl_ops tegra_xusb_padctl_pinctrl_ops = { | ||
249 | .get_groups_count = tegra_xusb_padctl_get_groups_count, | ||
250 | .get_group_name = tegra_xusb_padctl_get_group_name, | ||
251 | .dt_node_to_map = tegra_xusb_padctl_dt_node_to_map, | ||
252 | .dt_free_map = pinctrl_utils_dt_free_map, | ||
253 | }; | ||
254 | |||
255 | static int tegra_xusb_padctl_get_functions_count(struct pinctrl_dev *pinctrl) | ||
256 | { | ||
257 | struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); | ||
258 | |||
259 | return padctl->soc->num_functions; | ||
260 | } | ||
261 | |||
262 | static const char * | ||
263 | tegra_xusb_padctl_get_function_name(struct pinctrl_dev *pinctrl, | ||
264 | unsigned int function) | ||
265 | { | ||
266 | struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); | ||
267 | |||
268 | return padctl->soc->functions[function].name; | ||
269 | } | ||
270 | |||
271 | static int tegra_xusb_padctl_get_function_groups(struct pinctrl_dev *pinctrl, | ||
272 | unsigned int function, | ||
273 | const char * const **groups, | ||
274 | unsigned * const num_groups) | ||
275 | { | ||
276 | struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); | ||
277 | |||
278 | *num_groups = padctl->soc->functions[function].num_groups; | ||
279 | *groups = padctl->soc->functions[function].groups; | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int tegra_xusb_padctl_pinmux_enable(struct pinctrl_dev *pinctrl, | ||
285 | unsigned int function, | ||
286 | unsigned int group) | ||
287 | { | ||
288 | struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); | ||
289 | const struct tegra_xusb_padctl_lane *lane; | ||
290 | unsigned int i; | ||
291 | u32 value; | ||
292 | |||
293 | lane = &padctl->soc->lanes[group]; | ||
294 | |||
295 | for (i = 0; i < lane->num_funcs; i++) | ||
296 | if (lane->funcs[i] == function) | ||
297 | break; | ||
298 | |||
299 | if (i >= lane->num_funcs) | ||
300 | return -EINVAL; | ||
301 | |||
302 | value = padctl_readl(padctl, lane->offset); | ||
303 | value &= ~(lane->mask << lane->shift); | ||
304 | value |= i << lane->shift; | ||
305 | padctl_writel(padctl, value, lane->offset); | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static const struct pinmux_ops tegra_xusb_padctl_pinmux_ops = { | ||
311 | .get_functions_count = tegra_xusb_padctl_get_functions_count, | ||
312 | .get_function_name = tegra_xusb_padctl_get_function_name, | ||
313 | .get_function_groups = tegra_xusb_padctl_get_function_groups, | ||
314 | .enable = tegra_xusb_padctl_pinmux_enable, | ||
315 | }; | ||
316 | |||
317 | static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl, | ||
318 | unsigned int group, | ||
319 | unsigned long *config) | ||
320 | { | ||
321 | struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); | ||
322 | const struct tegra_xusb_padctl_lane *lane; | ||
323 | enum tegra_xusb_padctl_param param; | ||
324 | u32 value; | ||
325 | |||
326 | param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(*config); | ||
327 | lane = &padctl->soc->lanes[group]; | ||
328 | |||
329 | switch (param) { | ||
330 | case TEGRA_XUSB_PADCTL_IDDQ: | ||
331 | /* lanes with iddq == 0 don't support this parameter */ | ||
332 | if (lane->iddq == 0) | ||
333 | return -EINVAL; | ||
334 | |||
335 | value = padctl_readl(padctl, lane->offset); | ||
336 | |||
337 | if (value & BIT(lane->iddq)) | ||
338 | value = 0; | ||
339 | else | ||
340 | value = 1; | ||
341 | |||
342 | *config = TEGRA_XUSB_PADCTL_PACK(param, value); | ||
343 | break; | ||
344 | |||
345 | default: | ||
346 | dev_err(padctl->dev, "invalid configuration parameter: %04x\n", | ||
347 | param); | ||
348 | return -ENOTSUPP; | ||
349 | } | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl, | ||
355 | unsigned int group, | ||
356 | unsigned long *configs, | ||
357 | unsigned int num_configs) | ||
358 | { | ||
359 | struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); | ||
360 | const struct tegra_xusb_padctl_lane *lane; | ||
361 | enum tegra_xusb_padctl_param param; | ||
362 | unsigned long value; | ||
363 | unsigned int i; | ||
364 | u32 regval; | ||
365 | |||
366 | lane = &padctl->soc->lanes[group]; | ||
367 | |||
368 | for (i = 0; i < num_configs; i++) { | ||
369 | param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(configs[i]); | ||
370 | value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(configs[i]); | ||
371 | |||
372 | switch (param) { | ||
373 | case TEGRA_XUSB_PADCTL_IDDQ: | ||
374 | /* lanes with iddq == 0 don't support this parameter */ | ||
375 | if (lane->iddq == 0) | ||
376 | return -EINVAL; | ||
377 | |||
378 | regval = padctl_readl(padctl, lane->offset); | ||
379 | |||
380 | if (value) | ||
381 | regval &= ~BIT(lane->iddq); | ||
382 | else | ||
383 | regval |= BIT(lane->iddq); | ||
384 | |||
385 | padctl_writel(padctl, regval, lane->offset); | ||
386 | break; | ||
387 | |||
388 | default: | ||
389 | dev_err(padctl->dev, | ||
390 | "invalid configuration parameter: %04x\n", | ||
391 | param); | ||
392 | return -ENOTSUPP; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | #ifdef CONFIG_DEBUG_FS | ||
400 | static const char *strip_prefix(const char *s) | ||
401 | { | ||
402 | const char *comma = strchr(s, ','); | ||
403 | if (!comma) | ||
404 | return s; | ||
405 | |||
406 | return comma + 1; | ||
407 | } | ||
408 | |||
409 | static void | ||
410 | tegra_xusb_padctl_pinconf_group_dbg_show(struct pinctrl_dev *pinctrl, | ||
411 | struct seq_file *s, | ||
412 | unsigned int group) | ||
413 | { | ||
414 | unsigned int i; | ||
415 | |||
416 | for (i = 0; i < ARRAY_SIZE(properties); i++) { | ||
417 | unsigned long config, value; | ||
418 | int err; | ||
419 | |||
420 | config = TEGRA_XUSB_PADCTL_PACK(properties[i].param, 0); | ||
421 | |||
422 | err = tegra_xusb_padctl_pinconf_group_get(pinctrl, group, | ||
423 | &config); | ||
424 | if (err < 0) | ||
425 | continue; | ||
426 | |||
427 | value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(config); | ||
428 | |||
429 | seq_printf(s, "\n\t%s=%lu\n", strip_prefix(properties[i].name), | ||
430 | value); | ||
431 | } | ||
432 | } | ||
433 | |||
434 | static void | ||
435 | tegra_xusb_padctl_pinconf_config_dbg_show(struct pinctrl_dev *pinctrl, | ||
436 | struct seq_file *s, | ||
437 | unsigned long config) | ||
438 | { | ||
439 | enum tegra_xusb_padctl_param param; | ||
440 | const char *name = "unknown"; | ||
441 | unsigned long value; | ||
442 | unsigned int i; | ||
443 | |||
444 | param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(config); | ||
445 | value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(config); | ||
446 | |||
447 | for (i = 0; i < ARRAY_SIZE(properties); i++) { | ||
448 | if (properties[i].param == param) { | ||
449 | name = properties[i].name; | ||
450 | break; | ||
451 | } | ||
452 | } | ||
453 | |||
454 | seq_printf(s, "%s=%lu", strip_prefix(name), value); | ||
455 | } | ||
456 | #endif | ||
457 | |||
458 | static const struct pinconf_ops tegra_xusb_padctl_pinconf_ops = { | ||
459 | .pin_config_group_get = tegra_xusb_padctl_pinconf_group_get, | ||
460 | .pin_config_group_set = tegra_xusb_padctl_pinconf_group_set, | ||
461 | #ifdef CONFIG_DEBUG_FS | ||
462 | .pin_config_group_dbg_show = tegra_xusb_padctl_pinconf_group_dbg_show, | ||
463 | .pin_config_config_dbg_show = tegra_xusb_padctl_pinconf_config_dbg_show, | ||
464 | #endif | ||
465 | }; | ||
466 | |||
467 | static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl) | ||
468 | { | ||
469 | u32 value; | ||
470 | |||
471 | mutex_lock(&padctl->lock); | ||
472 | |||
473 | if (padctl->enable++ > 0) | ||
474 | goto out; | ||
475 | |||
476 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
477 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; | ||
478 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
479 | |||
480 | usleep_range(100, 200); | ||
481 | |||
482 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
483 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; | ||
484 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
485 | |||
486 | usleep_range(100, 200); | ||
487 | |||
488 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
489 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; | ||
490 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
491 | |||
492 | out: | ||
493 | mutex_unlock(&padctl->lock); | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl) | ||
498 | { | ||
499 | u32 value; | ||
500 | |||
501 | mutex_lock(&padctl->lock); | ||
502 | |||
503 | if (WARN_ON(padctl->enable == 0)) | ||
504 | goto out; | ||
505 | |||
506 | if (--padctl->enable > 0) | ||
507 | goto out; | ||
508 | |||
509 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
510 | value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; | ||
511 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
512 | |||
513 | usleep_range(100, 200); | ||
514 | |||
515 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
516 | value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; | ||
517 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
518 | |||
519 | usleep_range(100, 200); | ||
520 | |||
521 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
522 | value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; | ||
523 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
524 | |||
525 | out: | ||
526 | mutex_unlock(&padctl->lock); | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | static int tegra_xusb_phy_init(struct phy *phy) | ||
531 | { | ||
532 | struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); | ||
533 | |||
534 | return tegra_xusb_padctl_enable(padctl); | ||
535 | } | ||
536 | |||
537 | static int tegra_xusb_phy_exit(struct phy *phy) | ||
538 | { | ||
539 | struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); | ||
540 | |||
541 | return tegra_xusb_padctl_disable(padctl); | ||
542 | } | ||
543 | |||
544 | static int pcie_phy_power_on(struct phy *phy) | ||
545 | { | ||
546 | struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); | ||
547 | unsigned long timeout; | ||
548 | int err = -ETIMEDOUT; | ||
549 | u32 value; | ||
550 | |||
551 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
552 | value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK; | ||
553 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
554 | |||
555 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); | ||
556 | value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN | | ||
557 | XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN | | ||
558 | XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL; | ||
559 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); | ||
560 | |||
561 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
562 | value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST; | ||
563 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
564 | |||
565 | timeout = jiffies + msecs_to_jiffies(50); | ||
566 | |||
567 | while (time_before(jiffies, timeout)) { | ||
568 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
569 | if (value & XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) { | ||
570 | err = 0; | ||
571 | break; | ||
572 | } | ||
573 | |||
574 | usleep_range(100, 200); | ||
575 | } | ||
576 | |||
577 | return err; | ||
578 | } | ||
579 | |||
580 | static int pcie_phy_power_off(struct phy *phy) | ||
581 | { | ||
582 | struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); | ||
583 | u32 value; | ||
584 | |||
585 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
586 | value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST; | ||
587 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static const struct phy_ops pcie_phy_ops = { | ||
593 | .init = tegra_xusb_phy_init, | ||
594 | .exit = tegra_xusb_phy_exit, | ||
595 | .power_on = pcie_phy_power_on, | ||
596 | .power_off = pcie_phy_power_off, | ||
597 | .owner = THIS_MODULE, | ||
598 | }; | ||
599 | |||
600 | static int sata_phy_power_on(struct phy *phy) | ||
601 | { | ||
602 | struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); | ||
603 | unsigned long timeout; | ||
604 | int err = -ETIMEDOUT; | ||
605 | u32 value; | ||
606 | |||
607 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
608 | value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; | ||
609 | value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ; | ||
610 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
611 | |||
612 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
613 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; | ||
614 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ; | ||
615 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
616 | |||
617 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
618 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE; | ||
619 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
620 | |||
621 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
622 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST; | ||
623 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
624 | |||
625 | timeout = jiffies + msecs_to_jiffies(50); | ||
626 | |||
627 | while (time_before(jiffies, timeout)) { | ||
628 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
629 | if (value & XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) { | ||
630 | err = 0; | ||
631 | break; | ||
632 | } | ||
633 | |||
634 | usleep_range(100, 200); | ||
635 | } | ||
636 | |||
637 | return err; | ||
638 | } | ||
639 | |||
640 | static int sata_phy_power_off(struct phy *phy) | ||
641 | { | ||
642 | struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); | ||
643 | u32 value; | ||
644 | |||
645 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
646 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST; | ||
647 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
648 | |||
649 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
650 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE; | ||
651 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
652 | |||
653 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
654 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; | ||
655 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ; | ||
656 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
657 | |||
658 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
659 | value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; | ||
660 | value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ; | ||
661 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | static const struct phy_ops sata_phy_ops = { | ||
667 | .init = tegra_xusb_phy_init, | ||
668 | .exit = tegra_xusb_phy_exit, | ||
669 | .power_on = sata_phy_power_on, | ||
670 | .power_off = sata_phy_power_off, | ||
671 | .owner = THIS_MODULE, | ||
672 | }; | ||
673 | |||
674 | static struct phy *tegra_xusb_padctl_xlate(struct device *dev, | ||
675 | struct of_phandle_args *args) | ||
676 | { | ||
677 | struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev); | ||
678 | unsigned int index = args->args[0]; | ||
679 | |||
680 | if (args->args_count <= 0) | ||
681 | return ERR_PTR(-EINVAL); | ||
682 | |||
683 | if (index > ARRAY_SIZE(padctl->phys)) | ||
684 | return ERR_PTR(-EINVAL); | ||
685 | |||
686 | return padctl->phys[index]; | ||
687 | } | ||
688 | |||
689 | #define PIN_OTG_0 0 | ||
690 | #define PIN_OTG_1 1 | ||
691 | #define PIN_OTG_2 2 | ||
692 | #define PIN_ULPI_0 3 | ||
693 | #define PIN_HSIC_0 4 | ||
694 | #define PIN_HSIC_1 5 | ||
695 | #define PIN_PCIE_0 6 | ||
696 | #define PIN_PCIE_1 7 | ||
697 | #define PIN_PCIE_2 8 | ||
698 | #define PIN_PCIE_3 9 | ||
699 | #define PIN_PCIE_4 10 | ||
700 | #define PIN_SATA_0 11 | ||
701 | |||
702 | static const struct pinctrl_pin_desc tegra124_pins[] = { | ||
703 | PINCTRL_PIN(PIN_OTG_0, "otg-0"), | ||
704 | PINCTRL_PIN(PIN_OTG_1, "otg-1"), | ||
705 | PINCTRL_PIN(PIN_OTG_2, "otg-2"), | ||
706 | PINCTRL_PIN(PIN_ULPI_0, "ulpi-0"), | ||
707 | PINCTRL_PIN(PIN_HSIC_0, "hsic-0"), | ||
708 | PINCTRL_PIN(PIN_HSIC_1, "hsic-1"), | ||
709 | PINCTRL_PIN(PIN_PCIE_0, "pcie-0"), | ||
710 | PINCTRL_PIN(PIN_PCIE_1, "pcie-1"), | ||
711 | PINCTRL_PIN(PIN_PCIE_2, "pcie-2"), | ||
712 | PINCTRL_PIN(PIN_PCIE_3, "pcie-3"), | ||
713 | PINCTRL_PIN(PIN_PCIE_4, "pcie-4"), | ||
714 | PINCTRL_PIN(PIN_SATA_0, "sata-0"), | ||
715 | }; | ||
716 | |||
717 | static const char * const tegra124_snps_groups[] = { | ||
718 | "otg-0", | ||
719 | "otg-1", | ||
720 | "otg-2", | ||
721 | "ulpi-0", | ||
722 | "hsic-0", | ||
723 | "hsic-1", | ||
724 | }; | ||
725 | |||
726 | static const char * const tegra124_xusb_groups[] = { | ||
727 | "otg-0", | ||
728 | "otg-1", | ||
729 | "otg-2", | ||
730 | "ulpi-0", | ||
731 | "hsic-0", | ||
732 | "hsic-1", | ||
733 | }; | ||
734 | |||
735 | static const char * const tegra124_uart_groups[] = { | ||
736 | "otg-0", | ||
737 | "otg-1", | ||
738 | "otg-2", | ||
739 | }; | ||
740 | |||
741 | static const char * const tegra124_pcie_groups[] = { | ||
742 | "pcie-0", | ||
743 | "pcie-1", | ||
744 | "pcie-2", | ||
745 | "pcie-3", | ||
746 | "pcie-4", | ||
747 | "sata-0", | ||
748 | }; | ||
749 | |||
750 | static const char * const tegra124_usb3_groups[] = { | ||
751 | "pcie-0", | ||
752 | "pcie-1", | ||
753 | "pcie-2", | ||
754 | "pcie-3", | ||
755 | "pcie-4", | ||
756 | "sata-0", | ||
757 | }; | ||
758 | |||
759 | static const char * const tegra124_sata_groups[] = { | ||
760 | "pcie-0", | ||
761 | "pcie-1", | ||
762 | "pcie-2", | ||
763 | "pcie-3", | ||
764 | "pcie-4", | ||
765 | "sata-0", | ||
766 | }; | ||
767 | |||
768 | static const char * const tegra124_rsvd_groups[] = { | ||
769 | "otg-0", | ||
770 | "otg-1", | ||
771 | "otg-2", | ||
772 | "pcie-0", | ||
773 | "pcie-1", | ||
774 | "pcie-2", | ||
775 | "pcie-3", | ||
776 | "pcie-4", | ||
777 | "sata-0", | ||
778 | }; | ||
779 | |||
780 | #define TEGRA124_FUNCTION(_name) \ | ||
781 | { \ | ||
782 | .name = #_name, \ | ||
783 | .num_groups = ARRAY_SIZE(tegra124_##_name##_groups), \ | ||
784 | .groups = tegra124_##_name##_groups, \ | ||
785 | } | ||
786 | |||
787 | static struct tegra_xusb_padctl_function tegra124_functions[] = { | ||
788 | TEGRA124_FUNCTION(snps), | ||
789 | TEGRA124_FUNCTION(xusb), | ||
790 | TEGRA124_FUNCTION(uart), | ||
791 | TEGRA124_FUNCTION(pcie), | ||
792 | TEGRA124_FUNCTION(usb3), | ||
793 | TEGRA124_FUNCTION(sata), | ||
794 | TEGRA124_FUNCTION(rsvd), | ||
795 | }; | ||
796 | |||
797 | enum tegra124_function { | ||
798 | TEGRA124_FUNC_SNPS, | ||
799 | TEGRA124_FUNC_XUSB, | ||
800 | TEGRA124_FUNC_UART, | ||
801 | TEGRA124_FUNC_PCIE, | ||
802 | TEGRA124_FUNC_USB3, | ||
803 | TEGRA124_FUNC_SATA, | ||
804 | TEGRA124_FUNC_RSVD, | ||
805 | }; | ||
806 | |||
807 | static const unsigned int tegra124_otg_functions[] = { | ||
808 | TEGRA124_FUNC_SNPS, | ||
809 | TEGRA124_FUNC_XUSB, | ||
810 | TEGRA124_FUNC_UART, | ||
811 | TEGRA124_FUNC_RSVD, | ||
812 | }; | ||
813 | |||
814 | static const unsigned int tegra124_usb_functions[] = { | ||
815 | TEGRA124_FUNC_SNPS, | ||
816 | TEGRA124_FUNC_XUSB, | ||
817 | }; | ||
818 | |||
819 | static const unsigned int tegra124_pci_functions[] = { | ||
820 | TEGRA124_FUNC_PCIE, | ||
821 | TEGRA124_FUNC_USB3, | ||
822 | TEGRA124_FUNC_SATA, | ||
823 | TEGRA124_FUNC_RSVD, | ||
824 | }; | ||
825 | |||
826 | #define TEGRA124_LANE(_name, _offset, _shift, _mask, _iddq, _funcs) \ | ||
827 | { \ | ||
828 | .name = _name, \ | ||
829 | .offset = _offset, \ | ||
830 | .shift = _shift, \ | ||
831 | .mask = _mask, \ | ||
832 | .iddq = _iddq, \ | ||
833 | .num_funcs = ARRAY_SIZE(tegra124_##_funcs##_functions), \ | ||
834 | .funcs = tegra124_##_funcs##_functions, \ | ||
835 | } | ||
836 | |||
837 | static const struct tegra_xusb_padctl_lane tegra124_lanes[] = { | ||
838 | TEGRA124_LANE("otg-0", 0x004, 0, 0x3, 0, otg), | ||
839 | TEGRA124_LANE("otg-1", 0x004, 2, 0x3, 0, otg), | ||
840 | TEGRA124_LANE("otg-2", 0x004, 4, 0x3, 0, otg), | ||
841 | TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, 0, usb), | ||
842 | TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, 0, usb), | ||
843 | TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, 0, usb), | ||
844 | TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, 1, pci), | ||
845 | TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, 2, pci), | ||
846 | TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, 3, pci), | ||
847 | TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, 4, pci), | ||
848 | TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, 5, pci), | ||
849 | TEGRA124_LANE("sata-0", 0x134, 26, 0x3, 6, pci), | ||
850 | }; | ||
851 | |||
852 | static const struct tegra_xusb_padctl_soc tegra124_soc = { | ||
853 | .num_pins = ARRAY_SIZE(tegra124_pins), | ||
854 | .pins = tegra124_pins, | ||
855 | .num_functions = ARRAY_SIZE(tegra124_functions), | ||
856 | .functions = tegra124_functions, | ||
857 | .num_lanes = ARRAY_SIZE(tegra124_lanes), | ||
858 | .lanes = tegra124_lanes, | ||
859 | }; | ||
860 | |||
861 | static const struct of_device_id tegra_xusb_padctl_of_match[] = { | ||
862 | { .compatible = "nvidia,tegra124-xusb-padctl", .data = &tegra124_soc }, | ||
863 | { } | ||
864 | }; | ||
865 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); | ||
866 | |||
867 | static int tegra_xusb_padctl_probe(struct platform_device *pdev) | ||
868 | { | ||
869 | struct tegra_xusb_padctl *padctl; | ||
870 | const struct of_device_id *match; | ||
871 | struct resource *res; | ||
872 | struct phy *phy; | ||
873 | int err; | ||
874 | |||
875 | padctl = devm_kzalloc(&pdev->dev, sizeof(*padctl), GFP_KERNEL); | ||
876 | if (!padctl) | ||
877 | return -ENOMEM; | ||
878 | |||
879 | platform_set_drvdata(pdev, padctl); | ||
880 | mutex_init(&padctl->lock); | ||
881 | padctl->dev = &pdev->dev; | ||
882 | |||
883 | match = of_match_node(tegra_xusb_padctl_of_match, pdev->dev.of_node); | ||
884 | padctl->soc = match->data; | ||
885 | |||
886 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
887 | padctl->regs = devm_ioremap_resource(&pdev->dev, res); | ||
888 | if (IS_ERR(padctl->regs)) | ||
889 | return PTR_ERR(padctl->regs); | ||
890 | |||
891 | padctl->rst = devm_reset_control_get(&pdev->dev, NULL); | ||
892 | if (IS_ERR(padctl->rst)) | ||
893 | return PTR_ERR(padctl->rst); | ||
894 | |||
895 | err = reset_control_deassert(padctl->rst); | ||
896 | if (err < 0) | ||
897 | return err; | ||
898 | |||
899 | memset(&padctl->desc, 0, sizeof(padctl->desc)); | ||
900 | padctl->desc.name = dev_name(padctl->dev); | ||
901 | padctl->desc.pctlops = &tegra_xusb_padctl_pinctrl_ops; | ||
902 | padctl->desc.pmxops = &tegra_xusb_padctl_pinmux_ops; | ||
903 | padctl->desc.confops = &tegra_xusb_padctl_pinconf_ops; | ||
904 | padctl->desc.owner = THIS_MODULE; | ||
905 | |||
906 | padctl->pinctrl = pinctrl_register(&padctl->desc, &pdev->dev, padctl); | ||
907 | if (!padctl->pinctrl) { | ||
908 | dev_err(&pdev->dev, "failed to register pincontrol\n"); | ||
909 | err = -ENODEV; | ||
910 | goto reset; | ||
911 | } | ||
912 | |||
913 | phy = devm_phy_create(&pdev->dev, &pcie_phy_ops, NULL); | ||
914 | if (IS_ERR(phy)) { | ||
915 | err = PTR_ERR(phy); | ||
916 | goto unregister; | ||
917 | } | ||
918 | |||
919 | padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy; | ||
920 | phy_set_drvdata(phy, padctl); | ||
921 | |||
922 | phy = devm_phy_create(&pdev->dev, &sata_phy_ops, NULL); | ||
923 | if (IS_ERR(phy)) { | ||
924 | err = PTR_ERR(phy); | ||
925 | goto unregister; | ||
926 | } | ||
927 | |||
928 | padctl->phys[TEGRA_XUSB_PADCTL_SATA] = phy; | ||
929 | phy_set_drvdata(phy, padctl); | ||
930 | |||
931 | padctl->provider = devm_of_phy_provider_register(&pdev->dev, | ||
932 | tegra_xusb_padctl_xlate); | ||
933 | if (err < 0) { | ||
934 | dev_err(&pdev->dev, "failed to register PHYs: %d\n", err); | ||
935 | goto unregister; | ||
936 | } | ||
937 | |||
938 | return 0; | ||
939 | |||
940 | unregister: | ||
941 | pinctrl_unregister(padctl->pinctrl); | ||
942 | reset: | ||
943 | reset_control_assert(padctl->rst); | ||
944 | return err; | ||
945 | } | ||
946 | |||
947 | static int tegra_xusb_padctl_remove(struct platform_device *pdev) | ||
948 | { | ||
949 | struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev); | ||
950 | int err; | ||
951 | |||
952 | pinctrl_unregister(padctl->pinctrl); | ||
953 | |||
954 | err = reset_control_assert(padctl->rst); | ||
955 | if (err < 0) | ||
956 | dev_err(&pdev->dev, "failed to assert reset: %d\n", err); | ||
957 | |||
958 | return err; | ||
959 | } | ||
960 | |||
961 | static struct platform_driver tegra_xusb_padctl_driver = { | ||
962 | .driver = { | ||
963 | .name = "tegra-xusb-padctl", | ||
964 | .of_match_table = tegra_xusb_padctl_of_match, | ||
965 | }, | ||
966 | .probe = tegra_xusb_padctl_probe, | ||
967 | .remove = tegra_xusb_padctl_remove, | ||
968 | }; | ||
969 | module_platform_driver(tegra_xusb_padctl_driver); | ||
970 | |||
971 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); | ||
972 | MODULE_DESCRIPTION("Tegra 124 XUSB Pad Control driver"); | ||
973 | MODULE_LICENSE("GPL v2"); | ||