1 /*******************************************************************************
2 * Copyright (C) 2015 Maxim Integrated Products, Inc., All Rights Reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
22 * Except as contained in this notice, the name of Maxim Integrated
23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
24 * Products, Inc. Branding Policy.
26 * The mere transfer of this software does not imply any licenses
27 * of trade secrets, proprietary technology, copyrights, patents,
28 * trademarks, maskwork rights, or any other form of intellectual
29 * property whatsoever. Maxim Integrated Products, Inc. retains all
31 *******************************************************************************
34 #if defined(TARGET_Maxim)
38 #include "clkman_regs.h"
40 #define CONNECT_INTS (MXC_F_USB_DEV_INTEN_BRST | MXC_F_USB_DEV_INTEN_SETUP | MXC_F_USB_DEV_INTEN_EP_IN | MXC_F_USB_DEV_INTEN_EP_OUT | MXC_F_USB_DEV_INTEN_DMA_ERR)
42 USBHAL
*USBHAL::instance
;
45 volatile uint32_t buf0_desc
;
46 volatile uint32_t buf0_address
;
47 volatile uint32_t buf1_desc
;
48 volatile uint32_t buf1_address
;
52 ep_buffer_t out_buffer
;
53 ep_buffer_t in_buffer
;
58 ep_buffer_t ep
[MXC_USB_NUM_EP
- 1];
59 } ep_buffer_descriptor_t
;
61 // Static storage for endpoint buffer descriptor table. Must be 512 byte alligned for DMA.
62 #ifdef __IAR_SYSTEMS_ICC__
63 #pragma data_alignment = 512
65 __attribute__ ((aligned (512)))
67 ep_buffer_descriptor_t ep_buffer_descriptor
;
69 // static storage for temporary data buffers. Must be 32 byte alligned.
70 #ifdef __IAR_SYSTEMS_ICC__
71 #pragma data_alignment = 4
73 __attribute__ ((aligned (4)))
75 static uint8_t aligned_buffer
[NUMBER_OF_LOGICAL_ENDPOINTS
][MXC_USB_MAX_PACKET
];
77 // contorl packet state
87 NVIC_DisableIRQ(USB_IRQn
);
89 // The PLL must be enabled for USB
90 MBED_ASSERT(MXC_CLKMAN
->clk_config
& MXC_F_CLKMAN_CLK_CONFIG_PLL_ENABLE
);
92 // Enable the USB clock
93 MXC_CLKMAN
->clk_ctrl
|= MXC_F_CLKMAN_CLK_CTRL_USB_GATE_N
;
98 MXC_USB
->dev_inten
= 0;
100 MXC_USB
->dev_cn
= MXC_F_USB_DEV_CN_URST
;
103 // fill in callback arrays
104 epCallback
[EP0OUT
] = NULL
;
105 epCallback
[EP0IN
] = NULL
;
106 epCallback
[EP1OUT
] = &USBHAL::EP1_OUT_callback
;
107 epCallback
[EP1IN
] = &USBHAL::EP1_IN_callback
;
108 epCallback
[EP2OUT
] = &USBHAL::EP2_OUT_callback
;
109 epCallback
[EP2IN
] = &USBHAL::EP2_IN_callback
;
110 epCallback
[EP3OUT
] = &USBHAL::EP3_OUT_callback
;
111 epCallback
[EP3IN
] = &USBHAL::EP3_IN_callback
;
112 epCallback
[EP4OUT
] = &USBHAL::EP4_OUT_callback
;
113 epCallback
[EP4IN
] = &USBHAL::EP4_IN_callback
;
114 epCallback
[EP5OUT
] = &USBHAL::EP5_OUT_callback
;
115 epCallback
[EP5IN
] = &USBHAL::EP5_IN_callback
;
116 epCallback
[EP6OUT
] = &USBHAL::EP6_OUT_callback
;
117 epCallback
[EP6IN
] = &USBHAL::EP6_IN_callback
;
118 epCallback
[EP7OUT
] = &USBHAL::EP7_OUT_callback
;
119 epCallback
[EP7IN
] = &USBHAL::EP7_IN_callback
;
121 // clear driver state
122 control_state
= CTRL_NONE
;
124 // set the descriptor location
125 MXC_USB
->ep_base
= (uint32_t)&ep_buffer_descriptor
;
127 // attach IRQ handler and enable interrupts
129 NVIC_SetVector(USB_IRQn
, (uint32_t)&_usbisr
);
130 NVIC_EnableIRQ(USB_IRQn
);
133 USBHAL::~USBHAL(void)
135 MXC_USB
->dev_cn
= MXC_F_USB_DEV_CN_URST
;
140 void USBHAL::connect(void)
143 MXC_USB
->dev_inten
|= CONNECT_INTS
;
145 // allow interrupts on ep0
146 MXC_USB
->ep
[0] |= MXC_F_USB_EP_INT_EN
;
149 MXC_USB
->dev_cn
|= (MXC_F_USB_DEV_CN_CONNECT
| MXC_F_USB_DEV_CN_FIFO_MODE
);
152 void USBHAL::disconnect(void)
154 // disable interrupts
155 MXC_USB
->dev_inten
&= ~CONNECT_INTS
;
158 MXC_USB
->dev_cn
&= ~MXC_F_USB_DEV_CN_CONNECT
;
161 void USBHAL::configureDevice(void)
166 void USBHAL::unconfigureDevice(void)
169 for (int i
= 0; i
< MXC_USB_NUM_EP
; i
++) {
170 // Disable endpoint and clear the data toggle
171 MXC_USB
->ep
[i
] &= ~MXC_F_USB_EP_DIR
;
172 MXC_USB
->ep
[i
] |= MXC_F_USB_EP_DT
;
176 void USBHAL::setAddress(uint8_t address
)
181 void USBHAL::remoteWakeup(void)
186 static ep_buffer_t
*get_desc(uint8_t endpoint
)
188 uint8_t epnum
= EP_NUM(endpoint
);
192 if (IN_EP(endpoint
)) {
193 desc
= &ep_buffer_descriptor
.ep0
.in_buffer
;
195 desc
= &ep_buffer_descriptor
.ep0
.out_buffer
;
198 desc
= &ep_buffer_descriptor
.ep
[epnum
- 1];
204 void USBHAL::EP0setup(uint8_t *buffer
)
206 memcpy(buffer
, (void*)&MXC_USB
->setup0
, 8); // setup packet is fixed at 8 bytes
209 void USBHAL::EP0read(void)
211 if (control_state
== CTRL_IN
) {
212 // This is the status stage. ACK.
213 MXC_USB
->ep
[0] |= MXC_F_USB_EP_ST_ACK
;
214 control_state
= CTRL_NONE
;
218 control_state
= CTRL_OUT
;
220 endpointRead(EP0OUT
, MAX_PACKET_SIZE_EP0
);
223 void USBHAL::EP0readStage(void)
228 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer
)
232 if (MXC_USB
->out_owner
& 1) {
236 // get the packet length and contents
237 ep_buffer_t
*desc
= get_desc(EP0OUT
);
238 size
= desc
->buf0_desc
;
239 memcpy(buffer
, aligned_buffer
[0], size
);
244 void USBHAL::EP0write(uint8_t *buffer
, uint32_t size
)
246 if ((size
== 0) && (control_state
!= CTRL_IN
)) {
247 // This is a status stage ACK. Handle in hardware.
248 MXC_USB
->ep
[0] |= MXC_F_USB_EP_ST_ACK
;
249 control_state
= CTRL_NONE
;
253 control_state
= CTRL_IN
;
255 endpointWrite(EP0IN
, buffer
, size
);
258 void USBHAL::EP0stall(void)
263 EP_STATUS
USBHAL::endpointRead(uint8_t endpoint
, uint32_t maximumSize
)
265 uint8_t epnum
= EP_NUM(endpoint
);
267 if ((endpoint
>= NUMBER_OF_PHYSICAL_ENDPOINTS
) || IN_EP(endpoint
)) {
271 if (maximumSize
> MXC_USB_MAX_PACKET
) {
275 uint32_t mask
= (1 << epnum
);
276 if (MXC_USB
->out_owner
& mask
) {
280 ep_buffer_t
*desc
= get_desc(endpoint
);
281 desc
->buf0_desc
= maximumSize
;
282 desc
->buf0_address
= (uint32_t)aligned_buffer
[epnum
];
284 MXC_USB
->out_owner
= mask
;
289 EP_STATUS
USBHAL::endpointReadResult(uint8_t endpoint
, uint8_t *data
, uint32_t *bytesRead
)
291 if ((endpoint
>= NUMBER_OF_PHYSICAL_ENDPOINTS
) || IN_EP(endpoint
)) {
295 uint32_t mask
= (1 << EP_NUM(endpoint
));
296 if (MXC_USB
->out_owner
& mask
) {
300 // get the packet length and contents
301 ep_buffer_t
*desc
= get_desc(endpoint
);
302 *bytesRead
= desc
->buf0_desc
;
303 memcpy(data
, aligned_buffer
[EP_NUM(endpoint
)], *bytesRead
);
308 EP_STATUS
USBHAL::endpointWrite(uint8_t endpoint
, uint8_t *data
, uint32_t size
)
310 uint8_t epnum
= EP_NUM(endpoint
);
312 if ((endpoint
>= NUMBER_OF_PHYSICAL_ENDPOINTS
) || OUT_EP(endpoint
)) {
316 if (size
> MXC_USB_MAX_PACKET
) {
320 uint32_t mask
= (1 << epnum
);
321 if (MXC_USB
->in_owner
& mask
) {
325 memcpy(aligned_buffer
[epnum
], data
, size
);
327 ep_buffer_t
*desc
= get_desc(endpoint
);
328 desc
->buf0_desc
= size
;
329 desc
->buf0_address
= (uint32_t)aligned_buffer
[epnum
];
332 MXC_USB
->in_owner
= mask
;
337 EP_STATUS
USBHAL::endpointWriteResult(uint8_t endpoint
)
339 uint32_t mask
= (1 << EP_NUM(endpoint
));
340 if (MXC_USB
->in_owner
& mask
) {
347 void USBHAL::stallEndpoint(uint8_t endpoint
)
349 uint8_t epnum
= EP_NUM(endpoint
);
352 MXC_USB
->ep
[epnum
] |= MXC_F_USB_EP_ST_STALL
;
355 MXC_USB
->ep
[epnum
] |= MXC_F_USB_EP_STALL
;
358 void USBHAL::unstallEndpoint(uint8_t endpoint
)
360 MXC_USB
->ep
[EP_NUM(endpoint
)] &= ~MXC_F_USB_EP_STALL
;
363 bool USBHAL::realiseEndpoint(uint8_t endpoint
, uint32_t maxPacket
, uint32_t options
)
365 uint8_t epnum
= EP_NUM(endpoint
);
368 if (epnum
>= NUMBER_OF_PHYSICAL_ENDPOINTS
) {
372 if (IN_EP(endpoint
)) {
373 ep_ctrl
= (MXC_V_USB_EP_DIR_IN
<< MXC_F_USB_EP_DIR_POS
);
375 ep_ctrl
= (MXC_S_USB_EP_DIR_OUT
<< MXC_F_USB_EP_DIR_POS
);
378 ep_ctrl
|= (MXC_F_USB_EP_DT
| MXC_F_USB_EP_INT_EN
);
380 MXC_USB
->ep
[epnum
] = ep_ctrl
;
385 bool USBHAL::getEndpointStallState(unsigned char endpoint
)
387 return !!(MXC_USB
->ep
[endpoint
] & MXC_F_USB_EP_STALL
);
390 void USBHAL::_usbisr(void)
395 void USBHAL::usbisr(void)
397 // get and clear irqs
398 uint32_t irq_flags
= MXC_USB
->dev_intfl
;
399 MXC_USB
->dev_intfl
= irq_flags
;
401 // process only enabled interrupts
402 irq_flags
&= MXC_USB
->dev_inten
;
405 if (irq_flags
& MXC_F_USB_DEV_INTFL_SUSP
) {
406 suspendStateChanged(1);
410 if (irq_flags
& MXC_F_USB_DEV_INTFL_BRST
) {
413 for (int i
= 0; i
< MXC_USB_NUM_EP
; i
++) {
414 // Disable endpoint and clear the data toggle
415 MXC_USB
->ep
[i
] &= ~MXC_F_USB_EP_DIR
;
416 MXC_USB
->ep
[i
] |= MXC_F_USB_EP_DT
;
419 // clear driver state
420 control_state
= CTRL_NONE
;
424 // no need to process events after reset
429 if (irq_flags
& MXC_F_USB_DEV_INTFL_SETUP
) {
430 control_state
= CTRL_SETUP
;
435 if (irq_flags
& MXC_F_USB_DEV_INTFL_EP_IN
) {
436 // get and clear IN irqs
437 uint32_t in_irqs
= MXC_USB
->in_int
;
438 MXC_USB
->in_int
= in_irqs
;
444 for (uint8_t epnum
= 1; epnum
< NUMBER_OF_LOGICAL_ENDPOINTS
; epnum
++) {
445 uint32_t irq_mask
= (1 << epnum
);
446 if (in_irqs
& irq_mask
) {
447 uint8_t endpoint
= (epnum
<< 1) | DIR_IN
;
448 (instance
->*(epCallback
[endpoint
]))();
454 if (irq_flags
& MXC_F_USB_DEV_INTFL_EP_OUT
) {
455 // get and clear OUT irqs
456 uint32_t out_irqs
= MXC_USB
->out_int
;
457 MXC_USB
->out_int
= out_irqs
;
463 for (uint8_t epnum
= 1; epnum
< NUMBER_OF_LOGICAL_ENDPOINTS
; epnum
++) {
464 uint32_t irq_mask
= (1 << epnum
);
465 if (out_irqs
& irq_mask
) {
466 uint8_t endpoint
= (epnum
<< 1) | DIR_OUT
;
467 (instance
->*(epCallback
[endpoint
]))();