xref: /rk3399_rockchip-uboot/drivers/usb/host/ohci-generic.c (revision d2e45d1f9b7dfebc02ba362290e6b461b83bd1a2)
1fee331f6SAlexey Brodkin /*
2fee331f6SAlexey Brodkin  * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
3fee331f6SAlexey Brodkin  *
4fee331f6SAlexey Brodkin  * SPDX-License-Identifier:	GPL-2.0+
5fee331f6SAlexey Brodkin  */
6fee331f6SAlexey Brodkin 
75ccb6a79SFrank Wang #include <asm/io.h>
8fee331f6SAlexey Brodkin #include <common.h>
9155d9f65SPatrice Chotard #include <clk.h>
10fee331f6SAlexey Brodkin #include <dm.h>
11155d9f65SPatrice Chotard #include <dm/ofnode.h>
1228df1cfdSPatrice Chotard #include <generic-phy.h>
138a51b4b3SPatrice Chotard #include <reset.h>
14fee331f6SAlexey Brodkin #include "ohci.h"
15fee331f6SAlexey Brodkin 
16fee331f6SAlexey Brodkin #if !defined(CONFIG_USB_OHCI_NEW)
17fee331f6SAlexey Brodkin # error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW"
18fee331f6SAlexey Brodkin #endif
19fee331f6SAlexey Brodkin 
20fee331f6SAlexey Brodkin struct generic_ohci {
21fee331f6SAlexey Brodkin 	ohci_t ohci;
22155d9f65SPatrice Chotard 	struct clk *clocks;	/* clock list */
238a51b4b3SPatrice Chotard 	struct reset_ctl *resets; /* reset list */
2428df1cfdSPatrice Chotard 	struct phy phy;
25155d9f65SPatrice Chotard 	int clock_count;	/* number of clock in clock list */
268a51b4b3SPatrice Chotard 	int reset_count;	/* number of reset in reset list */
27fee331f6SAlexey Brodkin };
28fee331f6SAlexey Brodkin 
29fee331f6SAlexey Brodkin static int ohci_usb_probe(struct udevice *dev)
30fee331f6SAlexey Brodkin {
315ccb6a79SFrank Wang 	struct ohci_regs *regs;
32155d9f65SPatrice Chotard 	struct generic_ohci *priv = dev_get_priv(dev);
338a51b4b3SPatrice Chotard 	int i, err, ret, clock_nb, reset_nb;
34fee331f6SAlexey Brodkin 
35155d9f65SPatrice Chotard 	err = 0;
36155d9f65SPatrice Chotard 	priv->clock_count = 0;
37155d9f65SPatrice Chotard 	clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
38155d9f65SPatrice Chotard 	if (clock_nb > 0) {
39155d9f65SPatrice Chotard 		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
40155d9f65SPatrice Chotard 					    GFP_KERNEL);
41155d9f65SPatrice Chotard 		if (!priv->clocks)
42155d9f65SPatrice Chotard 			return -ENOMEM;
43155d9f65SPatrice Chotard 
44155d9f65SPatrice Chotard 		for (i = 0; i < clock_nb; i++) {
45155d9f65SPatrice Chotard 			err = clk_get_by_index(dev, i, &priv->clocks[i]);
46155d9f65SPatrice Chotard 			if (err < 0)
47155d9f65SPatrice Chotard 				break;
48155d9f65SPatrice Chotard 
49155d9f65SPatrice Chotard 			err = clk_enable(&priv->clocks[i]);
50*d2e45d1fSFrank Wang 			if (err && err != -ENOSYS) {
5190aa625cSMasahiro Yamada 				pr_err("failed to enable clock %d\n", i);
52155d9f65SPatrice Chotard 				clk_free(&priv->clocks[i]);
53155d9f65SPatrice Chotard 				goto clk_err;
54155d9f65SPatrice Chotard 			}
55155d9f65SPatrice Chotard 			priv->clock_count++;
56155d9f65SPatrice Chotard 		}
57155d9f65SPatrice Chotard 	} else if (clock_nb != -ENOENT) {
5890aa625cSMasahiro Yamada 		pr_err("failed to get clock phandle(%d)\n", clock_nb);
59155d9f65SPatrice Chotard 		return clock_nb;
60155d9f65SPatrice Chotard 	}
61155d9f65SPatrice Chotard 
628a51b4b3SPatrice Chotard 	priv->reset_count = 0;
638a51b4b3SPatrice Chotard 	reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells");
648a51b4b3SPatrice Chotard 	if (reset_nb > 0) {
658a51b4b3SPatrice Chotard 		priv->resets = devm_kcalloc(dev, reset_nb,
668a51b4b3SPatrice Chotard 					    sizeof(struct reset_ctl),
678a51b4b3SPatrice Chotard 					    GFP_KERNEL);
688a51b4b3SPatrice Chotard 		if (!priv->resets)
698a51b4b3SPatrice Chotard 			return -ENOMEM;
708a51b4b3SPatrice Chotard 
718a51b4b3SPatrice Chotard 		for (i = 0; i < reset_nb; i++) {
728a51b4b3SPatrice Chotard 			err = reset_get_by_index(dev, i, &priv->resets[i]);
738a51b4b3SPatrice Chotard 			if (err < 0)
748a51b4b3SPatrice Chotard 				break;
758a51b4b3SPatrice Chotard 
768a51b4b3SPatrice Chotard 			err = reset_deassert(&priv->resets[i]);
778a51b4b3SPatrice Chotard 			if (err) {
7890aa625cSMasahiro Yamada 				pr_err("failed to deassert reset %d\n", i);
798a51b4b3SPatrice Chotard 				reset_free(&priv->resets[i]);
808a51b4b3SPatrice Chotard 				goto reset_err;
818a51b4b3SPatrice Chotard 			}
828a51b4b3SPatrice Chotard 			priv->reset_count++;
838a51b4b3SPatrice Chotard 		}
848a51b4b3SPatrice Chotard 	} else if (reset_nb != -ENOENT) {
8590aa625cSMasahiro Yamada 		pr_err("failed to get reset phandle(%d)\n", reset_nb);
868a51b4b3SPatrice Chotard 		goto clk_err;
878a51b4b3SPatrice Chotard 	}
888a51b4b3SPatrice Chotard 
8928df1cfdSPatrice Chotard 	err = generic_phy_get_by_index(dev, 0, &priv->phy);
9028df1cfdSPatrice Chotard 	if (err) {
9128df1cfdSPatrice Chotard 		if (err != -ENOENT) {
9290aa625cSMasahiro Yamada 			pr_err("failed to get usb phy\n");
9328df1cfdSPatrice Chotard 			goto reset_err;
9428df1cfdSPatrice Chotard 		}
952080d023SPatrice Chotard 	} else {
9628df1cfdSPatrice Chotard 
9728df1cfdSPatrice Chotard 		err = generic_phy_init(&priv->phy);
9828df1cfdSPatrice Chotard 		if (err) {
9990aa625cSMasahiro Yamada 			pr_err("failed to init usb phy\n");
10028df1cfdSPatrice Chotard 			goto reset_err;
10128df1cfdSPatrice Chotard 		}
1022080d023SPatrice Chotard 	}
10328df1cfdSPatrice Chotard 
1045ccb6a79SFrank Wang 	regs = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
105155d9f65SPatrice Chotard 	err = ohci_register(dev, regs);
106155d9f65SPatrice Chotard 	if (err)
10728df1cfdSPatrice Chotard 		goto phy_err;
108155d9f65SPatrice Chotard 
109155d9f65SPatrice Chotard 	return 0;
110155d9f65SPatrice Chotard 
11128df1cfdSPatrice Chotard phy_err:
11228df1cfdSPatrice Chotard 	if (generic_phy_valid(&priv->phy)) {
11328df1cfdSPatrice Chotard 		ret = generic_phy_exit(&priv->phy);
11428df1cfdSPatrice Chotard 		if (ret)
11590aa625cSMasahiro Yamada 			pr_err("failed to release phy\n");
11628df1cfdSPatrice Chotard 	}
11728df1cfdSPatrice Chotard 
1188a51b4b3SPatrice Chotard reset_err:
1198a51b4b3SPatrice Chotard 	ret = reset_release_all(priv->resets, priv->reset_count);
1208a51b4b3SPatrice Chotard 	if (ret)
12190aa625cSMasahiro Yamada 		pr_err("failed to assert all resets\n");
122155d9f65SPatrice Chotard clk_err:
123155d9f65SPatrice Chotard 	ret = clk_release_all(priv->clocks, priv->clock_count);
124155d9f65SPatrice Chotard 	if (ret)
12590aa625cSMasahiro Yamada 		pr_err("failed to disable all clocks\n");
126155d9f65SPatrice Chotard 
127155d9f65SPatrice Chotard 	return err;
128fee331f6SAlexey Brodkin }
129fee331f6SAlexey Brodkin 
130fee331f6SAlexey Brodkin static int ohci_usb_remove(struct udevice *dev)
131fee331f6SAlexey Brodkin {
132155d9f65SPatrice Chotard 	struct generic_ohci *priv = dev_get_priv(dev);
133155d9f65SPatrice Chotard 	int ret;
134155d9f65SPatrice Chotard 
135155d9f65SPatrice Chotard 	ret = ohci_deregister(dev);
136155d9f65SPatrice Chotard 	if (ret)
137155d9f65SPatrice Chotard 		return ret;
138155d9f65SPatrice Chotard 
13928df1cfdSPatrice Chotard 	if (generic_phy_valid(&priv->phy)) {
14028df1cfdSPatrice Chotard 		ret = generic_phy_exit(&priv->phy);
14128df1cfdSPatrice Chotard 		if (ret)
14228df1cfdSPatrice Chotard 			return ret;
14328df1cfdSPatrice Chotard 	}
14428df1cfdSPatrice Chotard 
1458a51b4b3SPatrice Chotard 	ret = reset_release_all(priv->resets, priv->reset_count);
1468a51b4b3SPatrice Chotard 	if (ret)
1478a51b4b3SPatrice Chotard 		return ret;
1488a51b4b3SPatrice Chotard 
149155d9f65SPatrice Chotard 	return clk_release_all(priv->clocks, priv->clock_count);
150fee331f6SAlexey Brodkin }
151fee331f6SAlexey Brodkin 
152fee331f6SAlexey Brodkin static const struct udevice_id ohci_usb_ids[] = {
153fee331f6SAlexey Brodkin 	{ .compatible = "generic-ohci" },
154fee331f6SAlexey Brodkin 	{ }
155fee331f6SAlexey Brodkin };
156fee331f6SAlexey Brodkin 
157fee331f6SAlexey Brodkin U_BOOT_DRIVER(ohci_generic) = {
158fee331f6SAlexey Brodkin 	.name	= "ohci_generic",
159fee331f6SAlexey Brodkin 	.id	= UCLASS_USB,
160fee331f6SAlexey Brodkin 	.of_match = ohci_usb_ids,
161fee331f6SAlexey Brodkin 	.probe = ohci_usb_probe,
162fee331f6SAlexey Brodkin 	.remove = ohci_usb_remove,
163fee331f6SAlexey Brodkin 	.ops	= &ohci_usb_ops,
164fee331f6SAlexey Brodkin 	.priv_auto_alloc_size = sizeof(struct generic_ohci),
165fee331f6SAlexey Brodkin 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
166fee331f6SAlexey Brodkin };
167