libopencm3
A free/libre/open-source firmware library for various ARM Cortex-M3 microcontrollers.
usb_efm32.c
Go to the documentation of this file.
1/** @addtogroup usb_file USB peripheral API
2 * @ingroup peripheral_apis
3 *
4 * @sa usb_defines
5 * @copyright See @ref lgpl_license
6 */
7/*
8 * This file is part of the libopencm3 project.
9 *
10 * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
11 * Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@gmail.com>
12 *
13 * This library is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this library. If not, see <http://www.gnu.org/licenses/>.
25 */
26
27#include <string.h>
32#include <libopencm3/usb/usbd.h>
33#include "usb_private.h"
34
35/**@{*/
36
37/* Receive FIFO size in 32-bit words. */
38#define RX_FIFO_SIZE 256
39
40/* FIME: EFM32LG have 6 bidirectonal-endpoint
41 * problem is "uint32_t doeptsiz[4];" in usb_private.h
42 * doeptsiz is fixed size of length 4,
43 * if we it to be of length 6
44 * possibly, same with "uint8_t force_nak[4];"
45 *
46 * solution: remove everything driver specific from usb_private.h
47 * and move that to there specific driver files.
48 * maybe a pointer to driver specific data will do the task. */
49
50#define ENDPOINT_COUNT 4
51
52static struct _usbd_device _usbd_dev;
53
54/** Initialize the USB_FS device controller hardware of the STM32. */
56{
57 /* Enable clock */
60
61 /* wait till clock not selected */
63
65
66 USB_CTRL &= ~USB_CTRL_DMPUAP;
68
69 /* Wait for AHB idle. */
71 /* Do core soft reset. */
74
75 /* Force peripheral only mode. */
77
78 /* Full speed device. */
80
81 /* Restart the PHY clock. */
82 USB_PCGCCTL = 0;
83
84 USB_GRXFSIZ = efm32lg_usb_driver.rx_fifo_size;
85 _usbd_dev.fifo_mem_top = efm32lg_usb_driver.rx_fifo_size;
86
87 /* Unmask interrupts for TX and RX. */
94 USB_DAINTMSK = 0xF;
96
97 return &_usbd_dev;
98}
99
100static void efm32lg_set_address(usbd_device *usbd_dev, uint8_t addr)
101{
102 (void)usbd_dev;
103
104 USB_DCFG = (USB_DCFG & ~USB_DCFG_DAD) | (addr << 4);
105}
106
107static void efm32lg_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type,
108 uint16_t max_size,
109 void (*callback) (usbd_device *usbd_dev, uint8_t ep))
110{
111 /*
112 * Configure endpoint address and type. Allocate FIFO memory for
113 * endpoint. Install callback function.
114 */
115 uint8_t dir = addr & 0x80;
116 addr &= 0x7f;
117
118 if (addr == 0) { /* For the default control endpoint */
119 /* Configure IN part. */
120 if (max_size >= 64) {
122 } else if (max_size >= 32) {
124 } else if (max_size >= 16) {
126 } else {
128 }
129
131 (max_size & USB_DIEP0TSIZ_XFRSIZ_MASK);
132 USB_DIEP0CTL |=
134
135 /* Configure OUT part. */
136 usbd_dev->doeptsiz[0] = USB_DIEP0TSIZ_STUPCNT_1 |
138 (max_size & USB_DIEP0TSIZ_XFRSIZ_MASK);
139 USB_DOEPx_TSIZ(0) = usbd_dev->doeptsiz[0];
140 USB_DOEPx_CTL(0) |=
142
143 USB_GNPTXFSIZ = ((max_size / 4) << 16) |
144 usbd_dev->driver->rx_fifo_size;
145 usbd_dev->fifo_mem_top += max_size / 4;
146 usbd_dev->fifo_mem_top_ep0 = usbd_dev->fifo_mem_top;
147
148 return;
149 }
150
151 if (dir) {
152 USB_DIEPTXF(addr) = ((max_size / 4) << 16) |
153 usbd_dev->fifo_mem_top;
154 usbd_dev->fifo_mem_top += max_size / 4;
155
156 USB_DIEPx_TSIZ(addr) =
157 (max_size & USB_DIEP0TSIZ_XFRSIZ_MASK);
158 USB_DIEPx_CTL(addr) |=
161 | (addr << 22) | max_size;
162
163 if (callback) {
164 usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_IN] =
165 (void *)callback;
166 }
167 }
168
169 if (!dir) {
170 usbd_dev->doeptsiz[addr] = USB_DIEP0TSIZ_PKTCNT |
171 (max_size & USB_DIEP0TSIZ_XFRSIZ_MASK);
172 USB_DOEPx_TSIZ(addr) = usbd_dev->doeptsiz[addr];
175 USB_DOEP0CTL_SD0PID | (type << 18) | max_size;
176
177 if (callback) {
178 usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_OUT] =
179 (void *)callback;
180 }
181 }
182}
183
185{
186 /* The core resets the endpoints automatically on reset. */
187 usbd_dev->fifo_mem_top = usbd_dev->fifo_mem_top_ep0;
188}
189
190static void efm32lg_ep_stall_set(usbd_device *usbd_dev, uint8_t addr,
191 uint8_t stall)
192{
193 (void)usbd_dev;
194 if (addr == 0) {
195 if (stall) {
197 } else {
198 USB_DIEPx_CTL(addr) &= ~USB_DIEP0CTL_STALL;
199 }
200 }
201
202 if (addr & 0x80) {
203 addr &= 0x7F;
204
205 if (stall) {
207 } else {
208 USB_DIEPx_CTL(addr) &= ~USB_DIEP0CTL_STALL;
210 }
211 } else {
212 if (stall) {
214 } else {
215 USB_DOEPx_CTL(addr) &= ~USB_DOEP0CTL_STALL;
217 }
218 }
219}
220
221static uint8_t efm32lg_ep_stall_get(usbd_device *usbd_dev, uint8_t addr)
222{
223 (void)usbd_dev;
224
225 /* Return non-zero if STALL set. */
226 if (addr & 0x80) {
227 return (USB_DIEPx_CTL(addr & 0x7f) &
228 USB_DIEP0CTL_STALL) ? 1 : 0;
229 } else {
230 return (USB_DOEPx_CTL(addr) &
231 USB_DOEP0CTL_STALL) ? 1 : 0;
232 }
233}
234
235static void efm32lg_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak)
236{
237 /* It does not make sence to force NAK on IN endpoints. */
238 if (addr & 0x80) {
239 return;
240 }
241
242 usbd_dev->force_nak[addr] = nak;
243
244 if (nak) {
246 } else {
248 }
249}
250
251static uint16_t efm32lg_ep_write_packet(usbd_device *usbd_dev, uint8_t addr,
252 const void *buf, uint16_t len)
253{
254 (void)usbd_dev;
255 const uint32_t *buf32 = buf;
256 int i;
257
258 addr &= 0x7F;
259
260 /* Return if endpoint is already enabled. */
262 return 0;
263 }
264
265 /* Enable endpoint for transmission. */
269 volatile uint32_t *fifo = USB_FIFOxD(addr);
270
271 /* Copy buffer to endpoint FIFO, note - memcpy does not work */
272 for (i = len; i > 0; i -= 4) {
273 *fifo++ = *buf32++;
274 }
275
276 return len;
277}
278
279static uint16_t efm32lg_ep_read_packet(usbd_device *usbd_dev, uint8_t addr,
280 void *buf, uint16_t len)
281{
282 int i;
283 uint32_t *buf32 = buf;
284 uint32_t extra;
285
286 len = MIN(len, usbd_dev->rxbcnt);
287 usbd_dev->rxbcnt -= len;
288
289 volatile uint32_t *fifo = USB_FIFOxD(addr);
290 for (i = len; i >= 4; i -= 4) {
291 *buf32++ = *fifo++;
292 }
293
294 if (i) {
295 extra = *fifo++;
296 memcpy(buf32, &extra, i);
297 }
298
299 USB_DOEPx_TSIZ(addr) = usbd_dev->doeptsiz[addr];
301 (usbd_dev->force_nak[addr] ?
303
304 return len;
305}
306
307static void efm32lg_poll(usbd_device *usbd_dev)
308{
309 /* Read interrupt status register. */
310 uint32_t intsts = USB_GINTSTS;
311 int i;
312
313 if (intsts & USB_GINTSTS_ENUMDNE) {
314 /* Handle USB RESET condition. */
316 usbd_dev->fifo_mem_top = usbd_dev->driver->rx_fifo_size;
317 _usbd_reset(usbd_dev);
318 return;
319 }
320
321 /* Note: RX and TX handled differently in this device. */
322 if (intsts & USB_GINTSTS_RXFLVL) {
323 /* Receive FIFO non-empty. */
324 uint32_t rxstsp = USB_GRXSTSP;
325 uint32_t pktsts = rxstsp & USB_GRXSTSP_PKTSTS_MASK;
326 if ((pktsts != USB_GRXSTSP_PKTSTS_OUT) &&
327 (pktsts != USB_GRXSTSP_PKTSTS_SETUP)) {
328 return;
329 }
330
331 uint8_t ep = rxstsp & USB_GRXSTSP_EPNUM_MASK;
332 uint8_t type;
333 if (pktsts == USB_GRXSTSP_PKTSTS_SETUP) {
334 type = USB_TRANSACTION_SETUP;
335 } else {
336 type = USB_TRANSACTION_OUT;
337 }
338
339 /* Save packet size for stm32f107_ep_read_packet(). */
340 usbd_dev->rxbcnt = (rxstsp & USB_GRXSTSP_BCNT_MASK) >> 4;
341
342 /*
343 * FIXME: Why is a delay needed here?
344 * This appears to fix a problem where the first 4 bytes
345 * of the DATA OUT stage of a control transaction are lost.
346 */
347 for (i = 0; i < 1000; i++) {
348 __asm__("nop");
349 }
350
351 if (usbd_dev->user_callback_ctr[ep][type]) {
352 usbd_dev->user_callback_ctr[ep][type] (usbd_dev, ep);
353 }
354
355 /* Discard unread packet data. */
356 for (i = 0; i < usbd_dev->rxbcnt; i += 4) {
357 (void)*USB_FIFOxD(ep);
358 }
359
360 usbd_dev->rxbcnt = 0;
361 }
362
363 /*
364 * There is no global interrupt flag for transmit complete.
365 * The XFRC bit must be checked in each USB_DIEPx_INT(x).
366 */
367 for (i = 0; i < ENDPOINT_COUNT; i++) { /* Iterate over endpoints. */
369 /* Transfer complete. */
370 if (usbd_dev->user_callback_ctr[i]
371 [USB_TRANSACTION_IN]) {
372 usbd_dev->user_callback_ctr[i]
373 [USB_TRANSACTION_IN](usbd_dev, i);
374 }
375
377 }
378 }
379
380 if (intsts & USB_GINTSTS_USBSUSP) {
381 if (usbd_dev->user_callback_suspend) {
382 usbd_dev->user_callback_suspend();
383 }
385 }
386
387 if (intsts & USB_GINTSTS_WKUPINT) {
388 if (usbd_dev->user_callback_resume) {
389 usbd_dev->user_callback_resume();
390 }
392 }
393
394 if (intsts & USB_GINTSTS_SOF) {
395 if (usbd_dev->user_callback_sof) {
396 usbd_dev->user_callback_sof();
397 }
399 }
400
401 if (usbd_dev->user_callback_sof) {
403 } else {
404 USB_GINTMSK &= ~USB_GINTMSK_SOFM;
405 }
406}
407
408static void efm32lg_disconnect(usbd_device *usbd_dev, bool disconnected)
409{
410 (void)usbd_dev;
411
412 if (disconnected) {
414 } else {
415 USB_DCTL &= ~USB_DCTL_SDIS;
416 }
417}
418
419const struct _usbd_driver efm32lg_usb_driver = {
420 .init = efm32lg_usbd_init,
421 .set_address = efm32lg_set_address,
422 .ep_setup = efm32lg_ep_setup,
423 .ep_reset = efm32lg_endpoints_reset,
424 .ep_stall_set = efm32lg_ep_stall_set,
425 .ep_stall_get = efm32lg_ep_stall_get,
426 .ep_nak_set = efm32lg_ep_nak_set,
427 .ep_write_packet = efm32lg_ep_write_packet,
428 .ep_read_packet = efm32lg_ep_read_packet,
429 .poll = efm32lg_poll,
430 .disconnect = efm32lg_disconnect,
431 .base_address = USB_BASE,
432 .set_address_before_status = 1,
433 .rx_fifo_size = RX_FIFO_SIZE,
434};
435
436/**@}*/
#define USB_BASE
Dispatcher for the base address definitions, depending on the particular Gecko family.
#define CMU_HFCORECLKEN0_USBC
Definition: cmu_common.h:437
#define CMU_HFCORECLKEN0_USB
Definition: cmu_common.h:436
#define CMU_HFCORECLKEN0
Definition: cmu_common.h:45
#define CMU_CMD
Definition: cmu_common.h:38
#define CMU_STATUS
Definition: cmu_common.h:40
#define CMU_STATUS_USBCHFCLKSEL
Definition: cmu_common.h:376
#define CMU_CMD_USBCCLKSEL_HFCLKNODIV
Definition: cmu_common.h:343
#define USB_GRXSTSP_PKTSTS_OUT
Definition: usb_common.h:229
#define USB_DIEP0TSIZ_STUPCNT_1
Definition: usb_common.h:362
#define USB_GINTSTS_MMIS
Definition: usb_common.h:193
#define USB_FIFOxD(x)
Definition: usb_common.h:119
#define USB_GAHBCFG_GLBLINTRMSK
Definition: usb_common.h:136
#define USB_GRXSTSP_EPNUM_MASK
Definition: usb_common.h:239
#define USB_DIEP_INT_XFRC
Definition: usb_common.h:348
#define USB_DCFG
Definition: usb_common.h:84
#define USB_DIEP0CTL_SNAK
Definition: usb_common.h:302
#define USB_DIEP0CTL_MPSIZ_16
Definition: usb_common.h:315
#define USB_GRSTCTL
Definition: usb_common.h:51
#define USB_DOEP0CTL_EPENA
Definition: usb_common.h:319
#define USB_DIEPTXF(x)
Definition: usb_common.h:61
#define USB_GRSTCTL_AHBIDL
Definition: usb_common.h:154
#define USB_DIEP0CTL_USBAEP
Definition: usb_common.h:310
#define USB_GINTSTS_SOF
Definition: usb_common.h:191
#define USB_ROUTE_PHYPEN
Definition: usb_common.h:43
#define USB_GAHBCFG
Definition: usb_common.h:49
#define USB_GINTMSK_SOFM
Definition: usb_common.h:199
#define USB_DIEPx_TSIZ(x)
Definition: usb_common.h:99
#define USB_GINTMSK_IEPINT
Definition: usb_common.h:211
#define USB_GRSTCTL_CSRST
Definition: usb_common.h:162
#define USB_GINTMSK_RXFLVLM
Definition: usb_common.h:200
#define USB_DCTL_SDIS
Definition: usb_common.h:262
#define USB_DOEP0CTL_SD0PID
Definition: usb_common.h:322
#define USB_GRXSTSP
Definition: usb_common.h:55
#define USB_ROUTE_DMPUPEN
Definition: usb_common.h:41
#define USB_DCFG_DSPD
Definition: usb_common.h:266
#define USB_GRXSTSP_PKTSTS_MASK
Definition: usb_common.h:227
#define USB_DIEP0CTL_SD0PID
Definition: usb_common.h:301
#define USB_PCGCCTL
Definition: usb_common.h:116
#define USB_DIEP0CTL_MPSIZ_8
Definition: usb_common.h:316
#define USB_GINTMSK
Definition: usb_common.h:53
#define USB_GUSBCFG_TRDT_16BIT
Definition: usb_common.h:145
#define USB_GINTSTS
Definition: usb_common.h:52
#define USB_DIEP0CTL_EPENA
Definition: usb_common.h:298
#define USB_GINTSTS_ENUMDNE
Definition: usb_common.h:182
#define USB_DIEP0CTL
Definition: usb_common.h:101
#define USB_DAINTMSK
Definition: usb_common.h:90
#define USB_GRXFSIZ
Definition: usb_common.h:56
#define USB_DOEP0CTL_STALL
Definition: usb_common.h:326
#define USB_DIEP0CTL_MPSIZ_32
Definition: usb_common.h:314
#define USB_GINTSTS_WKUPINT
Definition: usb_common.h:165
#define USB_DIEPx_CTL(x)
Definition: usb_common.h:95
#define USB_GINTMSK_USBSUSPM
Definition: usb_common.h:205
#define USB_GINTSTS_USBSUSP
Definition: usb_common.h:184
#define USB_GNPTXFSIZ
Definition: usb_common.h:57
#define USB_DIEP0TSIZ
Definition: usb_common.h:102
#define USB_GUSBCFG
Definition: usb_common.h:50
#define USB_GINTSTS_RXFLVL
Definition: usb_common.h:190
#define USB_GINTMSK_WUIM
Definition: usb_common.h:222
#define USB_DIEPMSK_XFRCM
Definition: usb_common.h:282
#define USB_DIEPx_INT(x)
Definition: usb_common.h:97
#define USB_CTRL
Definition: usb_common.h:29
#define USB_DIEP0CTL_STALL
Definition: usb_common.h:305
#define USB_ROUTE
Definition: usb_common.h:35
#define USB_DIEP0TSIZ_XFRSIZ_MASK
Definition: usb_common.h:369
#define USB_GRXSTSP_PKTSTS_SETUP
Definition: usb_common.h:232
#define USB_GUSBCFG_FDMOD
Definition: usb_common.h:149
#define USB_DOEPx_TSIZ(x)
Definition: usb_common.h:109
#define USB_DIEP0TSIZ_PKTCNT
Definition: usb_common.h:367
#define USB_DIEP0CTL_CNAK
Definition: usb_common.h:303
#define USB_GRXSTSP_BCNT_MASK
Definition: usb_common.h:238
#define USB_DOEP0CTL_USBAEP
Definition: usb_common.h:331
#define USB_GINTMSK_ENUMDNEM
Definition: usb_common.h:207
#define USB_DIEP0CTL_MPSIZ_64
Definition: usb_common.h:313
#define USB_DOEP0CTL_SNAK
Definition: usb_common.h:323
#define USB_DOEPx_CTL(x)
Definition: usb_common.h:105
#define USB_DOEP0CTL_CNAK
Definition: usb_common.h:324
#define USB_DCTL
Definition: usb_common.h:85
#define USB_DIEPMSK
Definition: usb_common.h:87
struct _usbd_device usbd_device
Definition: usbd.h:53
void _usbd_reset(usbd_device *usbd_dev)
Definition: usb.c:113
#define ENDPOINT_COUNT
Definition: usb_efm32.c:50
static void efm32lg_disconnect(usbd_device *usbd_dev, bool disconnected)
Definition: usb_efm32.c:408
static void efm32lg_endpoints_reset(usbd_device *usbd_dev)
Definition: usb_efm32.c:184
static struct _usbd_device _usbd_dev
Definition: usb_efm32.c:52
static void efm32lg_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak)
Definition: usb_efm32.c:235
#define RX_FIFO_SIZE
Definition: usb_efm32.c:38
static uint8_t efm32lg_ep_stall_get(usbd_device *usbd_dev, uint8_t addr)
Definition: usb_efm32.c:221
static void efm32lg_set_address(usbd_device *usbd_dev, uint8_t addr)
Definition: usb_efm32.c:100
static void efm32lg_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type, uint16_t max_size, void(*callback)(usbd_device *usbd_dev, uint8_t ep))
Definition: usb_efm32.c:107
static uint16_t efm32lg_ep_write_packet(usbd_device *usbd_dev, uint8_t addr, const void *buf, uint16_t len)
Definition: usb_efm32.c:251
static uint16_t efm32lg_ep_read_packet(usbd_device *usbd_dev, uint8_t addr, void *buf, uint16_t len)
Definition: usb_efm32.c:279
const struct _usbd_driver efm32lg_usb_driver
Definition: usb_efm32.c:419
static void efm32lg_poll(usbd_device *usbd_dev)
Definition: usb_efm32.c:307
static usbd_device * efm32lg_usbd_init(void)
Initialize the USB_FS device controller hardware of the STM32.
Definition: usb_efm32.c:55
static void efm32lg_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, uint8_t stall)
Definition: usb_efm32.c:190