1 // 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 
10 static 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 
17 struct 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 
ux500_musb_enable(struct musb * musb)25 static 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 
ux500_musb_disable(struct musb * musb)43 static 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 
ux500_musb_init(struct musb * musb)60 static 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 
ux500_musb_exit(struct musb * musb)74 static 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 
88 static 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 
dm_usb_gadget_handle_interrupts(struct udevice * dev)95 int 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 
ux500_musb_probe(struct udevice * dev)103 static 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 
ux500_musb_remove(struct udevice * dev)146 static 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 
159 static const struct udevice_id ux500_musb_ids[] = {
160 	{ .compatible = "stericsson,db8500-musb" },
161 	{ }
162 };
163 
164 U_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 };
180