diff options
Diffstat (limited to 'drivers/phy/tegra/xusb.c')
-rw-r--r-- | drivers/phy/tegra/xusb.c | 67 |
1 files changed, 65 insertions, 2 deletions
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index 5b3b8863363e..0417213ed68b 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. | 2 | * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 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, | 5 | * under the terms and conditions of the GNU General Public License, |
@@ -68,6 +68,12 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = { | |||
68 | .data = &tegra210_xusb_padctl_soc, | 68 | .data = &tegra210_xusb_padctl_soc, |
69 | }, | 69 | }, |
70 | #endif | 70 | #endif |
71 | #if defined(CONFIG_ARCH_TEGRA_186_SOC) | ||
72 | { | ||
73 | .compatible = "nvidia,tegra186-xusb-padctl", | ||
74 | .data = &tegra186_xusb_padctl_soc, | ||
75 | }, | ||
76 | #endif | ||
71 | { } | 77 | { } |
72 | }; | 78 | }; |
73 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); | 79 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); |
@@ -313,6 +319,10 @@ static void tegra_xusb_lane_program(struct tegra_xusb_lane *lane) | |||
313 | const struct tegra_xusb_lane_soc *soc = lane->soc; | 319 | const struct tegra_xusb_lane_soc *soc = lane->soc; |
314 | u32 value; | 320 | u32 value; |
315 | 321 | ||
322 | /* skip single function lanes */ | ||
323 | if (soc->num_funcs < 2) | ||
324 | return; | ||
325 | |||
316 | /* choose function */ | 326 | /* choose function */ |
317 | value = padctl_readl(padctl, soc->offset); | 327 | value = padctl_readl(padctl, soc->offset); |
318 | value &= ~(soc->mask << soc->shift); | 328 | value &= ~(soc->mask << soc->shift); |
@@ -542,13 +552,34 @@ static void tegra_xusb_port_unregister(struct tegra_xusb_port *port) | |||
542 | device_unregister(&port->dev); | 552 | device_unregister(&port->dev); |
543 | } | 553 | } |
544 | 554 | ||
555 | static const char *const modes[] = { | ||
556 | [USB_DR_MODE_UNKNOWN] = "", | ||
557 | [USB_DR_MODE_HOST] = "host", | ||
558 | [USB_DR_MODE_PERIPHERAL] = "peripheral", | ||
559 | [USB_DR_MODE_OTG] = "otg", | ||
560 | }; | ||
561 | |||
545 | static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2) | 562 | static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2) |
546 | { | 563 | { |
547 | struct tegra_xusb_port *port = &usb2->base; | 564 | struct tegra_xusb_port *port = &usb2->base; |
548 | struct device_node *np = port->dev.of_node; | 565 | struct device_node *np = port->dev.of_node; |
566 | const char *mode; | ||
549 | 567 | ||
550 | usb2->internal = of_property_read_bool(np, "nvidia,internal"); | 568 | usb2->internal = of_property_read_bool(np, "nvidia,internal"); |
551 | 569 | ||
570 | if (!of_property_read_string(np, "mode", &mode)) { | ||
571 | int err = match_string(modes, ARRAY_SIZE(modes), mode); | ||
572 | if (err < 0) { | ||
573 | dev_err(&port->dev, "invalid value %s for \"mode\"\n", | ||
574 | mode); | ||
575 | usb2->mode = USB_DR_MODE_UNKNOWN; | ||
576 | } else { | ||
577 | usb2->mode = err; | ||
578 | } | ||
579 | } else { | ||
580 | usb2->mode = USB_DR_MODE_HOST; | ||
581 | } | ||
582 | |||
552 | usb2->supply = devm_regulator_get(&port->dev, "vbus"); | 583 | usb2->supply = devm_regulator_get(&port->dev, "vbus"); |
553 | return PTR_ERR_OR_ZERO(usb2->supply); | 584 | return PTR_ERR_OR_ZERO(usb2->supply); |
554 | } | 585 | } |
@@ -839,6 +870,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) | |||
839 | struct tegra_xusb_padctl *padctl; | 870 | struct tegra_xusb_padctl *padctl; |
840 | const struct of_device_id *match; | 871 | const struct of_device_id *match; |
841 | struct resource *res; | 872 | struct resource *res; |
873 | unsigned int i; | ||
842 | int err; | 874 | int err; |
843 | 875 | ||
844 | /* for backwards compatibility with old device trees */ | 876 | /* for backwards compatibility with old device trees */ |
@@ -876,14 +908,38 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) | |||
876 | goto remove; | 908 | goto remove; |
877 | } | 909 | } |
878 | 910 | ||
911 | padctl->supplies = devm_kcalloc(&pdev->dev, padctl->soc->num_supplies, | ||
912 | sizeof(*padctl->supplies), GFP_KERNEL); | ||
913 | if (!padctl->supplies) { | ||
914 | err = -ENOMEM; | ||
915 | goto remove; | ||
916 | } | ||
917 | |||
918 | for (i = 0; i < padctl->soc->num_supplies; i++) | ||
919 | padctl->supplies[i].supply = padctl->soc->supply_names[i]; | ||
920 | |||
921 | err = devm_regulator_bulk_get(&pdev->dev, padctl->soc->num_supplies, | ||
922 | padctl->supplies); | ||
923 | if (err < 0) { | ||
924 | dev_err(&pdev->dev, "failed to get regulators: %d\n", err); | ||
925 | goto remove; | ||
926 | } | ||
927 | |||
879 | err = reset_control_deassert(padctl->rst); | 928 | err = reset_control_deassert(padctl->rst); |
880 | if (err < 0) | 929 | if (err < 0) |
881 | goto remove; | 930 | goto remove; |
882 | 931 | ||
932 | err = regulator_bulk_enable(padctl->soc->num_supplies, | ||
933 | padctl->supplies); | ||
934 | if (err < 0) { | ||
935 | dev_err(&pdev->dev, "failed to enable supplies: %d\n", err); | ||
936 | goto reset; | ||
937 | } | ||
938 | |||
883 | err = tegra_xusb_setup_pads(padctl); | 939 | err = tegra_xusb_setup_pads(padctl); |
884 | if (err < 0) { | 940 | if (err < 0) { |
885 | dev_err(&pdev->dev, "failed to setup pads: %d\n", err); | 941 | dev_err(&pdev->dev, "failed to setup pads: %d\n", err); |
886 | goto reset; | 942 | goto power_down; |
887 | } | 943 | } |
888 | 944 | ||
889 | err = tegra_xusb_setup_ports(padctl); | 945 | err = tegra_xusb_setup_ports(padctl); |
@@ -896,6 +952,8 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) | |||
896 | 952 | ||
897 | remove_pads: | 953 | remove_pads: |
898 | tegra_xusb_remove_pads(padctl); | 954 | tegra_xusb_remove_pads(padctl); |
955 | power_down: | ||
956 | regulator_bulk_disable(padctl->soc->num_supplies, padctl->supplies); | ||
899 | reset: | 957 | reset: |
900 | reset_control_assert(padctl->rst); | 958 | reset_control_assert(padctl->rst); |
901 | remove: | 959 | remove: |
@@ -911,6 +969,11 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev) | |||
911 | tegra_xusb_remove_ports(padctl); | 969 | tegra_xusb_remove_ports(padctl); |
912 | tegra_xusb_remove_pads(padctl); | 970 | tegra_xusb_remove_pads(padctl); |
913 | 971 | ||
972 | err = regulator_bulk_disable(padctl->soc->num_supplies, | ||
973 | padctl->supplies); | ||
974 | if (err < 0) | ||
975 | dev_err(&pdev->dev, "failed to disable supplies: %d\n", err); | ||
976 | |||
914 | err = reset_control_assert(padctl->rst); | 977 | err = reset_control_assert(padctl->rst); |
915 | if (err < 0) | 978 | if (err < 0) |
916 | dev_err(&pdev->dev, "failed to assert reset: %d\n", err); | 979 | dev_err(&pdev->dev, "failed to assert reset: %d\n", err); |