xref: /rk3399_rockchip-uboot/drivers/usb/host/ohci-generic.c (revision 1a4f6af8bfd44c8ae6e87a81ff125eed47042cc5)
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 
ohci_setup_phy(struct udevice * dev,int index)298a1be473SPatrice Chotard static int ohci_setup_phy(struct udevice *dev, int index)
308a1be473SPatrice Chotard {
318a1be473SPatrice Chotard 	struct generic_ohci *priv = dev_get_priv(dev);
328a1be473SPatrice Chotard 	int ret;
338a1be473SPatrice Chotard 
348a1be473SPatrice Chotard 	ret = generic_phy_get_by_index(dev, index, &priv->phy);
358a1be473SPatrice Chotard 	if (ret) {
368a1be473SPatrice Chotard 		if (ret != -ENOENT) {
378a1be473SPatrice Chotard 			dev_err(dev, "failed to get usb phy\n");
388a1be473SPatrice Chotard 			return ret;
398a1be473SPatrice Chotard 		}
408a1be473SPatrice Chotard 	} else {
418a1be473SPatrice Chotard 		ret = generic_phy_init(&priv->phy);
428a1be473SPatrice Chotard 		if (ret) {
438a1be473SPatrice Chotard 			dev_err(dev, "failed to init usb phy\n");
448a1be473SPatrice Chotard 			return ret;
458a1be473SPatrice Chotard 		}
468a1be473SPatrice Chotard 
478a1be473SPatrice Chotard 		ret = generic_phy_power_on(&priv->phy);
488a1be473SPatrice Chotard 		if (ret) {
498a1be473SPatrice Chotard 			dev_err(dev, "failed to power on usb phy\n");
508a1be473SPatrice Chotard 			return generic_phy_exit(&priv->phy);
518a1be473SPatrice Chotard 		}
528a1be473SPatrice Chotard 	}
538a1be473SPatrice Chotard 
548a1be473SPatrice Chotard 	return 0;
558a1be473SPatrice Chotard }
568a1be473SPatrice Chotard 
ohci_shutdown_phy(struct udevice * dev)578a1be473SPatrice Chotard static int ohci_shutdown_phy(struct udevice *dev)
588a1be473SPatrice Chotard {
598a1be473SPatrice Chotard 	struct generic_ohci *priv = dev_get_priv(dev);
608a1be473SPatrice Chotard 	int ret = 0;
618a1be473SPatrice Chotard 
628a1be473SPatrice Chotard 	if (generic_phy_valid(&priv->phy)) {
638a1be473SPatrice Chotard 		ret = generic_phy_power_off(&priv->phy);
648a1be473SPatrice Chotard 		if (ret) {
658a1be473SPatrice Chotard 			dev_err(dev, "failed to power off usb phy\n");
668a1be473SPatrice Chotard 			return ret;
678a1be473SPatrice Chotard 		}
688a1be473SPatrice Chotard 
698a1be473SPatrice Chotard 		ret = generic_phy_exit(&priv->phy);
708a1be473SPatrice Chotard 		if (ret) {
718a1be473SPatrice Chotard 			dev_err(dev, "failed to power off usb phy\n");
728a1be473SPatrice Chotard 			return ret;
738a1be473SPatrice Chotard 		}
748a1be473SPatrice Chotard 	}
758a1be473SPatrice Chotard 
768a1be473SPatrice Chotard 	return 0;
778a1be473SPatrice Chotard }
788a1be473SPatrice Chotard 
ohci_usb_probe(struct udevice * dev)79fee331f6SAlexey Brodkin static int ohci_usb_probe(struct udevice *dev)
80fee331f6SAlexey Brodkin {
815ccb6a79SFrank Wang 	struct ohci_regs *regs;
82155d9f65SPatrice Chotard 	struct generic_ohci *priv = dev_get_priv(dev);
838a51b4b3SPatrice Chotard 	int i, err, ret, clock_nb, reset_nb;
84fee331f6SAlexey Brodkin 
85155d9f65SPatrice Chotard 	err = 0;
86155d9f65SPatrice Chotard 	priv->clock_count = 0;
87155d9f65SPatrice Chotard 	clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
88155d9f65SPatrice Chotard 	if (clock_nb > 0) {
89155d9f65SPatrice Chotard 		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
90155d9f65SPatrice Chotard 					    GFP_KERNEL);
91155d9f65SPatrice Chotard 		if (!priv->clocks)
92155d9f65SPatrice Chotard 			return -ENOMEM;
93155d9f65SPatrice Chotard 
94155d9f65SPatrice Chotard 		for (i = 0; i < clock_nb; i++) {
95155d9f65SPatrice Chotard 			err = clk_get_by_index(dev, i, &priv->clocks[i]);
96155d9f65SPatrice Chotard 			if (err < 0)
97155d9f65SPatrice Chotard 				break;
98155d9f65SPatrice Chotard 
99155d9f65SPatrice Chotard 			err = clk_enable(&priv->clocks[i]);
100*541cc577SKever Yang 			if (err && err != -ENOSYS) {
101f7dd2187SPatrice Chotard 				dev_err(dev, "failed to enable clock %d\n", i);
102155d9f65SPatrice Chotard 				clk_free(&priv->clocks[i]);
103155d9f65SPatrice Chotard 				goto clk_err;
104155d9f65SPatrice Chotard 			}
105155d9f65SPatrice Chotard 			priv->clock_count++;
106155d9f65SPatrice Chotard 		}
107155d9f65SPatrice Chotard 	} else if (clock_nb != -ENOENT) {
108f7dd2187SPatrice Chotard 		dev_err(dev, "failed to get clock phandle(%d)\n", clock_nb);
109155d9f65SPatrice Chotard 		return clock_nb;
110155d9f65SPatrice Chotard 	}
111155d9f65SPatrice Chotard 
1128a51b4b3SPatrice Chotard 	priv->reset_count = 0;
1138a51b4b3SPatrice Chotard 	reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells");
1148a51b4b3SPatrice Chotard 	if (reset_nb > 0) {
1158a51b4b3SPatrice Chotard 		priv->resets = devm_kcalloc(dev, reset_nb,
1168a51b4b3SPatrice Chotard 					    sizeof(struct reset_ctl),
1178a51b4b3SPatrice Chotard 					    GFP_KERNEL);
1188a51b4b3SPatrice Chotard 		if (!priv->resets)
1198a51b4b3SPatrice Chotard 			return -ENOMEM;
1208a51b4b3SPatrice Chotard 
1218a51b4b3SPatrice Chotard 		for (i = 0; i < reset_nb; i++) {
1228a51b4b3SPatrice Chotard 			err = reset_get_by_index(dev, i, &priv->resets[i]);
1238a51b4b3SPatrice Chotard 			if (err < 0)
1248a51b4b3SPatrice Chotard 				break;
1258a51b4b3SPatrice Chotard 
1268a51b4b3SPatrice Chotard 			err = reset_deassert(&priv->resets[i]);
1278a51b4b3SPatrice Chotard 			if (err) {
128f7dd2187SPatrice Chotard 				dev_err(dev, "failed to deassert reset %d\n", i);
1298a51b4b3SPatrice Chotard 				reset_free(&priv->resets[i]);
1308a51b4b3SPatrice Chotard 				goto reset_err;
1318a51b4b3SPatrice Chotard 			}
1328a51b4b3SPatrice Chotard 			priv->reset_count++;
1338a51b4b3SPatrice Chotard 		}
1348a51b4b3SPatrice Chotard 	} else if (reset_nb != -ENOENT) {
135f7dd2187SPatrice Chotard 		dev_err(dev, "failed to get reset phandle(%d)\n", reset_nb);
1368a51b4b3SPatrice Chotard 		goto clk_err;
1378a51b4b3SPatrice Chotard 	}
1388a51b4b3SPatrice Chotard 
1398a1be473SPatrice Chotard 	err = ohci_setup_phy(dev, 0);
1408a1be473SPatrice Chotard 	if (err)
14128df1cfdSPatrice Chotard 		goto reset_err;
14228df1cfdSPatrice Chotard 
1435ccb6a79SFrank Wang 	regs = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
144155d9f65SPatrice Chotard 	err = ohci_register(dev, regs);
145155d9f65SPatrice Chotard 	if (err)
14628df1cfdSPatrice Chotard 		goto phy_err;
147155d9f65SPatrice Chotard 
148155d9f65SPatrice Chotard 	return 0;
149155d9f65SPatrice Chotard 
15028df1cfdSPatrice Chotard phy_err:
1518a1be473SPatrice Chotard 	ret = ohci_shutdown_phy(dev);
152324810fcSPatrice Chotard 	if (ret)
1538a1be473SPatrice Chotard 		dev_err(dev, "failed to shutdown usb phy\n");
15428df1cfdSPatrice Chotard 
1558a51b4b3SPatrice Chotard reset_err:
1568a51b4b3SPatrice Chotard 	ret = reset_release_all(priv->resets, priv->reset_count);
1578a51b4b3SPatrice Chotard 	if (ret)
158f7dd2187SPatrice Chotard 		dev_err(dev, "failed to assert all resets\n");
159155d9f65SPatrice Chotard clk_err:
160155d9f65SPatrice Chotard 	ret = clk_release_all(priv->clocks, priv->clock_count);
161155d9f65SPatrice Chotard 	if (ret)
162f7dd2187SPatrice Chotard 		dev_err(dev, "failed to disable all clocks\n");
163155d9f65SPatrice Chotard 
164155d9f65SPatrice Chotard 	return err;
165fee331f6SAlexey Brodkin }
166fee331f6SAlexey Brodkin 
ohci_usb_remove(struct udevice * dev)167fee331f6SAlexey Brodkin static int ohci_usb_remove(struct udevice *dev)
168fee331f6SAlexey Brodkin {
169155d9f65SPatrice Chotard 	struct generic_ohci *priv = dev_get_priv(dev);
170155d9f65SPatrice Chotard 	int ret;
171155d9f65SPatrice Chotard 
172155d9f65SPatrice Chotard 	ret = ohci_deregister(dev);
173155d9f65SPatrice Chotard 	if (ret)
174155d9f65SPatrice Chotard 		return ret;
175155d9f65SPatrice Chotard 
1768a1be473SPatrice Chotard 	ret = ohci_shutdown_phy(dev);
177324810fcSPatrice Chotard 	if (ret)
178324810fcSPatrice Chotard 		return ret;
179324810fcSPatrice Chotard 
1808a51b4b3SPatrice Chotard 	ret = reset_release_all(priv->resets, priv->reset_count);
1818a51b4b3SPatrice Chotard 	if (ret)
1828a51b4b3SPatrice Chotard 		return ret;
1838a51b4b3SPatrice Chotard 
184155d9f65SPatrice Chotard 	return clk_release_all(priv->clocks, priv->clock_count);
185fee331f6SAlexey Brodkin }
186fee331f6SAlexey Brodkin 
187fee331f6SAlexey Brodkin static const struct udevice_id ohci_usb_ids[] = {
188fee331f6SAlexey Brodkin 	{ .compatible = "generic-ohci" },
189fee331f6SAlexey Brodkin 	{ }
190fee331f6SAlexey Brodkin };
191fee331f6SAlexey Brodkin 
192fee331f6SAlexey Brodkin U_BOOT_DRIVER(ohci_generic) = {
193fee331f6SAlexey Brodkin 	.name	= "ohci_generic",
194fee331f6SAlexey Brodkin 	.id	= UCLASS_USB,
195fee331f6SAlexey Brodkin 	.of_match = ohci_usb_ids,
196fee331f6SAlexey Brodkin 	.probe = ohci_usb_probe,
197fee331f6SAlexey Brodkin 	.remove = ohci_usb_remove,
198fee331f6SAlexey Brodkin 	.ops	= &ohci_usb_ops,
199fee331f6SAlexey Brodkin 	.priv_auto_alloc_size = sizeof(struct generic_ohci),
200fee331f6SAlexey Brodkin 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
201fee331f6SAlexey Brodkin };
202