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