blob: 57c7d5630d37e79344acd667e34d984f6702eba3 [file] [log] [blame]
Stephan Gerhold845d9cf2021-07-08 20:33:50 +02001// SPDX-License-Identifier: GPL-2.0+
2/* Copyright (C) 2019 Stephan Gerhold */
3
4#include <common.h>
5#include <dm.h>
6#include <generic-phy.h>
7#include <dm/device_compat.h>
8#include "musb_uboot.h"
9
10static struct musb_hdrc_config ux500_musb_hdrc_config = {
11 .multipoint = true,
12 .dyn_fifo = true,
13 .num_eps = 16,
14 .ram_bits = 16,
15};
16
17struct ux500_glue {
18 struct musb_host_data mdata;
19 struct device dev;
20 struct phy phy;
21 bool enabled;
22};
23#define to_ux500_glue(d) container_of(d, struct ux500_glue, dev)
24
25static int ux500_musb_enable(struct musb *musb)
26{
27 struct ux500_glue *glue = to_ux500_glue(musb->controller);
28 int ret;
29
30 if (glue->enabled)
31 return 0;
32
33 ret = generic_phy_power_on(&glue->phy);
34 if (ret) {
35 printf("%s: failed to power on USB PHY\n", __func__);
36 return ret;
37 }
38
39 glue->enabled = true;
40 return 0;
41}
42
43static void ux500_musb_disable(struct musb *musb)
44{
45 struct ux500_glue *glue = to_ux500_glue(musb->controller);
46 int ret;
47
48 if (!glue->enabled)
49 return;
50
51 ret = generic_phy_power_off(&glue->phy);
52 if (ret) {
53 printf("%s: failed to power off USB PHY\n", __func__);
54 return;
55 }
56
57 glue->enabled = false;
58}
59
60static int ux500_musb_init(struct musb *musb)
61{
62 struct ux500_glue *glue = to_ux500_glue(musb->controller);
63 int ret;
64
65 ret = generic_phy_init(&glue->phy);
66 if (ret) {
67 printf("%s: failed to init USB PHY\n", __func__);
68 return ret;
69 }
70
71 return 0;
72}
73
74static int ux500_musb_exit(struct musb *musb)
75{
76 struct ux500_glue *glue = to_ux500_glue(musb->controller);
77 int ret;
78
79 ret = generic_phy_exit(&glue->phy);
80 if (ret) {
81 printf("%s: failed to exit USB PHY\n", __func__);
82 return ret;
83 }
84
85 return 0;
86}
87
88static const struct musb_platform_ops ux500_musb_ops = {
89 .init = ux500_musb_init,
90 .exit = ux500_musb_exit,
91 .enable = ux500_musb_enable,
92 .disable = ux500_musb_disable,
93};
94
95int dm_usb_gadget_handle_interrupts(struct udevice *dev)
96{
97 struct ux500_glue *glue = dev_get_priv(dev);
98
99 glue->mdata.host->isr(0, glue->mdata.host);
100 return 0;
101}
102
103static int ux500_musb_probe(struct udevice *dev)
104{
105#ifdef CONFIG_USB_MUSB_HOST
106 struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
107#endif
108 struct ux500_glue *glue = dev_get_priv(dev);
109 struct musb_host_data *host = &glue->mdata;
110 struct musb_hdrc_platform_data pdata;
111 void *base = dev_read_addr_ptr(dev);
112 int ret;
113
114 if (!base)
115 return -EINVAL;
116
117 ret = generic_phy_get_by_name(dev, "usb", &glue->phy);
118 if (ret) {
119 dev_err(dev, "failed to get USB PHY: %d\n", ret);
120 return ret;
121 }
122
123 memset(&pdata, 0, sizeof(pdata));
124 pdata.platform_ops = &ux500_musb_ops;
125 pdata.config = &ux500_musb_hdrc_config;
126
127#ifdef CONFIG_USB_MUSB_HOST
128 priv->desc_before_addr = true;
129 pdata.mode = MUSB_HOST;
130
131 host->host = musb_init_controller(&pdata, &glue->dev, base);
132 if (!host->host)
133 return -EIO;
134
135 return musb_lowlevel_init(host);
136#else
137 pdata.mode = MUSB_PERIPHERAL;
138 host->host = musb_init_controller(&pdata, &glue->dev, base);
139 if (!host->host)
140 return -EIO;
141
142 return usb_add_gadget_udc(&glue->dev, &host->host->g);
143#endif
144}
145
146static int ux500_musb_remove(struct udevice *dev)
147{
148 struct ux500_glue *glue = dev_get_priv(dev);
149 struct musb_host_data *host = &glue->mdata;
150
151 usb_del_gadget_udc(&host->host->g);
152 musb_stop(host->host);
153 free(host->host);
154 host->host = NULL;
155
156 return 0;
157}
158
159static const struct udevice_id ux500_musb_ids[] = {
160 { .compatible = "stericsson,db8500-musb" },
161 { }
162};
163
164U_BOOT_DRIVER(ux500_musb) = {
165 .name = "ux500-musb",
166#ifdef CONFIG_USB_MUSB_HOST
167 .id = UCLASS_USB,
168#else
169 .id = UCLASS_USB_GADGET_GENERIC,
170#endif
171 .of_match = ux500_musb_ids,
172 .probe = ux500_musb_probe,
173 .remove = ux500_musb_remove,
174#ifdef CONFIG_USB_MUSB_HOST
175 .ops = &musb_usb_ops,
176#endif
177 .plat_auto = sizeof(struct usb_plat),
178 .priv_auto = sizeof(struct ux500_glue),
179};