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