Update USB_FLASH_DRIVE_SUPPORT (#15021)
This commit is contained in:
committed by
Scott Lahteine
parent
20fc66f875
commit
da601d5114
213
Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp
Normal file
213
Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
/****************
|
||||
* usb_host.cpp *
|
||||
****************/
|
||||
|
||||
/****************************************************************************
|
||||
* Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* To view a copy of the GNU General Public License, go to the following *
|
||||
* location: <http://www.gnu.org/licenses/>. *
|
||||
****************************************************************************/
|
||||
|
||||
/* What follows is a modified version of the MAX3421e originally defined in
|
||||
* lib/usbhost.c". This has been rewritten to use SPI routines from the
|
||||
* Marlin HAL */
|
||||
|
||||
#include "../../../inc/MarlinConfigPre.h"
|
||||
|
||||
#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB)
|
||||
|
||||
#include "Usb.h"
|
||||
#include "usbhost.h"
|
||||
|
||||
uint8_t MAX3421e::vbusState = 0;
|
||||
|
||||
// constructor
|
||||
void MAX3421e::cs() {
|
||||
WRITE(USB_CS_PIN,0);
|
||||
}
|
||||
|
||||
void MAX3421e::ncs() {
|
||||
WRITE(USB_CS_PIN,1);
|
||||
}
|
||||
|
||||
// write single byte into MAX3421 register
|
||||
void MAX3421e::regWr(uint8_t reg, uint8_t data) {
|
||||
cs();
|
||||
spiSend(reg | 0x02);
|
||||
spiSend(data);
|
||||
ncs();
|
||||
};
|
||||
|
||||
// multiple-byte write
|
||||
// return a pointer to memory position after last written
|
||||
uint8_t* MAX3421e::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
|
||||
cs();
|
||||
spiSend(reg | 0x02);
|
||||
while (nbytes--) spiSend(*data_p++);
|
||||
ncs();
|
||||
return data_p;
|
||||
}
|
||||
|
||||
// GPIO write
|
||||
// GPIO byte is split between 2 registers, so two writes are needed to write one byte
|
||||
|
||||
// GPOUT bits are in the low nybble. 0-3 in IOPINS1, 4-7 in IOPINS2
|
||||
void MAX3421e::gpioWr(uint8_t data) {
|
||||
regWr(rIOPINS1, data);
|
||||
regWr(rIOPINS2, data >> 4);
|
||||
}
|
||||
|
||||
// single host register read
|
||||
uint8_t MAX3421e::regRd(uint8_t reg) {
|
||||
cs();
|
||||
spiSend(reg);
|
||||
uint8_t rv = spiRec();
|
||||
ncs();
|
||||
return rv;
|
||||
}
|
||||
// multiple-byte register read
|
||||
|
||||
// return a pointer to a memory position after last read
|
||||
uint8_t* MAX3421e::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
|
||||
cs();
|
||||
spiSend(reg);
|
||||
while (nbytes--) *data_p++ = spiRec();
|
||||
ncs();
|
||||
return data_p;
|
||||
}
|
||||
// GPIO read. See gpioWr for explanation
|
||||
|
||||
// GPIN pins are in high nybbles of IOPINS1, IOPINS2
|
||||
uint8_t MAX3421e::gpioRd() {
|
||||
return (regRd(rIOPINS2) & 0xf0) | // pins 4-7, clean lower nybble
|
||||
(regRd(rIOPINS1) >> 4); // shift low bits and OR with upper from previous operation.
|
||||
}
|
||||
|
||||
// reset MAX3421e. Returns false if PLL failed to stabilize 1 second after reset
|
||||
bool MAX3421e::reset() {
|
||||
regWr(rUSBCTL, bmCHIPRES);
|
||||
regWr(rUSBCTL, 0x00);
|
||||
for (uint8_t i = 100; i--;) {
|
||||
if (regRd(rUSBIRQ) & bmOSCOKIRQ) return true;
|
||||
delay(10);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// initialize MAX3421e. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not
|
||||
bool MAX3421e::start() {
|
||||
// Initialize pins and SPI bus
|
||||
|
||||
SET_OUTPUT(USB_CS_PIN);
|
||||
SET_INPUT_PULLUP(USB_INTR_PIN);
|
||||
ncs();
|
||||
spiBegin();
|
||||
|
||||
spiInit(
|
||||
#ifdef SPI_SPEED
|
||||
SPI_SPEED
|
||||
#else
|
||||
SPI_FULL_SPEED
|
||||
#endif
|
||||
);
|
||||
|
||||
// MAX3421e - full-duplex, level interrupt, vbus off.
|
||||
regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET));
|
||||
|
||||
const uint8_t revision = regRd(rREVISION);
|
||||
if (revision == 0x00 || revision == 0xFF) {
|
||||
SERIAL_ECHOLNPAIR("Revision register appears incorrect on MAX3421e initialization. Got ", revision);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reset()) {
|
||||
SERIAL_ECHOLNPGM("OSCOKIRQ hasn't asserted in time");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delay a minimum of 1 second to ensure any capacitors are drained.
|
||||
// 1 second is required to make sure we do not smoke a Microdrive!
|
||||
|
||||
delay(1000);
|
||||
|
||||
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
|
||||
regWr(rHIEN, bmCONDETIE | bmFRAMEIE); // connection detection
|
||||
|
||||
// check if device is connected
|
||||
regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
|
||||
while (!(regRd(rHCTL) & bmSAMPLEBUS)) delay(10); // wait for sample operation to finish
|
||||
|
||||
busprobe(); // check if anything is connected
|
||||
|
||||
regWr(rHIRQ, bmCONDETIRQ); // clear connection detect interrupt
|
||||
regWr(rCPUCTL, 0x01); // enable interrupt pin
|
||||
|
||||
// GPX pin on. This is done here so that busprobe will fail if we have a switch connected.
|
||||
regWr(rPINCTL, bmFDUPSPI | bmINTLEVEL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Probe bus to determine device presence and speed. Switch host to this speed.
|
||||
void MAX3421e::busprobe() {
|
||||
// Switch on just the J & K bits
|
||||
switch (regRd(rHRSL) & (bmJSTATUS | bmKSTATUS)) {
|
||||
case bmJSTATUS:
|
||||
if ((regRd(rMODE) & bmLOWSPEED) == 0) {
|
||||
regWr(rMODE, MODE_FS_HOST); // start full-speed host
|
||||
vbusState = FSHOST;
|
||||
}
|
||||
else {
|
||||
regWr(rMODE, MODE_LS_HOST); // start low-speed host
|
||||
vbusState = LSHOST;
|
||||
}
|
||||
break;
|
||||
case bmKSTATUS:
|
||||
if ((regRd(rMODE) & bmLOWSPEED) == 0) {
|
||||
regWr(rMODE, MODE_LS_HOST); // start low-speed host
|
||||
vbusState = LSHOST;
|
||||
}
|
||||
else {
|
||||
regWr(rMODE, MODE_FS_HOST); // start full-speed host
|
||||
vbusState = FSHOST;
|
||||
}
|
||||
break;
|
||||
case bmSE1: // illegal state
|
||||
vbusState = SE1;
|
||||
break;
|
||||
case bmSE0: // disconnected state
|
||||
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ);
|
||||
vbusState = SE0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// MAX3421 state change task and interrupt handler
|
||||
uint8_t MAX3421e::Task(void) {
|
||||
return READ(USB_INTR_PIN) ? 0 : IntHandler();
|
||||
}
|
||||
|
||||
uint8_t MAX3421e::IntHandler() {
|
||||
uint8_t HIRQ = regRd(rHIRQ), // determine interrupt source
|
||||
HIRQ_sendback = 0x00;
|
||||
if (HIRQ & bmCONDETIRQ) {
|
||||
busprobe();
|
||||
HIRQ_sendback |= bmCONDETIRQ;
|
||||
}
|
||||
// End HIRQ interrupts handling, clear serviced IRQs
|
||||
regWr(rHIRQ, HIRQ_sendback);
|
||||
return HIRQ_sendback;
|
||||
}
|
||||
|
||||
#endif // USB_FLASH_DRIVE_SUPPORT
|
Reference in New Issue
Block a user