Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-os by
USBHAL_Maxim.cpp
00001 /******************************************************************************* 00002 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved. 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00020 * OTHER DEALINGS IN THE SOFTWARE. 00021 * 00022 * Except as contained in this notice, the name of Maxim Integrated 00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated 00024 * Products, Inc. Branding Policy. 00025 * 00026 * The mere transfer of this software does not imply any licenses 00027 * of trade secrets, proprietary technology, copyrights, patents, 00028 * trademarks, maskwork rights, or any other form of intellectual 00029 * property whatsoever. Maxim Integrated Products, Inc. retains all 00030 * ownership rights. 00031 ******************************************************************************* 00032 */ 00033 00034 #if defined(TARGET_Maxim) 00035 00036 #include "USBHAL.h" 00037 #include "usb_regs.h" 00038 #include "clkman_regs.h" 00039 00040 #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) 00041 00042 USBHAL *USBHAL::instance; 00043 00044 typedef struct { 00045 volatile uint32_t buf0_desc; 00046 volatile uint32_t buf0_address; 00047 volatile uint32_t buf1_desc; 00048 volatile uint32_t buf1_address; 00049 } ep_buffer_t; 00050 00051 typedef struct { 00052 ep_buffer_t out_buffer; 00053 ep_buffer_t in_buffer; 00054 } ep0_buffer_t; 00055 00056 typedef struct { 00057 ep0_buffer_t ep0; 00058 ep_buffer_t ep[MXC_USB_NUM_EP - 1]; 00059 } ep_buffer_descriptor_t; 00060 00061 // Static storage for endpoint buffer descriptor table. Must be 512 byte aligned for DMA. 00062 #ifdef __IAR_SYSTEMS_ICC__ 00063 #pragma data_alignment = 512 00064 #else 00065 __attribute__ ((aligned (512))) 00066 #endif 00067 ep_buffer_descriptor_t ep_buffer_descriptor; 00068 00069 // static storage for temporary data buffers. Must be 32 byte aligned. 00070 #ifdef __IAR_SYSTEMS_ICC__ 00071 #pragma data_alignment = 4 00072 #else 00073 __attribute__ ((aligned (4))) 00074 #endif 00075 static uint8_t aligned_buffer[NUMBER_OF_LOGICAL_ENDPOINTS][MXC_USB_MAX_PACKET]; 00076 00077 // control packet state 00078 static enum { 00079 CTRL_NONE = 0, 00080 CTRL_SETUP, 00081 CTRL_OUT, 00082 CTRL_IN, 00083 } control_state; 00084 00085 USBHAL::USBHAL(void) 00086 { 00087 NVIC_DisableIRQ(USB_IRQn); 00088 00089 #if defined(TARGET_MAX32600) 00090 // The PLL must be enabled for USB 00091 MBED_ASSERT(MXC_CLKMAN->clk_config & MXC_F_CLKMAN_CLK_CONFIG_PLL_ENABLE); 00092 00093 // Enable the USB clock 00094 MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_GATE_N; 00095 #elif defined(TARGET_MAX32620) 00096 // Enable the USB clock 00097 MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_CLOCK_ENABLE; 00098 #endif 00099 00100 // reset the device 00101 MXC_USB->cn = 0; 00102 MXC_USB->cn = MXC_F_USB_CN_USB_EN; 00103 MXC_USB->dev_inten = 0; 00104 MXC_USB->dev_cn = 0; 00105 MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST; 00106 MXC_USB->dev_cn = 0; 00107 00108 // fill in callback arrays 00109 epCallback[EP0OUT] = NULL; 00110 epCallback[EP0IN] = NULL; 00111 epCallback[EP1OUT] = &USBHAL::EP1_OUT_callback; 00112 epCallback[EP1IN ] = &USBHAL::EP1_IN_callback; 00113 epCallback[EP2OUT] = &USBHAL::EP2_OUT_callback; 00114 epCallback[EP2IN ] = &USBHAL::EP2_IN_callback; 00115 epCallback[EP3OUT] = &USBHAL::EP3_OUT_callback; 00116 epCallback[EP3IN ] = &USBHAL::EP3_IN_callback; 00117 epCallback[EP4OUT] = &USBHAL::EP4_OUT_callback; 00118 epCallback[EP4IN ] = &USBHAL::EP4_IN_callback; 00119 epCallback[EP5OUT] = &USBHAL::EP5_OUT_callback; 00120 epCallback[EP5IN ] = &USBHAL::EP5_IN_callback; 00121 epCallback[EP6OUT] = &USBHAL::EP6_OUT_callback; 00122 epCallback[EP6IN ] = &USBHAL::EP6_IN_callback; 00123 epCallback[EP7OUT] = &USBHAL::EP7_OUT_callback; 00124 epCallback[EP7IN ] = &USBHAL::EP7_IN_callback; 00125 00126 // clear driver state 00127 control_state = CTRL_NONE; 00128 00129 // set the descriptor location 00130 MXC_USB->ep_base = (uint32_t)&ep_buffer_descriptor; 00131 00132 // enable VBUS interrupts 00133 MXC_USB->dev_inten = MXC_F_USB_DEV_INTEN_NO_VBUS | MXC_F_USB_DEV_INTEN_VBUS; 00134 00135 // attach IRQ handler and enable interrupts 00136 instance = this; 00137 NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr); 00138 NVIC_EnableIRQ(USB_IRQn); 00139 } 00140 00141 USBHAL::~USBHAL(void) 00142 { 00143 MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST; 00144 MXC_USB->dev_cn = 0; 00145 MXC_USB->cn = 0; 00146 } 00147 00148 void USBHAL::connect(void) 00149 { 00150 // enable interrupts 00151 MXC_USB->dev_inten |= CONNECT_INTS; 00152 00153 // allow interrupts on ep0 00154 MXC_USB->ep[0] |= MXC_F_USB_EP_INT_EN; 00155 00156 // pullup enable 00157 MXC_USB->dev_cn |= (MXC_F_USB_DEV_CN_CONNECT | MXC_F_USB_DEV_CN_FIFO_MODE); 00158 } 00159 00160 void USBHAL::disconnect(void) 00161 { 00162 // disable interrupts 00163 MXC_USB->dev_inten &= ~CONNECT_INTS; 00164 00165 // disable pullup 00166 MXC_USB->dev_cn &= ~MXC_F_USB_DEV_CN_CONNECT; 00167 } 00168 00169 void USBHAL::configureDevice(void) 00170 { 00171 // do nothing 00172 } 00173 00174 void USBHAL::unconfigureDevice(void) 00175 { 00176 // reset endpoints 00177 for (int i = 0; i < MXC_USB_NUM_EP; i++) { 00178 // Disable endpoint and clear the data toggle 00179 MXC_USB->ep[i] &= ~MXC_F_USB_EP_DIR; 00180 MXC_USB->ep[i] |= MXC_F_USB_EP_DT; 00181 } 00182 } 00183 00184 void USBHAL::setAddress(uint8_t address) 00185 { 00186 // do nothing 00187 } 00188 00189 void USBHAL::remoteWakeup(void) 00190 { 00191 // do nothing 00192 } 00193 00194 static ep_buffer_t *get_desc(uint8_t endpoint) 00195 { 00196 uint8_t epnum = EP_NUM(endpoint); 00197 ep_buffer_t *desc; 00198 00199 if (epnum == 0) { 00200 if (IN_EP(endpoint)) { 00201 desc = &ep_buffer_descriptor.ep0.in_buffer; 00202 } else { 00203 desc = &ep_buffer_descriptor.ep0.out_buffer; 00204 } 00205 } else { 00206 desc = &ep_buffer_descriptor.ep[epnum - 1]; 00207 } 00208 00209 return desc; 00210 } 00211 00212 void USBHAL::EP0setup(uint8_t *buffer) 00213 { 00214 // Setup packet is fixed at 8 bytes 00215 // Setup registers cannot be read in byte mode 00216 uint32_t *ptr32 = (uint32_t*)buffer; 00217 ptr32[0] = (uint32_t)MXC_USB->setup0; 00218 ptr32[1] = (uint32_t)MXC_USB->setup1; 00219 } 00220 00221 void USBHAL::EP0read(void) 00222 { 00223 if (control_state == CTRL_IN) { 00224 // This is the status stage. ACK. 00225 MXC_USB->ep[0] |= MXC_F_USB_EP_ST_ACK; 00226 control_state = CTRL_NONE; 00227 return; 00228 } 00229 00230 control_state = CTRL_OUT; 00231 00232 endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0); 00233 } 00234 00235 void USBHAL::EP0readStage(void) 00236 { 00237 // do nothing 00238 } 00239 00240 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) 00241 { 00242 uint32_t size; 00243 00244 if (MXC_USB->out_owner & 1) { 00245 return 0; 00246 } 00247 00248 // get the packet length and contents 00249 ep_buffer_t *desc = get_desc(EP0OUT); 00250 size = desc->buf0_desc; 00251 memcpy(buffer, aligned_buffer[0], size); 00252 00253 return size; 00254 } 00255 00256 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) 00257 { 00258 if ((size == 0) && (control_state != CTRL_IN)) { 00259 // This is a status stage ACK. Handle in hardware. 00260 MXC_USB->ep[0] |= MXC_F_USB_EP_ST_ACK; 00261 control_state = CTRL_NONE; 00262 return; 00263 } 00264 00265 control_state = CTRL_IN; 00266 00267 endpointWrite(EP0IN, buffer, size); 00268 } 00269 00270 void USBHAL::EP0stall(void) 00271 { 00272 stallEndpoint(0); 00273 } 00274 00275 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) 00276 { 00277 uint8_t epnum = EP_NUM(endpoint); 00278 00279 if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || IN_EP(endpoint)) { 00280 return EP_INVALID; 00281 } 00282 00283 if (maximumSize > MXC_USB_MAX_PACKET) { 00284 return EP_INVALID; 00285 } 00286 00287 uint32_t mask = (1 << epnum); 00288 if (MXC_USB->out_owner & mask) { 00289 return EP_INVALID; 00290 } 00291 00292 ep_buffer_t *desc = get_desc(endpoint); 00293 desc->buf0_desc = maximumSize; 00294 desc->buf0_address = (uint32_t)aligned_buffer[epnum]; 00295 00296 MXC_USB->out_owner = mask; 00297 00298 return EP_PENDING; 00299 } 00300 00301 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead) 00302 { 00303 if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || IN_EP(endpoint)) { 00304 return EP_INVALID; 00305 } 00306 00307 uint32_t mask = (1 << EP_NUM(endpoint)); 00308 if (MXC_USB->out_owner & mask) { 00309 return EP_PENDING; 00310 } 00311 00312 // get the packet length and contents 00313 ep_buffer_t *desc = get_desc(endpoint); 00314 *bytesRead = desc->buf0_desc; 00315 memcpy(data, aligned_buffer[EP_NUM(endpoint)], *bytesRead); 00316 00317 return EP_COMPLETED; 00318 } 00319 00320 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) 00321 { 00322 uint8_t epnum = EP_NUM(endpoint); 00323 00324 if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || OUT_EP(endpoint)) { 00325 return EP_INVALID; 00326 } 00327 00328 if (size > MXC_USB_MAX_PACKET) { 00329 return EP_INVALID; 00330 } 00331 00332 uint32_t mask = (1 << epnum); 00333 if (MXC_USB->in_owner & mask) { 00334 return EP_INVALID; 00335 } 00336 00337 memcpy(aligned_buffer[epnum], data, size); 00338 00339 ep_buffer_t *desc = get_desc(endpoint); 00340 desc->buf0_desc = size; 00341 desc->buf0_address = (uint32_t)aligned_buffer[epnum]; 00342 00343 // start the DMA 00344 MXC_USB->in_owner = mask; 00345 00346 return EP_PENDING; 00347 } 00348 00349 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) 00350 { 00351 uint32_t mask = (1 << EP_NUM(endpoint)); 00352 if (MXC_USB->in_owner & mask) { 00353 return EP_PENDING; 00354 } 00355 00356 return EP_COMPLETED; 00357 } 00358 00359 void USBHAL::stallEndpoint(uint8_t endpoint) 00360 { 00361 uint8_t epnum = EP_NUM(endpoint); 00362 00363 if (epnum == 0) { 00364 MXC_USB->ep[epnum] |= MXC_F_USB_EP_ST_STALL; 00365 } 00366 00367 MXC_USB->ep[epnum] |= MXC_F_USB_EP_STALL; 00368 } 00369 00370 void USBHAL::unstallEndpoint(uint8_t endpoint) 00371 { 00372 MXC_USB->ep[EP_NUM(endpoint)] &= ~MXC_F_USB_EP_STALL; 00373 } 00374 00375 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options) 00376 { 00377 uint8_t epnum = EP_NUM(endpoint); 00378 uint32_t ep_ctrl; 00379 00380 if (epnum >= NUMBER_OF_PHYSICAL_ENDPOINTS) { 00381 return false; 00382 } 00383 00384 if (IN_EP(endpoint)) { 00385 ep_ctrl = (MXC_V_USB_EP_DIR_IN << MXC_F_USB_EP_DIR_POS); 00386 } else { 00387 ep_ctrl = (MXC_S_USB_EP_DIR_OUT << MXC_F_USB_EP_DIR_POS); 00388 } 00389 00390 ep_ctrl |= (MXC_F_USB_EP_DT | MXC_F_USB_EP_INT_EN); 00391 00392 MXC_USB->ep[epnum] = ep_ctrl; 00393 00394 return true; 00395 } 00396 00397 bool USBHAL::getEndpointStallState(unsigned char endpoint) 00398 { 00399 return !!(MXC_USB->ep[endpoint] & MXC_F_USB_EP_STALL); 00400 } 00401 00402 void USBHAL::_usbisr(void) 00403 { 00404 instance->usbisr(); 00405 } 00406 00407 void USBHAL::usbisr(void) 00408 { 00409 // get and clear irqs 00410 uint32_t irq_flags = MXC_USB->dev_intfl; 00411 MXC_USB->dev_intfl = irq_flags; 00412 00413 // process only enabled interrupts 00414 irq_flags &= MXC_USB->dev_inten; 00415 00416 // suspend 00417 if (irq_flags & MXC_F_USB_DEV_INTFL_SUSP) { 00418 suspendStateChanged(1); 00419 } 00420 00421 // bus reset 00422 if (irq_flags & MXC_F_USB_DEV_INTFL_BRST) { 00423 00424 // reset endpoints 00425 for (int i = 0; i < MXC_USB_NUM_EP; i++) { 00426 // Disable endpoint and clear the data toggle 00427 MXC_USB->ep[i] &= ~MXC_F_USB_EP_DIR; 00428 MXC_USB->ep[i] |= MXC_F_USB_EP_DT; 00429 } 00430 00431 // clear driver state 00432 control_state = CTRL_NONE; 00433 00434 busReset(); 00435 00436 // no need to process events after reset 00437 return; 00438 } 00439 00440 // Setup packet 00441 if (irq_flags & MXC_F_USB_DEV_INTFL_SETUP) { 00442 control_state = CTRL_SETUP; 00443 EP0setupCallback(); 00444 } 00445 00446 // IN packets 00447 if (irq_flags & MXC_F_USB_DEV_INTFL_EP_IN) { 00448 // get and clear IN irqs 00449 uint32_t in_irqs = MXC_USB->in_int; 00450 MXC_USB->in_int = in_irqs; 00451 00452 if (in_irqs & 1) { 00453 EP0in(); 00454 } 00455 00456 for (uint8_t epnum = 1; epnum < NUMBER_OF_LOGICAL_ENDPOINTS; epnum++) { 00457 uint32_t irq_mask = (1 << epnum); 00458 if (in_irqs & irq_mask) { 00459 uint8_t endpoint = (epnum << 1) | DIR_IN; 00460 (instance->*(epCallback[endpoint]))(); 00461 } 00462 } 00463 } 00464 00465 // OUT packets 00466 if (irq_flags & MXC_F_USB_DEV_INTFL_EP_OUT) { 00467 // get and clear OUT irqs 00468 uint32_t out_irqs = MXC_USB->out_int; 00469 MXC_USB->out_int = out_irqs; 00470 00471 if (out_irqs & 1) { 00472 EP0out(); 00473 } 00474 00475 for (uint8_t epnum = 1; epnum < NUMBER_OF_LOGICAL_ENDPOINTS; epnum++) { 00476 uint32_t irq_mask = (1 << epnum); 00477 if (out_irqs & irq_mask) { 00478 uint8_t endpoint = (epnum << 1) | DIR_OUT; 00479 (instance->*(epCallback[endpoint]))(); 00480 } 00481 } 00482 } 00483 } 00484 00485 #endif
Generated on Tue Jul 12 2022 13:16:18 by
